perf(vat): drive the post-fill recompute off actual call completion, no timer

Instead of waiting a fixed delay after selecting dövr, wrap frappe.call to track
the fill calls (populate_vat_tables + formula_editor run_reports_batch): suppress
the per-write recompute while any is in flight and run it exactly once the moment
the last one resolves (deferred a tick so the apply lands first). User edits
recompute instantly. Robust regardless of how long the reports take.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-07-15 15:52:37 +00:00
parent f45414e5ac
commit 9e8732a676
1 changed files with 35 additions and 21 deletions

View File

@ -284,31 +284,45 @@ function vc_recompute(frm) {
frm.refresh_field("sertifikathesabatdövründəmalındəyərininsəhifəsicəmi");
}
// --- Suppress the per-write recompute during the report-fill storm (populate_vat_tables /
// formula_editor write hundreds of cells via set_value; recomputing on each would freeze
// the UI). "Fill mode" starts on period change and re-arms on every programmatic write.
// 3s after the fill settles it runs the recompute ONCE, so roll-ups / passthrough
// (e.g. 301.1 = Σ children, turnover ← appendices) fill in from the report data.
// User edits (outside fill mode) are debounced. ---
var vc_fill_mode = false, vc_fill_timer = null, vc_frm = null;
function vc_mark_fill(frm) {
if (frm) vc_frm = frm;
vc_fill_mode = true;
if (vc_fill_timer) clearTimeout(vc_fill_timer);
vc_fill_timer = setTimeout(function () {
vc_fill_mode = false;
if (vc_frm) vc_recompute(vc_frm); // one recompute after the report-fill burst settles
}, 400);
// --- Recompute exactly when the report-fill finishes — event-driven, no timer. Picking a
// period fires populate_vat_tables + formula_editor (run_reports_batch) via frappe.call,
// each writing many cells; recomputing per write would freeze the form. We wrap
// frappe.call to track those specific calls: the per-write recompute is suppressed while
// any is in flight, and runs ONCE when the last one resolves (deferred one tick so the
// response's synchronous apply lands first). No timer, so it waits exactly as long as
// the reports actually take. ---
var VC = (frappe.__vc = frappe.__vc || { mode: false, n: 0 });
VC.recompute = vc_recompute; // always the current load's recompute
VC.re = /populate_vat_tables|run_reports_batch/;
if (!frappe.__vc_call_wrapped) {
frappe.__vc_call_wrapped = true;
var _vc_call = frappe.call;
frappe.call = function (opts) {
var m = (opts && opts.method) || (typeof opts === "string" ? opts : "");
var fill = VC.re.test(m || "");
if (fill) { VC.n++; VC.mode = true; }
var ret = _vc_call.apply(this, arguments);
if (fill && ret && typeof ret.then === "function") {
var done = function () {
if (--VC.n > 0) return; // other fill calls still running
VC.n = 0;
setTimeout(function () { // let this response's set_values apply first
VC.mode = false;
if (cur_frm && cur_frm.doctype === "Declaration of value added tax" && VC.recompute) {
VC.recompute(cur_frm);
}
}, 0);
};
ret.then(done, done);
}
return ret;
};
}
function vc_onchange(frm) {
vc_frm = frm;
if (vc_fill_mode) { vc_mark_fill(frm); return; } // during report-fill: don't recompute per write (would freeze)
vc_recompute(frm); // user edit: recompute instantly
if (frappe.__vc.mode) return; // report-fill running: recompute once when the last fill call resolves
vc_recompute(frm); // user edit: instant
}
// period change (dövr picker writes ay/il) starts the fill window
frappe.ui.form.on("Declaration of value added tax", { ay: vc_mark_fill, il: vc_mark_fill, "dövr": vc_mark_fill });
// recompute on input changes in each child table
[
["Declaration of value added tax Elave 2 Hisse 1", [A2H1AMT]],