Materialize ERPNext Bank / Bank Account / GL Account in wizard
Keeps invoice_az's loader untouched (it still only fills the read-only E-Taxes Bank Account cache) and does the ERPNext-native side here instead. After materialize_after_setup runs the bank loader, we walk the cache rows linked to the new Company and create a Bank (global, one per unique bank_name), a GL Account under parent "223 Bank hesablaşma hesabları" (account_type=Bank, account_currency from e-taxes, named "<CUR> <IBAN>"), and a Bank Account tying them all together. Closed accounts (status=C) are skipped entirely — cache row still exists. Stock AZ CoA placeholders matching "<CUR> AZXX…" under the bank group are deleted at the end, since nothing references them on a fresh setup and they'd otherwise clutter the chart of accounts alongside the real entries. Per-row failures are logged under "Jey Wizard materialize (bank …)" and never abort the run. Idempotent on re-entry.
This commit is contained in:
parent
3137fc3caf
commit
45e9e54535
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.3"
|
||||
__version__ = "0.1.4"
|
||||
|
|
|
|||
|
|
@ -197,9 +197,156 @@ def materialize_after_setup(args):
|
|||
"Jey Wizard materialize",
|
||||
)
|
||||
|
||||
# invoice_az's bank loader only populates the E-Taxes Bank Account cache doctype.
|
||||
# For the wizard we also want native ERPNext Bank / Bank Account / GL Account so
|
||||
# the user can post transactions on day one, plus we clear out unused CoA
|
||||
# placeholders. Runs off the just-populated cache, not another e-taxes fetch.
|
||||
_materialize_native_banks(company_name)
|
||||
|
||||
_materialize_amas_employees(company_name)
|
||||
|
||||
|
||||
def _materialize_native_banks(company):
|
||||
"""Read E-Taxes Bank Account rows just populated for `company` and create
|
||||
ERPNext-native Bank / GL Account / Bank Account records for each non-closed
|
||||
entry. Idempotent — safe to re-run. Closed accounts (status=C) are ignored.
|
||||
After the loop, unused AZ CoA bank placeholders (names like `<CUR> AZXX…`
|
||||
under account_number=223) are deleted.
|
||||
"""
|
||||
cache_rows = frappe.get_all(
|
||||
"E-Taxes Bank Account",
|
||||
filters={"company": company},
|
||||
fields=[
|
||||
"bank_name",
|
||||
"number",
|
||||
"currency",
|
||||
"status",
|
||||
"account_type",
|
||||
],
|
||||
)
|
||||
if not cache_rows:
|
||||
return
|
||||
|
||||
parent = _find_bank_parent_account(company)
|
||||
if not parent:
|
||||
frappe.log_error(
|
||||
f"No bank parent account found for company '{company}' — skipping native bank materialize",
|
||||
"Jey Wizard materialize",
|
||||
)
|
||||
return
|
||||
|
||||
for row in cache_rows:
|
||||
if (row.get("status") or "").upper() == "C":
|
||||
continue
|
||||
try:
|
||||
_materialize_one_bank(company, parent, row)
|
||||
except Exception as exc:
|
||||
frappe.log_error(
|
||||
f"{row.get('number')}: {exc}\n{traceback.format_exc()}",
|
||||
"Jey Wizard materialize (bank native)",
|
||||
)
|
||||
|
||||
_delete_bank_placeholders(company, parent)
|
||||
|
||||
|
||||
def _find_bank_parent_account(company):
|
||||
"""'Bank hesablaşma hesabları' group (account_number=223) under this company.
|
||||
Falls back to any group with the AZ name prefix."""
|
||||
parent = frappe.db.get_value(
|
||||
"Account",
|
||||
{"company": company, "account_number": "223", "is_group": 1},
|
||||
"name",
|
||||
)
|
||||
if parent:
|
||||
return parent
|
||||
return frappe.db.get_value(
|
||||
"Account",
|
||||
{"company": company, "account_name": ("like", "Bank hesablaşma%"), "is_group": 1},
|
||||
"name",
|
||||
)
|
||||
|
||||
|
||||
def _materialize_one_bank(company, parent_account, row):
|
||||
bank_name = (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("account_type") or "").strip()
|
||||
|
||||
if not bank_name or not iban:
|
||||
return
|
||||
|
||||
# 1. Bank (global, unique on bank_name)
|
||||
if not frappe.db.exists("Bank", bank_name):
|
||||
bank_doc = frappe.get_doc({"doctype": "Bank", "bank_name": bank_name})
|
||||
bank_doc.flags.ignore_permissions = True
|
||||
bank_doc.flags.ignore_if_duplicate = True
|
||||
bank_doc.insert(ignore_permissions=True, ignore_if_duplicate=True)
|
||||
|
||||
# 2. GL Account under parent 223
|
||||
account_name = f"{currency} {iban}"
|
||||
gl_name = frappe.db.get_value(
|
||||
"Account",
|
||||
{"company": company, "account_name": account_name},
|
||||
"name",
|
||||
)
|
||||
if not gl_name:
|
||||
gl_doc = frappe.get_doc({
|
||||
"doctype": "Account",
|
||||
"account_name": account_name,
|
||||
"parent_account": parent_account,
|
||||
"company": company,
|
||||
"account_type": "Bank",
|
||||
"account_currency": currency,
|
||||
"is_group": 0,
|
||||
})
|
||||
gl_doc.insert(ignore_permissions=True)
|
||||
gl_name = gl_doc.name
|
||||
|
||||
# 3. Bank Account (links Bank + GL + Company)
|
||||
ba_exists = frappe.db.exists(
|
||||
"Bank Account",
|
||||
{"bank": bank_name, "account_name": account_name, "company": company},
|
||||
)
|
||||
if not ba_exists:
|
||||
ba_doc = frappe.get_doc({
|
||||
"doctype": "Bank Account",
|
||||
"account_name": account_name,
|
||||
"bank": bank_name,
|
||||
"account": gl_name,
|
||||
"company": company,
|
||||
"is_company_account": 1,
|
||||
"bank_account_no": iban,
|
||||
"iban": iban,
|
||||
"account_type": etx_account_type or None,
|
||||
})
|
||||
ba_doc.insert(ignore_permissions=True)
|
||||
|
||||
|
||||
def _delete_bank_placeholders(company, parent_account):
|
||||
"""Remove the stock 'AZN AZXXX…', 'USD AZXXX…' template accounts from AZ CoA
|
||||
once real banks have been materialised. Fresh-setup only — nothing references
|
||||
these placeholders yet, so deletion is safe. Per-row failures logged.
|
||||
"""
|
||||
placeholders = frappe.get_all(
|
||||
"Account",
|
||||
filters={
|
||||
"company": company,
|
||||
"parent_account": parent_account,
|
||||
"account_name": ("like", "% AZXX%"),
|
||||
"is_group": 0,
|
||||
},
|
||||
pluck="name",
|
||||
)
|
||||
for name in placeholders:
|
||||
try:
|
||||
frappe.delete_doc("Account", name, ignore_permissions=True, delete_permanently=True)
|
||||
except Exception as exc:
|
||||
frappe.log_error(
|
||||
f"Placeholder delete failed: {name}: {exc}",
|
||||
"Jey Wizard materialize (bank placeholder)",
|
||||
)
|
||||
|
||||
|
||||
def _materialize_amas_employees(company_name):
|
||||
"""If the user loaded ƏMAS employees during the wizard, enqueue bulk import now
|
||||
that Company exists. Skipped silently when the cache is empty (i.e. user skipped
|
||||
|
|
|
|||
|
|
@ -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.3";
|
||||
const JEY_WIZARD_VERSION = "0.1.4";
|
||||
|
||||
// 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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue