fix(bank-integration): no checkbox flicker + keep "use original description" on mode change

Two BRT polish fixes:
- The checkbox column was added by destroying and rebuilding the
  DataTable after each "Get Unreconciled Entries", which visibly redrew
  the rows. Replaced with a wholesale override of DataTableManager's
  get_datatable that creates the table with checkboxColumn:true from the
  start and injects the toolbar there — no rebuild, no flicker. The
  render-event polling is gone.
- _applyModeVisibility unconditionally un-hid "Custom Purpose Keyword"
  when leaving "Documents & Reconcile" mode, overriding the effect of
  the "Use original description" checkbox. Now it re-applies the
  checkbox state after the mode-driven visibility pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-05-11 13:21:52 +00:00
parent 71e2c06a35
commit 6c395f9e3b
1 changed files with 50 additions and 54 deletions

View File

@ -1,16 +1,17 @@
// Bank Reconciliation Tool extensions for jey_erp.
//
// (1) refresh — patches DataTableManager prototype once to add a
// "Bank Transaction" column (BT name with a link).
// (2) render — fires on every "Get Unreconciled Entries"; rebuilds the
// DataTable with a checkbox column and injects a "Create & Reconcile"
// toolbar. Selected rows are mapped to Payment Entry / Journal Entry
// using either a Bank Integration record's mappings or Kapital Bank
// Settings' mappings (chosen in the dialog; default comes from the
// Bank Account's hidden bank_integration field, written back on submit).
// All wiring happens via a one-time DataTableManager prototype patch (on the
// form's refresh):
// - get_dt_columns / format_row : adds a "Bank Transaction" column (BT name + link)
// - get_datatable : creates the table WITH a checkbox column and
// injects the "Create & Reconcile" toolbar
// (done here so there is no destroy/rebuild flicker)
//
// The dialog / mapping logic is a port of kapital_bank's BRT extension,
// generalised to pick the mapping source.
// "Create & Reconcile" maps the selected Bank Transactions to Payment Entry /
// Journal Entry using a chosen mapping source: a Bank Integration record
// (jey_erp) or Kapital Bank Settings (kapital_bank). The default source comes
// from the Bank Account's hidden bank_integration field and is written back on
// submit. The dialog / mapping logic is a port of kapital_bank's BRT extension.
frappe.ui.form.on("Bank Reconciliation Tool", {
refresh(frm) {
@ -21,6 +22,7 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
if (!DTM || DTM.prototype._jey_erp_patched) return;
const proto = DTM.prototype;
// --- "Bank Transaction" column ---
const orig_get_dt_columns = proto.get_dt_columns;
proto.get_dt_columns = function () {
orig_get_dt_columns.call(this);
@ -42,43 +44,37 @@ frappe.ui.form.on("Bank Reconciliation Tool", {
return result;
};
// --- checkbox column + Create & Reconcile toolbar ---
// Replace get_datatable wholesale so the table is built with
// checkboxColumn:true from the start (no visible rebuild).
proto.get_datatable = function () {
this.datatable = new frappe.DataTable(this.$reconciliation_tool_dt.get(0), {
columns: this.columns,
data: this.transactions,
dynamicRowHeight: true,
checkboxColumn: true,
inlineFilters: true,
});
$(`.${this.datatable.style.scopeClass} .dt-scrollable`).css("max-height", "calc(100vh - 400px)");
if (this.transactions.length > 0) {
this.$reconciliation_tool_dt.show();
this.$no_bank_transactions.hide();
} else {
this.$reconciliation_tool_dt.hide();
this.$no_bank_transactions.show();
}
this._bi_scopeClass = this.datatable.style.scopeClass;
BIBRT.injectToolbar(this);
};
proto._jey_erp_patched = true;
});
},
render(frm) {
if (frm._bi_check_interval) clearInterval(frm._bi_check_interval);
frm._bi_check_interval = setInterval(function () {
const dtm = frm.bank_reconciliation_data_table_manager;
if (dtm && dtm.datatable && !dtm._bi_enhanced) {
clearInterval(frm._bi_check_interval);
BIBRT.enhance(frm, dtm);
}
}, 200);
setTimeout(function () { clearInterval(frm._bi_check_interval); }, 15000);
},
});
const BIBRT = {
enhance: function (frm, dtm) {
dtm._bi_enhanced = true;
dtm._bi_frm = frm;
dtm.datatable.destroy();
dtm.datatable = new frappe.DataTable(dtm.$reconciliation_tool_dt.get(0), {
columns: dtm.columns,
data: dtm.transactions,
dynamicRowHeight: true,
checkboxColumn: true,
inlineFilters: true,
});
$(`.${dtm.datatable.style.scopeClass} .dt-scrollable`).css("max-height", "calc(100vh - 400px)");
dtm.set_listeners();
dtm._bi_scopeClass = dtm.datatable.style.scopeClass;
BIBRT.injectToolbar(dtm);
},
injectToolbar: function (dtm) {
$("#bi-brt-toolbar").remove();
@ -126,15 +122,14 @@ const BIBRT = {
return;
}
const frm = dtm._bi_frm;
const bankAccount = frm.doc.bank_account;
const bankAccount = dtm.bank_account;
if (!bankAccount) {
frappe.msgprint({ title: __("Bank Account Required"), indicator: "orange",
message: __("Pick a Bank Account in the form first.") });
return;
}
// dtm.transactions rows are arrays. With the jey_erp prototype patch active the layout is:
// dtm.transactions rows are arrays. With the jey_erp prototype patch active:
// [0]date [1]party_type [2]party(HTML) [3]description [4]deposit [5]withdrawal
// [6]unallocated [7]reference_number [8]bank_transaction_name(string) [9]actions(button HTML)
const txns = [];
@ -178,7 +173,6 @@ const BIBRT = {
return;
}
// Build mapping-source options + load BA default
Promise.all([
frappe.db.get_list("Bank Integration", { fields: ["name", "bank_name"], limit: 200 }),
frappe.db.get_value("Bank Account", bankAccount, ["bank_integration_type", "bank_integration"]),
@ -187,7 +181,7 @@ const BIBRT = {
const baFields = (baResp && baResp.message) || {};
const kbInstalled = kbList && kbList.length > 0;
const sourceMap = {}; // value -> label
const sourceMap = {};
(integrations || []).forEach(i => {
sourceMap["Bank Integration::" + i.name] = __("Bank Integration: {0}", [i.bank_name || i.name]);
});
@ -208,12 +202,11 @@ const BIBRT = {
if (sourceMap[candidate]) defaultSource = candidate;
}
BIBRT._renderDialog(dtm, frm, bankAccount, txns, skippedCount, sourceMap, sourceValues, defaultSource);
BIBRT._renderDialog(dtm, bankAccount, txns, skippedCount, sourceMap, sourceValues, defaultSource);
});
},
_renderDialog: function (dtm, frm, bankAccount, txns, skippedCount, sourceMap, sourceValues, defaultSource) {
// Preview table (deduped)
_renderDialog: function (dtm, bankAccount, txns, skippedCount, sourceMap, sourceValues, defaultSource) {
const purposeMap = new Map();
txns.forEach(function (txn) {
const key = txn.purpose + "|" + txn.drcr;
@ -340,13 +333,12 @@ const BIBRT = {
const [sourceType, sourceName] = values.source.split("::");
d.disable_primary_action();
// Persist the chosen source on the Bank Account, then run the mapping/reconcile
frappe.call({
method: "jey_erp.bank_integration.import_api.update_bank_account_bi_default",
args: { bank_account: bankAccount, bi_type: sourceType, bi_name: sourceName },
always: function () {
BIBRT._submit(d, finalTxns, sourceType, sourceName,
values.paid_from, values.paid_to, values.document_type, values.mode, frm);
values.paid_from, values.paid_to, values.document_type, values.mode);
},
});
},
@ -356,7 +348,6 @@ const BIBRT = {
d.show();
BIBRT._applyModeVisibility(d);
// Pre-fill custom purpose from the Description inline filter if active
const $fi = $(`.${dtm._bi_scopeClass} .dt-row-filter input.dt-filter[data-name="Description"]`);
const filterVal = ($fi.val() || "").trim();
if (filterVal) d.set_value("custom_purpose", filterVal);
@ -367,10 +358,15 @@ const BIBRT = {
const toHide = ["preview_html", "sec_options", "document_type", "use_original_purpose",
"custom_purpose", "sec_accounts", "paid_from", "col_break", "paid_to"];
toHide.forEach(fn => d.set_df_property(fn, "hidden", isDR ? 1 : 0));
// The "use original description" checkbox also hides custom_purpose — re-apply
// it so switching Action modes doesn't reveal a field the checkbox had hidden.
if (!isDR && d.get_value("use_original_purpose")) {
d.set_df_property("custom_purpose", "hidden", 1);
}
d.refresh_fields(toHide);
},
_submit: function (dialog, txns, sourceType, sourceName, paid_from, paid_to, document_type, mode, frm) {
_submit: function (dialog, txns, sourceType, sourceName, paid_from, paid_to, document_type, mode) {
const isKB = sourceType === "Kapital Bank Settings";
const method = isKB
? "kapital_bank.mapping.create_purpose_mappings"
@ -415,7 +411,7 @@ const BIBRT = {
message: parts.join(" &bull; ") || __("No changes"),
indicator: (res.created_mappings > 0 || res.created_docs > 0) ? "green" : "blue",
}, 6);
if (frm) frm.refresh();
if (cur_frm && cur_frm.doctype === "Bank Reconciliation Tool") cur_frm.refresh();
if (res.errors && res.errors.length) BIBRT.showErrors(res.errors);
},
error: function () {