fix(fno): run declaration calculations once per Dövr pick
Picking a period fired every recalculation twice. `frm.set_value()` schedules the
field's handlers asynchronously (frappe.model.set_value -> run_serially), so by
the time the first trigger ran, both `ay`/`rüb` and `il` were already set in
frm.doc — and each field's handler then did a full pass. In VAT that also meant
`populate_vat_tables` was called twice per pick.
Five declarations were affected, all of them via Formula_Editor_Script_* which
bind a handler to every field a formula depends on: Declaration of value added
tax, Declaration of mining tax, Road tax 2, Tax return withheld at source of
payment, Single declaration related to salaried and non-salaried work.
Those scripts are generated, so they can't be patched — the fix has to live in
the picker. Instead of two set_value() calls, write the fields directly, do what
set_value would have done (refresh_field, refresh_dependency, dirty) and fire the
handlers exactly once.
Firing only `il` is safe: for every affected declaration the period handler and
the `il` handler have byte-identical bodies once the trigger-field argument is
normalized (VAT 2750 lines each, single declaration 1202, mining tax 484, road
tax 2 128, tax withheld 4 — differing only in a comment), and
calculate_table_row_field() never reads its triggerField argument. A runtime
fallback triggers the period field instead when no `il` handler is bound.
Note this cannot be done with set_value("il", year) alone: frappe.model.set_value
skips both the trigger and dirty() when the value is unchanged, so changing only
the month within the same year would silently recalculate nothing.
Verified headless: one call per pick on both VAT (month) and Single declaration
(quarter), including a second pick within the same year.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fd389d7b37
commit
afd65ce302
|
|
@ -102,19 +102,50 @@ frappe.provide("taxes_az.dovr");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seçilmiş tarixi ay/il/rüb + dövr-a yazır.
|
// Seçilmiş tarixi ay/il/rüb + dövr-a yazır və hesablamaları BİR DƏFƏ işə salır.
|
||||||
|
//
|
||||||
|
// Niyə `frm.set_value()` yox:
|
||||||
|
// set_value hər sahə üçün ayrıca trigger qoyur, triggerlər isə asinxron
|
||||||
|
// işləyir (frappe.model.set_value -> run_serially). Yəni `ay` və `il`
|
||||||
|
// dəyərləri hər ikisi frm.doc-a düşəndən sonra HƏR İKİ handler işə düşür və
|
||||||
|
// bütün hesablama iki dəfə aparılır (VAT-da həm də populate_vat_tables iki
|
||||||
|
// dəfə çağırılır).
|
||||||
|
// Üstəlik set_value dəyər dəyişməyibsə heç nə etmir (`doc[key] !== value`),
|
||||||
|
// ona görə yalnız ayı dəyişəndə (il eyni qalanda) `il`-ə arxalanmaq olmaz —
|
||||||
|
// nə trigger, nə də dirty olardı.
|
||||||
|
//
|
||||||
|
// Ona görə set_value-nun etdiklərini əl ilə təkrarlayırıq və trigger-i bir dəfə
|
||||||
|
// özümüz çağırırıq. Bu təhlükəsizdir: bütün ФНО-larda period handler-i ilə `il`
|
||||||
|
// handler-inin gövdəsi eynidir (formula editor hər asılı sahə üçün eyni bloku
|
||||||
|
// generasiya edir), `calculate_table_row_field`-in triggerField arqumenti isə
|
||||||
|
// heç yerdə istifadə olunmur.
|
||||||
function apply_selection(frm, mode, date) {
|
function apply_selection(frm, mode, date) {
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
|
const pf = period_field(mode); // "ay" | "rüb" | null (annual)
|
||||||
let period = null;
|
let period = null;
|
||||||
if (mode === "month") {
|
|
||||||
period = MONTHS[date.getMonth()];
|
if (pf) {
|
||||||
frm.set_value("ay", period);
|
period = (mode === "month")
|
||||||
} else if (is_quarter(mode)) {
|
? MONTHS[date.getMonth()]
|
||||||
period = QUARTERS[Math.floor(date.getMonth() / 3)];
|
: QUARTERS[Math.floor(date.getMonth() / 3)];
|
||||||
frm.set_value(period_field(mode), period);
|
frm.doc[pf] = period;
|
||||||
|
}
|
||||||
|
frm.doc.il = year;
|
||||||
|
frm.doc["dövr"] = build_label(mode, period, year);
|
||||||
|
|
||||||
|
if (pf) frm.refresh_field(pf);
|
||||||
|
frm.refresh_field("il");
|
||||||
|
frm.refresh_field("dövr");
|
||||||
|
frm.layout.refresh_dependency();
|
||||||
|
frm.dirty();
|
||||||
|
|
||||||
|
// Hesablamaları bir dəfə işə salırıq. Adətən `il` handler-i var; yoxdursa
|
||||||
|
// period sahəsinin handler-inə geri düşürük.
|
||||||
|
const bound = frappe.ui.form.handlers[frm.doctype] || {};
|
||||||
|
const on = (bound["il"] || []).length ? "il" : pf;
|
||||||
|
if (on) {
|
||||||
|
frm.script_manager.trigger(on, frm.doctype, frm.docname);
|
||||||
}
|
}
|
||||||
frm.set_value("il", year);
|
|
||||||
frm.set_value("dövr", build_label(mode, period, year));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function inject_style() {
|
function inject_style() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue