batch journal entries
This commit is contained in:
+180
-54
@@ -70,8 +70,6 @@
|
|||||||
<?php require '../include_ending.php'; ?>
|
<?php require '../include_ending.php'; ?>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// (batch_process lives in custom.js)
|
|
||||||
|
|
||||||
var TAB_MAP = {
|
var TAB_MAP = {
|
||||||
'invoice': 'invoice',
|
'invoice': 'invoice',
|
||||||
'credit_note': 'credit_note',
|
'credit_note': 'credit_note',
|
||||||
@@ -81,19 +79,23 @@
|
|||||||
'payment': 'payment'
|
'payment': 'payment'
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stores the last loaded IDs per tab so Run doesn't need to re-fetch
|
var _gl_loaded = {}; // doc_type → [ids] (flat, used by single-formula run)
|
||||||
var _gl_loaded = {};
|
var _gl_rows = {}; // doc_type → [rows]
|
||||||
// Stores full row data per tab for client-side pagination
|
var _gl_failed = {}; // doc_type → failed items from last run
|
||||||
var _gl_rows = {};
|
var _gl_loaded_by_formula = {}; // doc_type → { formula_id: [ids] }
|
||||||
// Stores failed items from the last batch run per tab (for Retry Failed)
|
var _formula_run_queue = {}; // doc_type → [formula_ids] remaining in "all" run
|
||||||
var _gl_failed = {};
|
|
||||||
|
|
||||||
// ── init tab once ─────────────────────────────────────────────────────────
|
// ── init tab once ─────────────────────────────────────────────────────────
|
||||||
var _inited = {};
|
var _inited = {};
|
||||||
function init_gl_tab(doc_type) {
|
function init_gl_tab(doc_type) {
|
||||||
if (_inited[doc_type]) return;
|
if (_inited[doc_type]) return;
|
||||||
_inited[doc_type] = true;
|
_inited[doc_type] = true;
|
||||||
load_formula_options('gl-formula-' + doc_type, doc_type, null);
|
|
||||||
|
load_formula_options('gl-formula-' + doc_type, doc_type, null, function(formulas) {
|
||||||
|
var $sel = $('#gl-formula-' + doc_type);
|
||||||
|
$sel.prepend('<option value="all">— All Formulas (' + formulas.length + ') —</option>');
|
||||||
|
$sel.val('all');
|
||||||
|
});
|
||||||
|
|
||||||
var today = new Date();
|
var today = new Date();
|
||||||
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
var firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||||
@@ -113,15 +115,21 @@
|
|||||||
$('#gl-date-to-' + doc_type).val(fmt(today));
|
$('#gl-date-to-' + doc_type).val(fmt(today));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── load documents into table ─────────────────────────────────────────────
|
// ── load documents ────────────────────────────────────────────────────────
|
||||||
function load_gl_tab(doc_type) {
|
function load_gl_tab(doc_type) {
|
||||||
var formula_id = $('#gl-formula-' + doc_type).val();
|
var formula_id = $('#gl-formula-' + doc_type).val();
|
||||||
if (!formula_id) { alert('Please select a GL formula first.'); return; }
|
if (!formula_id) { bootbox.alert('Please select a GL formula first.'); return; }
|
||||||
|
|
||||||
|
if (formula_id === 'all') {
|
||||||
|
load_all_formulas(doc_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var $tbody = $('#gl-tbody-' + doc_type);
|
var $tbody = $('#gl-tbody-' + doc_type);
|
||||||
var $badge = $('#gl-badge-' + doc_type);
|
var $badge = $('#gl-badge-' + doc_type);
|
||||||
|
|
||||||
_gl_loaded[doc_type] = [];
|
_gl_loaded[doc_type] = [];
|
||||||
|
_gl_loaded_by_formula[doc_type] = {};
|
||||||
set_btn_state('#gl-btn-run-' + doc_type, false);
|
set_btn_state('#gl-btn-run-' + doc_type, false);
|
||||||
$badge.text('');
|
$badge.text('');
|
||||||
$tbody.html('<tr><td colspan="6" class="text-center text-muted py-4">'
|
$tbody.html('<tr><td colspan="6" class="text-center text-muted py-4">'
|
||||||
@@ -142,10 +150,74 @@
|
|||||||
date_to: $('#gl-date-to-' + doc_type).val(),
|
date_to: $('#gl-date-to-' + doc_type).val(),
|
||||||
formula_id: formula_id
|
formula_id: formula_id
|
||||||
},
|
},
|
||||||
|
onSuccess: function(res) {
|
||||||
|
_render_gl_tab(doc_type, formula_id, res.output || []);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_all_formulas(doc_type) {
|
||||||
|
var $tbody = $('#gl-tbody-' + doc_type);
|
||||||
|
var $badge = $('#gl-badge-' + doc_type);
|
||||||
|
|
||||||
|
// Collect all formula IDs from the dropdown (skip 'all' and empty)
|
||||||
|
var formula_ids = [];
|
||||||
|
$('#gl-formula-' + doc_type + ' option').each(function() {
|
||||||
|
var v = $(this).val();
|
||||||
|
if (v && v !== 'all') formula_ids.push(v);
|
||||||
|
});
|
||||||
|
if (!formula_ids.length) { bootbox.alert('No formulas available.'); return; }
|
||||||
|
|
||||||
|
_gl_loaded[doc_type] = [];
|
||||||
|
_gl_loaded_by_formula[doc_type] = {};
|
||||||
|
_gl_rows[doc_type] = [];
|
||||||
|
set_btn_state('#gl-btn-run-' + doc_type, false);
|
||||||
|
$badge.html('<i class="ti ti-loader ti-spin me-1"></i>Loading ' + formula_ids.length + ' formulas…');
|
||||||
|
$tbody.html('<tr><td colspan="6" class="text-center text-muted py-4">'
|
||||||
|
+ '<i class="ti ti-loader ti-spin me-1"></i>Loading…</td></tr>');
|
||||||
|
|
||||||
|
var pending = formula_ids.length;
|
||||||
|
var all_rows = [];
|
||||||
|
|
||||||
|
formula_ids.forEach(function(fid) {
|
||||||
|
var ctx = document.getElementById('session-context');
|
||||||
|
ajax_request({
|
||||||
|
url: '<?php echo $server_url?>accounting/api/engine/get_gl_documents.php',
|
||||||
|
action: 'get', queueLock: false, noLoading: true,
|
||||||
|
data: {
|
||||||
|
otp: ctx ? ctx.dataset.otp : '',
|
||||||
|
company_id: ctx ? ctx.dataset.companyId : '',
|
||||||
|
action: 'get',
|
||||||
|
doc_type: doc_type,
|
||||||
|
date_from: $('#gl-date-from-' + doc_type).val(),
|
||||||
|
date_to: $('#gl-date-to-' + doc_type).val(),
|
||||||
|
formula_id: fid
|
||||||
|
},
|
||||||
onSuccess: function(res) {
|
onSuccess: function(res) {
|
||||||
var rows = res.output || [];
|
var rows = res.output || [];
|
||||||
var table_id = 'gl-table-' + doc_type; // HTML element id (hyphens ok)
|
rows.forEach(function(r) { r._formula_id = fid; });
|
||||||
var ala_id = 'gl_table_' + doc_type; // alasql identifier (underscores only)
|
_gl_loaded_by_formula[doc_type][fid] = rows.map(function(r) { return r.id; });
|
||||||
|
all_rows = all_rows.concat(rows);
|
||||||
|
if (--pending === 0) _finish_all_formulas_load(doc_type, all_rows);
|
||||||
|
},
|
||||||
|
onError: function() {
|
||||||
|
if (--pending === 0) _finish_all_formulas_load(doc_type, all_rows);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _finish_all_formulas_load(doc_type, all_rows) {
|
||||||
|
_gl_rows[doc_type] = all_rows;
|
||||||
|
_gl_loaded[doc_type] = all_rows.map(function(r) { return r.id; });
|
||||||
|
_render_gl_tab(doc_type, 'all', all_rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _render_gl_tab(doc_type, formula_id, rows) {
|
||||||
|
var $tbody = $('#gl-tbody-' + doc_type);
|
||||||
|
var $badge = $('#gl-badge-' + doc_type);
|
||||||
|
var table_id = 'gl-table-' + doc_type;
|
||||||
|
var ala_id = 'gl_table_' + doc_type;
|
||||||
|
|
||||||
if (rows.length === 0) {
|
if (rows.length === 0) {
|
||||||
$tbody.html('<tr><td colspan="6" class="text-center text-muted py-4">No documents found.</td></tr>');
|
$tbody.html('<tr><td colspan="6" class="text-center text-muted py-4">No documents found.</td></tr>');
|
||||||
@@ -157,17 +229,17 @@
|
|||||||
_gl_loaded[doc_type] = rows.map(function(r) { return r.id; });
|
_gl_loaded[doc_type] = rows.map(function(r) { return r.id; });
|
||||||
_gl_rows[doc_type] = rows;
|
_gl_rows[doc_type] = rows;
|
||||||
|
|
||||||
// Register with alasql for client-side pagination
|
|
||||||
alasql('CREATE TABLE IF NOT EXISTS ' + ala_id);
|
alasql('CREATE TABLE IF NOT EXISTS ' + ala_id);
|
||||||
alasql.tables[ala_id].data = rows;
|
alasql.tables[ala_id].data = rows;
|
||||||
|
|
||||||
var unposted = rows.filter(function(r) { return r.gl_status == 0; }).length;
|
var unposted = rows.filter(function(r) { return r.gl_status == 0; }).length;
|
||||||
var posted = rows.length - unposted;
|
var posted = rows.length - unposted;
|
||||||
var missing_mapping = rows.filter(function(r) {
|
var missing_mapping = rows.filter(function(r) { return Number(r.product_mapping_missing || 0) > 0; }).length;
|
||||||
return Number(r.product_mapping_missing || 0) > 0;
|
|
||||||
}).length;
|
var formula_note = formula_id === 'all'
|
||||||
|
? ' · <span class="text-info">All Formulas</span>' : '';
|
||||||
$badge.html(
|
$badge.html(
|
||||||
rows.length + ' document(s) · '
|
rows.length + ' document(s)' + formula_note + ' · '
|
||||||
+ '<span class="text-danger">' + unposted + ' unposted</span>'
|
+ '<span class="text-danger">' + unposted + ' unposted</span>'
|
||||||
+ ' · '
|
+ ' · '
|
||||||
+ '<span class="text-success">' + posted + ' posted</span>'
|
+ '<span class="text-success">' + posted + ' posted</span>'
|
||||||
@@ -176,7 +248,6 @@
|
|||||||
: '')
|
: '')
|
||||||
);
|
);
|
||||||
|
|
||||||
// Wire up dynamic change_page function keyed by HTML table id
|
|
||||||
window['change_page_' + table_id] = function(page_num) {
|
window['change_page_' + table_id] = function(page_num) {
|
||||||
var offset = (page_num - 1) * prop_limit;
|
var offset = (page_num - 1) * prop_limit;
|
||||||
var page_rows = alasql('SELECT * FROM ' + ala_id + ' LIMIT ' + prop_limit + ' OFFSET ' + offset);
|
var page_rows = alasql('SELECT * FROM ' + ala_id + ' LIMIT ' + prop_limit + ' OFFSET ' + offset);
|
||||||
@@ -201,11 +272,8 @@
|
|||||||
|
|
||||||
$('#' + table_id + ' tfoot').html(generate_pagination(table_id, rows.length));
|
$('#' + table_id + ' tfoot').html(generate_pagination(table_id, rows.length));
|
||||||
window['change_page_' + table_id](1);
|
window['change_page_' + table_id](1);
|
||||||
|
|
||||||
set_btn_state('#gl-btn-run-' + doc_type, missing_mapping === 0);
|
set_btn_state('#gl-btn-run-' + doc_type, missing_mapping === 0);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function product_mapping_badge(row) {
|
function product_mapping_badge(row) {
|
||||||
if (String(row.product_mapping_checked || '0') !== '1') {
|
if (String(row.product_mapping_checked || '0') !== '1') {
|
||||||
@@ -218,8 +286,7 @@
|
|||||||
return '<span class="badge bg-success-subtle text-success">Mapped</span>';
|
return '<span class="badge bg-success-subtle text-success">Mapped</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── batch overlay helpers — delegated to shared BatchOverlay ─────────────
|
// ── batch overlay helpers ─────────────────────────────────────────────────
|
||||||
|
|
||||||
function show_batch_overlay(label, total) {
|
function show_batch_overlay(label, total) {
|
||||||
BatchOverlay.show('Batch GL Posting — ' + label, total, { unit: 'documents' });
|
BatchOverlay.show('Batch GL Posting — ' + label, total, { unit: 'documents' });
|
||||||
}
|
}
|
||||||
@@ -228,7 +295,7 @@
|
|||||||
BatchOverlay.update(done, total, 'document ' + done + ' of ' + total);
|
BatchOverlay.update(done, total, 'document ' + done + ' of ' + total);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── run batch over all loaded IDs ─────────────────────────────────────────
|
// ── run batch ─────────────────────────────────────────────────────────────
|
||||||
var DOC_LABELS = {
|
var DOC_LABELS = {
|
||||||
invoice: 'Invoice',
|
invoice: 'Invoice',
|
||||||
credit_note: 'Credit Note',
|
credit_note: 'Credit Note',
|
||||||
@@ -239,6 +306,13 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
function run_gl_batch(doc_type) {
|
function run_gl_batch(doc_type) {
|
||||||
|
var formula_id = $('#gl-formula-' + doc_type).val();
|
||||||
|
|
||||||
|
if (formula_id === 'all') {
|
||||||
|
run_all_formula_batches(doc_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var ids = _gl_loaded[doc_type] || [];
|
var ids = _gl_loaded[doc_type] || [];
|
||||||
if (!ids.length) return;
|
if (!ids.length) return;
|
||||||
|
|
||||||
@@ -246,18 +320,15 @@
|
|||||||
return Number(r.product_mapping_missing || 0) > 0;
|
return Number(r.product_mapping_missing || 0) > 0;
|
||||||
});
|
});
|
||||||
if (missing_mapping.length) {
|
if (missing_mapping.length) {
|
||||||
alert('Product Account Mapping is incomplete for ' + missing_mapping.length + ' loaded document(s). Fill Sales/Purchase accounts on Account Formulas > Product Accounts, then reload this batch.');
|
bootbox.alert('Product Account Mapping is incomplete for ' + missing_mapping.length + ' loaded document(s). Fill Sales/Purchase accounts on Account Formulas > Product Accounts, then reload this batch.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate TTL: ids × (throttle delay + avg PHP response) + 20% buffer, min 2 min
|
var per_item_ms = 200 + 150;
|
||||||
var per_item_ms = 200 + 150; // throttle + avg response
|
var ttl_minutes = Math.max(2, Math.ceil(ids.length * per_item_ms / 60000 * 1.2));
|
||||||
var estimated_ms = ids.length * per_item_ms;
|
|
||||||
var ttl_minutes = Math.max(2, Math.ceil(estimated_ms / 60000 * 1.2));
|
|
||||||
|
|
||||||
// Acquire DB lock before starting — blocks other tabs/users
|
|
||||||
acquire_op_lock('gl_post', function() {
|
acquire_op_lock('gl_post', function() {
|
||||||
_start_gl_batch(doc_type, ids);
|
_start_gl_batch(doc_type, ids, null);
|
||||||
}, function(msg, res) {
|
}, function(msg, res) {
|
||||||
var wait_msg = msg || 'A GL posting batch is already running.';
|
var wait_msg = msg || 'A GL posting batch is already running.';
|
||||||
if (res && res.expires_at) {
|
if (res && res.expires_at) {
|
||||||
@@ -265,19 +336,75 @@
|
|||||||
var remaining_m = Math.ceil(remaining_s / 60);
|
var remaining_m = Math.ceil(remaining_s / 60);
|
||||||
wait_msg += '\nEstimated wait: ~' + (remaining_s < 60 ? remaining_s + ' seconds' : remaining_m + ' minute(s)') + '.';
|
wait_msg += '\nEstimated wait: ~' + (remaining_s < 60 ? remaining_s + ' seconds' : remaining_m + ' minute(s)') + '.';
|
||||||
}
|
}
|
||||||
alert(wait_msg);
|
bootbox.alert(wait_msg);
|
||||||
}, ttl_minutes);
|
}, ttl_minutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _start_gl_batch(doc_type, ids) {
|
// ── All Formulas sequential run ───────────────────────────────────────────
|
||||||
var formula_id = $('#gl-formula-' + doc_type).val();
|
function run_all_formula_batches(doc_type) {
|
||||||
|
var by_formula = _gl_loaded_by_formula[doc_type] || {};
|
||||||
|
var queue = Object.keys(by_formula).filter(function(fid) {
|
||||||
|
return (by_formula[fid] || []).length > 0;
|
||||||
|
});
|
||||||
|
if (!queue.length) { bootbox.alert('Load documents first.'); return; }
|
||||||
|
|
||||||
|
_formula_run_queue[doc_type] = queue;
|
||||||
|
set_btn_state('#gl-btn-run-' + doc_type, false);
|
||||||
|
set_btn_state('#gl-btn-load-' + doc_type, false);
|
||||||
|
run_next_formula(doc_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_next_formula(doc_type) {
|
||||||
|
var queue = _formula_run_queue[doc_type] || [];
|
||||||
|
if (!queue.length) {
|
||||||
|
BatchOverlay.done('All formulas posted.');
|
||||||
|
set_btn_state('#gl-btn-load-' + doc_type, true);
|
||||||
|
load_gl_tab(doc_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fid = queue.shift();
|
||||||
|
var ids = (_gl_loaded_by_formula[doc_type] || {})[fid] || [];
|
||||||
|
|
||||||
|
var missing = (_gl_rows[doc_type] || []).filter(function(r) {
|
||||||
|
return r._formula_id == fid && Number(r.product_mapping_missing || 0) > 0;
|
||||||
|
});
|
||||||
|
if (missing.length) {
|
||||||
|
run_next_formula(doc_type); // skip this formula
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var ttl = Math.max(2, Math.ceil(ids.length * 350 / 60000 * 1.2));
|
||||||
|
var formula_label = $('#gl-formula-' + doc_type + ' option[value="' + fid + '"]').text();
|
||||||
|
|
||||||
|
acquire_op_lock('gl_post', function() {
|
||||||
|
_start_gl_batch(doc_type, ids, function() {
|
||||||
|
run_next_formula(doc_type);
|
||||||
|
}, fid);
|
||||||
|
}, function(msg, res) {
|
||||||
|
var wait_msg = msg || 'A GL posting batch is already running.';
|
||||||
|
if (res && res.expires_at) {
|
||||||
|
var s = Math.max(0, Math.round((new Date(res.expires_at) - new Date()) / 1000));
|
||||||
|
wait_msg += ' (~' + (s < 60 ? s + 's' : Math.ceil(s/60) + 'm') + ')';
|
||||||
|
}
|
||||||
|
bootbox.alert(wait_msg);
|
||||||
|
}, ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── core batch processor ──────────────────────────────────────────────────
|
||||||
|
function _start_gl_batch(doc_type, ids, onComplete, formula_id_override) {
|
||||||
|
var formula_id = formula_id_override || $('#gl-formula-' + doc_type).val();
|
||||||
var $msg = $('#gl-msg-' + doc_type);
|
var $msg = $('#gl-msg-' + doc_type);
|
||||||
|
|
||||||
set_btn_state('#gl-btn-load-' + doc_type, false);
|
set_btn_state('#gl-btn-load-' + doc_type, false);
|
||||||
set_btn_state('#gl-btn-run-' + doc_type, false);
|
set_btn_state('#gl-btn-run-' + doc_type, false);
|
||||||
$msg.addClass('d-none').empty();
|
$msg.addClass('d-none').empty();
|
||||||
|
|
||||||
show_batch_overlay(DOC_LABELS[doc_type] || doc_type, ids.length);
|
var label = DOC_LABELS[doc_type] || doc_type;
|
||||||
|
if (formula_id_override) {
|
||||||
|
label += ' — ' + $('#gl-formula-' + doc_type + ' option[value="' + formula_id_override + '"]').text().trim();
|
||||||
|
}
|
||||||
|
show_batch_overlay(label, ids.length);
|
||||||
|
|
||||||
batch_process(
|
batch_process(
|
||||||
'gl_post',
|
'gl_post',
|
||||||
@@ -298,11 +425,12 @@
|
|||||||
update_batch_overlay(done, total);
|
update_batch_overlay(done, total);
|
||||||
},
|
},
|
||||||
function(failed) {
|
function(failed) {
|
||||||
// Always release DB lock — whether succeeded or failed
|
|
||||||
release_op_lock('gl_post');
|
release_op_lock('gl_post');
|
||||||
|
|
||||||
var succeeded = ids.length - failed.length;
|
var succeeded = ids.length - failed.length;
|
||||||
|
|
||||||
|
if (!onComplete) {
|
||||||
|
// Single-formula mode — show result in tab
|
||||||
if (failed.length === 0) {
|
if (failed.length === 0) {
|
||||||
_gl_failed[doc_type] = [];
|
_gl_failed[doc_type] = [];
|
||||||
BatchOverlay.done(succeeded + ' document(s) posted successfully.');
|
BatchOverlay.done(succeeded + ' document(s) posted successfully.');
|
||||||
@@ -322,30 +450,29 @@
|
|||||||
+ '<i class="ti ti-refresh me-1"></i>Retry Failed</button>');
|
+ '<i class="ti ti-refresh me-1"></i>Retry Failed</button>');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
set_btn_state('#gl-btn-load-' + doc_type, true);
|
||||||
|
load_gl_tab(doc_type);
|
||||||
|
} else {
|
||||||
|
// All-Formulas sequential mode — hand off to queue runner
|
||||||
|
BatchOverlay.done(succeeded + ' posted' + (failed.length ? ', ' + failed.length + ' failed' : '') + '.');
|
||||||
|
onComplete(succeeded, failed.length);
|
||||||
|
}
|
||||||
|
|
||||||
// Log the batch action
|
// Log
|
||||||
var ctx = document.getElementById('session-context');
|
var ctx = document.getElementById('session-context');
|
||||||
ajax_request({
|
ajax_request({
|
||||||
url: '<?php echo $server_url?>accounting/api/engine/log_batch_action.php',
|
url: '<?php echo $server_url?>accounting/api/engine/log_batch_action.php',
|
||||||
queueLock: false,
|
queueLock: false, noLoading: true,
|
||||||
noLoading: true,
|
|
||||||
data: {
|
data: {
|
||||||
otp: ctx ? ctx.dataset.otp : '',
|
otp: ctx ? ctx.dataset.otp : '',
|
||||||
company_id: ctx ? ctx.dataset.companyId : '',
|
company_id: ctx ? ctx.dataset.companyId : '',
|
||||||
action: 'post',
|
action: 'post', type: 'gl_post',
|
||||||
type: 'gl_post',
|
doc_type: doc_type, total: ids.length,
|
||||||
doc_type: doc_type,
|
succeeded: succeeded, failed: failed.length,
|
||||||
total: ids.length,
|
|
||||||
succeeded: succeeded,
|
|
||||||
failed: failed.length,
|
|
||||||
failed_ids: JSON.stringify(failed.map(function(f) { return f.item; }))
|
failed_ids: JSON.stringify(failed.map(function(f) { return f.item; }))
|
||||||
},
|
},
|
||||||
onSuccess: function() {}
|
onSuccess: function() {}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reload table to reflect updated GL status
|
|
||||||
set_btn_state('#gl-btn-load-' + doc_type, true);
|
|
||||||
load_gl_tab(doc_type);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -361,7 +488,7 @@
|
|||||||
var ttl_minutes = Math.max(2, Math.ceil(ids.length * per_item_ms / 60000 * 1.2));
|
var ttl_minutes = Math.max(2, Math.ceil(ids.length * per_item_ms / 60000 * 1.2));
|
||||||
|
|
||||||
acquire_op_lock('gl_post', function() {
|
acquire_op_lock('gl_post', function() {
|
||||||
_start_gl_batch(doc_type, ids);
|
_start_gl_batch(doc_type, ids, null);
|
||||||
}, function(msg, res) {
|
}, function(msg, res) {
|
||||||
var wait_msg = msg || 'A GL posting batch is already running.';
|
var wait_msg = msg || 'A GL posting batch is already running.';
|
||||||
if (res && res.expires_at) {
|
if (res && res.expires_at) {
|
||||||
@@ -369,7 +496,7 @@
|
|||||||
var remaining_m = Math.ceil(remaining_s / 60);
|
var remaining_m = Math.ceil(remaining_s / 60);
|
||||||
wait_msg += '\nEstimated wait: ~' + (remaining_s < 60 ? remaining_s + ' seconds' : remaining_m + ' minute(s)') + '.';
|
wait_msg += '\nEstimated wait: ~' + (remaining_s < 60 ? remaining_s + ' seconds' : remaining_m + ' minute(s)') + '.';
|
||||||
}
|
}
|
||||||
alert(wait_msg);
|
bootbox.alert(wait_msg);
|
||||||
}, ttl_minutes);
|
}, ttl_minutes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +535,6 @@ function gl_tab_html(string $doc_type, string $label): string {
|
|||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<label class="form-label mb-1 small">GL Formula <span class="text-danger">*</span></label>
|
<label class="form-label mb-1 small">GL Formula <span class="text-danger">*</span></label>
|
||||||
<select id="gl-formula-{$doc_type}" class="form-select form-select-sm" style="width:220px;">
|
<select id="gl-formula-{$doc_type}" class="form-select form-select-sm" style="width:220px;">
|
||||||
<option value="">— Select formula —</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
@@ -431,7 +557,7 @@ function gl_tab_html(string $doc_type, string $label): string {
|
|||||||
<!-- Result message -->
|
<!-- Result message -->
|
||||||
<div id="gl-msg-{$doc_type}" class="d-none mb-3"></div>
|
<div id="gl-msg-{$doc_type}" class="d-none mb-3"></div>
|
||||||
|
|
||||||
<!-- Document listing (informational, no selection) -->
|
<!-- Document listing -->
|
||||||
<table id="gl-table-{$doc_type}" class="table table-hover mb-0 table-centered">
|
<table id="gl-table-{$doc_type}" class="table table-hover mb-0 table-centered">
|
||||||
<thead class="table-primary border-light">
|
<thead class="table-primary border-light">
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
@@ -555,7 +555,7 @@ function load_location_config(callback) {
|
|||||||
/** =========================
|
/** =========================
|
||||||
* PREPARE FORM DATA
|
* PREPARE FORM DATA
|
||||||
* ========================= */
|
* ========================= */
|
||||||
function load_formula_options(select_id, document_type, selected_id) {
|
function load_formula_options(select_id, document_type, selected_id, onLoaded) {
|
||||||
var ctx = document.getElementById('session-context');
|
var ctx = document.getElementById('session-context');
|
||||||
ajax_request({
|
ajax_request({
|
||||||
url: server_url + 'accounting/api/engine/account_formula.php',
|
url: server_url + 'accounting/api/engine/account_formula.php',
|
||||||
@@ -570,12 +570,13 @@ function load_formula_options(select_id, document_type, selected_id) {
|
|||||||
},
|
},
|
||||||
onSuccess: function(res) {
|
onSuccess: function(res) {
|
||||||
var $sel = $('#' + select_id);
|
var $sel = $('#' + select_id);
|
||||||
$sel.empty().append('<option value="">— None —</option>');
|
$sel.empty();
|
||||||
$.each(res.output || [], function(i, f) {
|
$.each(res.output || [], function(i, f) {
|
||||||
var label = escape_html(f.formula_name) + (f.is_default == 1 ? ' (default)' : '');
|
var label = escape_html(f.formula_name) + (f.is_default == 1 ? ' (default)' : '');
|
||||||
$sel.append('<option value="' + f.id + '">' + label + '</option>');
|
$sel.append('<option value="' + f.id + '">' + label + '</option>');
|
||||||
});
|
});
|
||||||
if (selected_id) $sel.val(selected_id);
|
if (selected_id) $sel.val(selected_id);
|
||||||
|
if (onLoaded) onLoaded(res.output || []);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user