gl aggregate table (ETL), cronjob by NODEJS

This commit is contained in:
Thanakorn S
2026-05-23 10:52:27 +07:00
parent 9c275eb358
commit f5ea74e134
15 changed files with 1048 additions and 230 deletions
+14 -80
View File
@@ -69,35 +69,6 @@
<?php require '../include_ending.php'; ?>
<!-- Batch processing overlay -->
<div id="batch-overlay" style="display:none; position:fixed; inset:0; z-index:9999;
background:rgba(0,0,0,0.55); align-items:center; justify-content:center;">
<div class="card shadow-lg p-4 text-center" style="min-width:380px; max-width:480px; width:90%;">
<div class="spinner-border text-primary mx-auto mb-3" role="status" style="width:2.5rem; height:2.5rem;"></div>
<div class="fw-semibold fs-6 mb-1" id="batch-overlay-title">Processing…</div>
<div class="text-muted small mb-4" id="batch-overlay-sub"></div>
<!-- Large percentage number -->
<div id="batch-overlay-pct"
style="font-size:3rem; font-weight:700; line-height:1; letter-spacing:-1px; color:#0d6efd;">
0%
</div>
<div class="text-muted small mb-3" id="batch-overlay-count">0 / 0 documents</div>
<!-- Progress bar (pure visual fill, no text inside) -->
<div class="progress mb-2" style="height:10px; border-radius:6px;">
<div id="batch-overlay-bar"
class="progress-bar progress-bar-striped progress-bar-animated"
role="progressbar" style="width:0%; border-radius:6px;"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="text-muted small" id="batch-overlay-eta">&nbsp;</div>
</div>
</div>
<script>
// (batch_process lives in custom.js)
@@ -247,37 +218,14 @@
return '<span class="badge bg-success-subtle text-success">Mapped</span>';
}
// ── batch overlay helpers ─────────────────────────────────────────────────
var _batch_start_ms = 0;
// ── batch overlay helpers — delegated to shared BatchOverlay ─────────────
function show_batch_overlay(label, total) {
_batch_start_ms = Date.now();
$('#batch-overlay-title').text('Batch GL Posting — ' + label);
$('#batch-overlay-sub').text('Starting…');
$('#batch-overlay-pct').text('0%');
$('#batch-overlay-bar').css('width', '0%').attr('aria-valuenow', 0);
$('#batch-overlay-count').text('0 / ' + total + ' documents');
$('#batch-overlay-eta').html('&nbsp;');
$('#batch-overlay').css('display', 'flex');
BatchOverlay.show('Batch GL Posting — ' + label, total, { unit: 'documents' });
}
function update_batch_overlay(done, total) {
var pct = Math.round(done / total * 100);
var elapsed = (Date.now() - _batch_start_ms) / 1000;
var eta_txt = '&nbsp;';
if (done > 0) {
var remaining = Math.round((elapsed / done) * (total - done));
eta_txt = remaining > 0 ? ('~' + remaining + 's remaining') : 'almost done…';
}
$('#batch-overlay-pct').text(pct + '%');
$('#batch-overlay-bar').css('width', pct + '%').attr('aria-valuenow', pct);
$('#batch-overlay-count').text(done + ' / ' + total + ' documents');
$('#batch-overlay-sub').text('Processing document ' + done + ' of ' + total + '…');
$('#batch-overlay-eta').html(eta_txt);
}
function hide_batch_overlay() {
$('#batch-overlay').hide();
BatchOverlay.update(done, total, 'document ' + done + ' of ' + total);
}
// ── run batch over all loaded IDs ─────────────────────────────────────────
@@ -323,15 +271,11 @@
function _start_gl_batch(doc_type, ids) {
var formula_id = $('#gl-formula-' + doc_type).val();
var $prog = $('#gl-progress-' + doc_type);
var $bar = $prog.find('.progress-bar');
var $msg = $('#gl-msg-' + doc_type);
set_btn_state('#gl-btn-load-' + doc_type, false);
set_btn_state('#gl-btn-run-' + doc_type, false);
$msg.addClass('d-none').empty();
$prog.removeClass('d-none');
$bar.css('width', '0%').text('0%');
show_batch_overlay(DOC_LABELS[doc_type] || doc_type, ids.length);
@@ -351,35 +295,32 @@
};
},
function(done, total) {
var pct = Math.round(done / total * 100);
$bar.css('width', pct + '%').attr('aria-valuenow', pct).text(pct + '%');
update_batch_overlay(done, total);
},
function(failed) {
// Always release DB lock — whether succeeded or failed
release_op_lock('gl_post');
hide_batch_overlay();
$prog.addClass('d-none');
var succeeded = ids.length - failed.length;
if (failed.length === 0) {
_gl_failed[doc_type] = [];
$msg.removeClass('d-none alert-danger').addClass('alert alert-success')
.text('Done. ' + succeeded + ' document(s) posted successfully.');
BatchOverlay.done(succeeded + ' document(s) posted successfully.');
} else {
_gl_failed[doc_type] = failed;
var nums = failed.map(function(f) { return f.item; }).join(', ');
var nums = failed.map(function(f) { return f.item; }).join(', ');
var detail = failed.map(function(f) {
return escape_html(f.item + (f.error ? ': ' + f.error : ''));
}).join('<br>');
$msg.removeClass('d-none alert-success').addClass('alert alert-danger')
.html('<strong>' + failed.length + ' failed</strong> after 3 retries (IDs: '
+ escape_html(nums) + '). ' + succeeded + ' succeeded.'
+ '<div class="small mt-2">' + detail + '</div>'
+ ' <button class="btn btn-sm btn-warning ms-2"'
+ ' onclick="retry_gl_batch(\'' + doc_type + '\')">'
+ '<i class="ti ti-refresh me-1"></i>Retry Failed</button>');
BatchOverlay.done(failed.length + ' failed · ' + succeeded + ' succeeded.', function() {
$msg.removeClass('d-none alert-success').addClass('alert alert-danger')
.html('<strong>' + failed.length + ' failed</strong> after 3 retries (IDs: '
+ escape_html(nums) + '). ' + succeeded + ' succeeded.'
+ '<div class="small mt-2">' + detail + '</div>'
+ ' <button class="btn btn-sm btn-warning ms-2"'
+ ' onclick="retry_gl_batch(\'' + doc_type + '\')">'
+ '<i class="ti ti-refresh me-1"></i>Retry Failed</button>');
});
}
// Log the batch action
@@ -487,13 +428,6 @@ function gl_tab_html(string $doc_type, string $label): string {
<!-- Summary badge -->
<div id="gl-badge-{$doc_type}" class="text-muted small mb-2"></div>
<!-- Progress bar -->
<div id="gl-progress-{$doc_type}" class="progress mb-3 d-none" style="height:22px;">
<div class="progress-bar progress-bar-striped progress-bar-animated"
role="progressbar" style="width:0%" aria-valuenow="0"
aria-valuemin="0" aria-valuemax="100">0 / 0</div>
</div>
<!-- Result message -->
<div id="gl-msg-{$doc_type}" class="d-none mb-3"></div>