From 408102117c73a3059c7cdf86ae74bba7a06eab04 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Mon, 18 May 2026 12:24:53 +0000 Subject: [PATCH] fix(workspace): insert importer link into ERPNext Invoicing Banking card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the standalone Bank Statements workspace (incorrect approach — ERPNext doesn't expose top-level apps as tiles automatically) with a runtime insertion of a single 'Bank Statement Importer' link into the existing 'Banking' card on the ERPNext-owned Invoicing workspace. Editing the workspace at runtime via after_migrate (not by overriding its JSON) is intentional: ERPNext resyncs that JSON on every `bench migrate`, so a file-level patch would be reverted. after_migrate runs AFTER the resync, so the inserted link stays. The insert is idempotent — it skips when the link is already present, when the Banking card break isn't there, or when Bank Statement Importer DocType doesn't exist yet. --- jey_erp/bank_integration/migrations.py | 67 +++++++ jey_erp/hooks.py | 2 + .../bank_statements/bank_statements.json | 166 ------------------ 3 files changed, 69 insertions(+), 166 deletions(-) delete mode 100644 jey_erp/jey_erp/workspace/bank_statements/bank_statements.json diff --git a/jey_erp/bank_integration/migrations.py b/jey_erp/bank_integration/migrations.py index 4dc91a4..3ba3d70 100644 --- a/jey_erp/bank_integration/migrations.py +++ b/jey_erp/bank_integration/migrations.py @@ -3,6 +3,73 @@ import frappe +def add_importer_link_to_invoicing_workspace(): + """Insert a 'Bank Statement Importer' link into the existing 'Banking' card + on the ERPNext 'Invoicing' workspace. + + This intentionally edits an ERPNext-owned workspace at runtime rather than + overriding its JSON file: ERPNext re-syncs the JSON on every `bench + migrate`, so any direct file edit would be reverted. We run from + after_migrate, which fires AFTER that resync, so this stays in place. + + Idempotent — runs every migrate but only inserts when the link is missing. + """ + ws_name = "Invoicing" + link_to = "Bank Statement Importer" + card_label = "Banking" + + if not frappe.db.exists("Workspace", ws_name): + return + if not frappe.db.exists("DocType", link_to): + return + + ws = frappe.get_doc("Workspace", ws_name) + + if any(l.type == "Link" and l.link_to == link_to for l in ws.links): + return + + # Find the position of the "Banking" card break. + banking_idx = None + for i, link in enumerate(ws.links): + if link.type == "Card Break" and (link.label or "").strip() == card_label: + banking_idx = i + break + + if banking_idx is None: + # No Banking card break — bail out instead of appending in a random spot. + print(f"BI: '{card_label}' Card Break not found on '{ws_name}' workspace, skipping link insert") + return + + # Find the next Card Break — our link goes right before it (end of Banking + # section). If Banking is the last card, append to the very end. + next_card_idx = len(ws.links) + for i in range(banking_idx + 1, len(ws.links)): + if ws.links[i].type == "Card Break": + next_card_idx = i + break + + # Append a row (Frappe auto-assigns parent fields), then move it into place. + ws.append("links", { + "label": link_to, + "link_to": link_to, + "link_type": "DocType", + "type": "Link", + "onboard": 0, + "is_query_report": 0, + "hidden": 0, + }) + new_row = ws.links.pop() + ws.links.insert(next_card_idx, new_row) + for i, l in enumerate(ws.links): + l.idx = i + 1 + + ws.flags.ignore_version = True + ws.flags.ignore_permissions = True + ws.save(ignore_permissions=True) + frappe.db.commit() + print(f"BI: added '{link_to}' link to '{card_label}' card on '{ws_name}' workspace") + + def link_kb_bank_accounts_to_bi(): """For every Bank Account that appears in Kapital Bank Settings.account_mappings, set bank_integration_type='Kapital Bank Settings' / bank_integration='Kapital Bank Settings' diff --git a/jey_erp/hooks.py b/jey_erp/hooks.py index 8644af1..84533e8 100644 --- a/jey_erp/hooks.py +++ b/jey_erp/hooks.py @@ -144,11 +144,13 @@ def after_migrate_combined(): rename_bip_purposes, migrate_standard_field_codes_to_labels, copy_excel_preset_into_bank_integration, + add_importer_link_to_invoicing_workspace, ) link_kb_bank_accounts_to_bi() rename_bip_purposes() migrate_standard_field_codes_to_labels() copy_excel_preset_into_bank_integration() + add_importer_link_to_invoicing_workspace() except Exception as e: print(f"BI: post-migrate sync failed: {e}") # REMOVED: Asset categories creation moved to setup_wizard_complete hook diff --git a/jey_erp/jey_erp/workspace/bank_statements/bank_statements.json b/jey_erp/jey_erp/workspace/bank_statements/bank_statements.json deleted file mode 100644 index b9a0da7..0000000 --- a/jey_erp/jey_erp/workspace/bank_statements/bank_statements.json +++ /dev/null @@ -1,166 +0,0 @@ -{ - "app": "jey_erp", - "charts": [], - "content": "[{\"id\":\"bs_header_shortcuts\",\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"id\":\"bs_shortcut_importer\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Bank Statement Importer\",\"col\":3}},{\"id\":\"bs_shortcut_bt\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Bank Transaction\",\"col\":3}},{\"id\":\"bs_shortcut_brt\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Bank Reconciliation Tool\",\"col\":3}},{\"id\":\"bs_spacer\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"bs_header_masters\",\"type\":\"header\",\"data\":{\"text\":\"Setup & Registry\",\"col\":12}},{\"id\":\"bs_card_setup\",\"type\":\"card\",\"data\":{\"card_name\":\"Setup\",\"col\":4}},{\"id\":\"bs_card_registry\",\"type\":\"card\",\"data\":{\"card_name\":\"Registry\",\"col\":4}},{\"id\":\"bs_card_daily\",\"type\":\"card\",\"data\":{\"card_name\":\"Daily Use\",\"col\":4}}]", - "creation": "2026-05-18 00:00:00.000000", - "custom_blocks": [], - "docstatus": 0, - "doctype": "Workspace", - "for_user": "", - "hide_custom": 0, - "icon": "accounting", - "idx": 0, - "is_hidden": 0, - "label": "Bank Statements", - "links": [ - { - "hidden": 0, - "is_query_report": 0, - "label": "Setup", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Bank Statement Importer", - "link_count": 0, - "link_to": "Bank Statement Importer", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Bank", - "link_count": 0, - "link_to": "Bank", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Bank Account", - "link_count": 0, - "link_to": "Bank Account", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Daily Use", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Bank Transaction", - "link_count": 0, - "link_to": "Bank Transaction", - "link_type": "DocType", - "onboard": 1, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Bank Reconciliation Tool", - "link_count": 0, - "link_to": "Bank Reconciliation Tool", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "hidden": 0, - "is_query_report": 0, - "label": "Registry", - "link_count": 0, - "onboard": 0, - "type": "Card Break" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Counterparties (Customers)", - "link_count": 0, - "link_to": "Bank Integration Customer", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Counterparties (Suppliers)", - "link_count": 0, - "link_to": "Bank Integration Supplier", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - }, - { - "dependencies": "", - "hidden": 0, - "is_query_report": 0, - "label": "Purpose Keywords", - "link_count": 0, - "link_to": "Bank Integration Purpose", - "link_type": "DocType", - "onboard": 0, - "type": "Link" - } - ], - "modified": "2026-05-18 00:00:00.000000", - "modified_by": "Administrator", - "module": "Jey Erp", - "name": "Bank Statements", - "number_cards": [], - "owner": "Administrator", - "parent_page": "Accounting", - "public": 1, - "quick_lists": [], - "restrict_to_domain": "", - "roles": [], - "sequence_id": 6.0, - "shortcuts": [ - { - "color": "Blue", - "doc_view": "List", - "label": "Bank Statement Importer", - "link_to": "Bank Statement Importer", - "type": "DocType" - }, - { - "color": "Green", - "doc_view": "List", - "label": "Bank Transaction", - "link_to": "Bank Transaction", - "type": "DocType" - }, - { - "color": "Grey", - "doc_view": "", - "label": "Bank Reconciliation Tool", - "link_to": "Bank Reconciliation Tool", - "type": "DocType" - } - ], - "title": "Bank Statements", - "type": "Workspace" -}