From 1bc9fd6b13e8f95bc4b046c89b53200f99377673 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Tue, 28 Apr 2026 10:19:41 +0000 Subject: [PATCH] Silence two post-setup popups from bank materialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two unrelated user-visible errors appeared after a successful wizard run: 1. 'Hesab Növü: 2 tapılmadı' (×5, one per non-closed bank) Bank Account.account_type is a Link to the Bank Account Type doctype, which is empty on a fresh install. We were stuffing the e-taxes raw numeric 'type' code (e.g. '2' for card) into it. Field is optional — stop populating it, the validation error goes away. 2. 'Hesab 223.1 - AZN AZXX… ilə əlaqəli olduğu üçün silinə bilməz' (×1) ERPNext's setup_company → set_default_accounts picks the first Bank- typed Account and writes it to Company.default_bank_account. On the AZ chart that's a placeholder (223.1 - AZN AZXX… - JS), so when _delete_bank_placeholders later tries to delete it, Frappe blocks the delete with LinkExistsError pointing back at Company. Two-part fix: before the placeholder sweep, repoint Company.default_bank_account to the first real bank GL we just materialized (only when the current value is unset or a placeholder). And as a defensive fallback, _delete_bank_placeholders now catches LinkExistsError, clears the queued popup message, and disables the account instead of leaving the user with a scary error. --- jey_wizard/__init__.py | 2 +- jey_wizard/etaxes.py | 57 ++++++++++++++++++++++++++++--- jey_wizard/public/js/jey_setup.js | 2 +- 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/jey_wizard/__init__.py b/jey_wizard/__init__.py index f1380ee..9cb17e7 100644 --- a/jey_wizard/__init__.py +++ b/jey_wizard/__init__.py @@ -1 +1 @@ -__version__ = "0.1.7" +__version__ = "0.1.8" diff --git a/jey_wizard/etaxes.py b/jey_wizard/etaxes.py index b781592..b64d448 100644 --- a/jey_wizard/etaxes.py +++ b/jey_wizard/etaxes.py @@ -303,12 +303,15 @@ def _materialize_native_banks(company): created = 0 skipped_closed = 0 + created_gl_names = [] for acc in accounts: if (acc.get("status") or "").upper() == "C": skipped_closed += 1 continue try: - _materialize_one_bank(company, parent, acc) + gl = _materialize_one_bank(company, parent, acc) + if gl: + created_gl_names.append(gl) created += 1 except Exception as exc: frappe.log_error( @@ -316,6 +319,7 @@ def _materialize_native_banks(company): "Jey Wizard materialize (bank native)", ) + _repoint_company_default_bank(company, created_gl_names) _delete_bank_placeholders(company, parent) frappe.db.commit() # Success breadcrumb in Error Log so we can verify end-to-end run from the same @@ -352,13 +356,14 @@ def _find_bank_parent_account(company): def _materialize_one_bank(company, parent_account, row): # Accepts either the raw e-taxes payload shape (bankName/number/type…) or # the E-Taxes Bank Account doctype shape (bank_name/number/account_type). + # Returns the GL account name on success (used by the caller to repoint + # Company.default_bank_account before deleting placeholders), None otherwise. bank_name = (row.get("bankName") or row.get("bank_name") or "").strip() iban = (row.get("number") or "").strip() currency = (row.get("currency") or "").strip() or "AZN" - etx_account_type = (row.get("type") or row.get("account_type") or "").strip() if not bank_name or not iban: - return + return None # 1. Bank (global, unique on bank_name) if not frappe.db.exists("Bank", bank_name): @@ -393,6 +398,11 @@ def _materialize_one_bank(company, parent_account, row): {"bank": bank_name, "account_name": account_name, "company": company}, ) if not ba_exists: + # Bank Account.account_type is a Link to the Bank Account Type doctype + # (effectively empty on a fresh install). The e-taxes 'type' field is a + # numeric code (e.g. "2" for card) that has no Bank Account Type row to + # match — populating it raises "Hesab Növü: 2 tapılmadı" on validate. + # Field is optional, so just leave it unset. ba_doc = frappe.get_doc({ "doctype": "Bank Account", "account_name": account_name, @@ -402,10 +412,33 @@ def _materialize_one_bank(company, parent_account, row): "is_company_account": 1, "bank_account_no": iban, "iban": iban, - "account_type": etx_account_type or None, }) ba_doc.insert(ignore_permissions=True) + return gl_name + + +def _repoint_company_default_bank(company, created_gl_names): + """ERPNext's setup_company → set_default_accounts picks the first + account_type='Bank' Account it finds and writes it to + Company.default_bank_account. On a fresh AZ-CoA install that's a placeholder + (223.1 - AZN AZXX… - JS), and _delete_bank_placeholders then can't delete it + (LinkExistsError pointing back at Company). Repoint the default to the first + real bank GL we just created so the placeholder is free to remove. + + Only repoints when the current value is unset or matches the placeholder + pattern — never overwrites a value the user explicitly set. + """ + if not created_gl_names: + return + current = frappe.db.get_value("Company", company, "default_bank_account") + if current and "XXXX" not in current: + return + frappe.db.set_value( + "Company", company, "default_bank_account", + created_gl_names[0], update_modified=False, + ) + def _delete_bank_placeholders(company, parent_account): """Remove the stock template accounts from AZ CoA once real banks have been @@ -431,6 +464,22 @@ def _delete_bank_placeholders(company, parent_account): frappe.delete_doc( "Account", row.name, ignore_permissions=True, delete_permanently=True ) + except frappe.LinkExistsError: + # Some other doc still references this placeholder (e.g. a Company + # default field we didn't preempt). Frappe.throw queued a popup + # message before raising — clear it so the user doesn't see a + # scary error after a successful setup, then disable the account + # instead of leaving it active in the chart. + frappe.clear_last_message() + try: + frappe.db.set_value( + "Account", row.name, "disabled", 1, update_modified=False + ) + except Exception as exc: + frappe.log_error( + f"Placeholder disable fallback failed: {row.name}: {exc}", + "Jey Wizard materialize (bank placeholder)", + ) except Exception as exc: frappe.log_error( f"Placeholder delete failed: {row.name}: {exc}", diff --git a/jey_wizard/public/js/jey_setup.js b/jey_wizard/public/js/jey_setup.js index 8d5f1aa..c838cf0 100644 --- a/jey_wizard/public/js/jey_setup.js +++ b/jey_wizard/public/js/jey_setup.js @@ -10,7 +10,7 @@ frappe.provide("jey_wizard"); // Bump this string in every commit that changes wizard code. Displayed in the badge so // we can tell at a glance which version is actually running on a given machine. Kept in // sync with __version__ in jey_wizard/__init__.py. -const JEY_WIZARD_VERSION = "0.1.7"; +const JEY_WIZARD_VERSION = "0.1.8"; // Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners // don't try to mutate a wizard that isn't slide-based anymore.