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"
-}