fix(cascade-delete): override frm.savetrash so stock confirm never runs

Previous approach replaced the Menu Delete item's jQuery click handler,
but Frappe wires the same item through its own event chain that bypassed
.off('click') — both our cascade dialog AND the stock "Permanently
delete X?" prompt fired in sequence.

Form's Delete menu item ends up calling frm.savetrash(); overriding that
method directly is the single point that intercepts every code path that
reaches it. Removed the brittle DOM-walking wireMenuItem helper.
This commit is contained in:
Ali 2026-05-18 14:00:54 +00:00
parent 31d93fb887
commit c198574f6c
1 changed files with 2 additions and 25 deletions

View File

@ -23,7 +23,8 @@ frappe.ui.form.on('Bank Statement Importer', {
// Replace the standard Menu → Delete with a cascading version. The
// stock action would just error out on the link-check (registry rows
// + Bank Account dynamic-link) and leave the user stuck.
BSICascadeDelete.installMenuOverride(frm);
// frm.savetrash() is what the Menu Delete item ultimately calls.
frm.savetrash = () => BSICascadeDelete.run(frm);
// === Load Data (file-based, registry-only) ===
frm.add_custom_button(__('Load Data'), () => {
@ -642,30 +643,6 @@ function _bi_list_header(label, total, refresh_id) {
// ═══════════════════════════════════════════════════════════════════════════════
const BSICascadeDelete = {
installMenuOverride(frm) {
// frappe.PageMenu renders the items right after refresh; defer slightly.
setTimeout(() => this._wireMenuItem(frm), 50);
},
_wireMenuItem(frm) {
// Each Standard menu item is an <a class="dropdown-item"> in the
// page menu. We replace the "Delete" one's click handler.
const $menu = frm.page.menu;
if (!$menu || !$menu.length) return;
const $delete = $menu.find('a.grey-link').filter(function () {
const label = ($(this).find('.menu-item-label').text() || $(this).text() || '').trim();
return label === __('Delete');
});
if (!$delete.length) return;
if ($delete.data('bsiCascadeWired')) return;
$delete.data('bsiCascadeWired', true);
$delete.off('click.bsiCascade').on('click.bsiCascade', (e) => {
e.preventDefault();
e.stopImmediatePropagation();
this.run(frm);
});
},
run(frm) {
if (frm.is_new()) return;
frappe.call({