diff --git a/CLAUDE.md b/CLAUDE.md index a2cdca2..952fc17 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -29,7 +29,7 @@ The UI warns about the second tap on the employees step intro. Do not try to uni Single doctype that carries state between wizard steps and `setup_wizard_complete`: -- `objects_json` / `cash_registers_json` / `pos_terminals_json` / `bank_accounts_json` / `obligation_pacts_json` / `presented_certs_json` — written by `etaxes.py:fetch_all_etaxes` during the Asan step, **not read back** on finalize (see next point). +- `objects_json` / `cash_registers_json` / `pos_terminals_json` / `bank_accounts_json` / `presented_certs_json` — written by `etaxes.py:fetch_all_etaxes` during the Asan step, **not read back** on finalize (see next point). - `amas_selected_employees_json` — written by `amas.py:cache_selected_employees`, read by `etaxes.py:_materialize_amas_employees` in the `setup_wizard_complete` hook. - `last_summary` / `last_error` / `fetched_at` — displayed on the Asan done screen. diff --git a/jey_wizard/__init__.py b/jey_wizard/__init__.py index c8ec146..19492a9 100644 --- a/jey_wizard/__init__.py +++ b/jey_wizard/__init__.py @@ -1 +1 @@ -__version__ = "0.1.26" +__version__ = "0.1.27" diff --git a/jey_wizard/api.py b/jey_wizard/api.py index 9a24179..fe69629 100644 --- a/jey_wizard/api.py +++ b/jey_wizard/api.py @@ -90,7 +90,6 @@ def reset_company_selection(asan_login_name): "cash_registers_json", "pos_terminals_json", "bank_accounts_json", - "obligation_pacts_json", "presented_certs_json", "amas_selected_employees_json", "last_summary", diff --git a/jey_wizard/etaxes.py b/jey_wizard/etaxes.py index f2c23fd..b44edb7 100644 --- a/jey_wizard/etaxes.py +++ b/jey_wizard/etaxes.py @@ -54,13 +54,6 @@ ENDPOINTS = [ None, False, ), - ( - "obligation_pacts_json", - "GET", - f"{BASE}/api/po/edi-legal/public/v1/application/sub-contractor/obl-pact-list", - None, - False, - ), ( "presented_certs_json", "GET", @@ -79,7 +72,6 @@ KIND_TO_FIELD = { "cash_registers": "cash_registers_json", "pos_terminals": "pos_terminals_json", "bank_accounts": "bank_accounts_json", - "obligation_pacts": "obligation_pacts_json", "presented_certs": "presented_certs_json", } @@ -236,7 +228,6 @@ def get_preview_data(): "cash_registers": _preview_cash_registers(cache.cash_registers_json), "pos_terminals": _preview_pos_terminals(cache.pos_terminals_json), "bank_accounts": _preview_bank_accounts(cache.bank_accounts_json), - "obligation_pacts": _preview_obligation_pacts(cache.obligation_pacts_json), "presented_certs": _preview_presented_certs(cache.presented_certs_json), "profile": _preview_profile(cache.company_profile_json), } @@ -356,34 +347,6 @@ def _preview_bank_accounts(raw): return {"headers": headers, "rows": rows} -def _preview_obligation_pacts(raw): - headers = [_("Code"), _("Name"), _("Valid from"), _("Expires")] - data = _safe_parse(raw) - if data is None: - return _empty_preview(headers) - items = [] - if isinstance(data, dict): - items = data.get("oblPacts") or [] - rows = [] - for item in items[:PREVIEW_ROW_LIMIT]: - if not isinstance(item, dict): - continue - pact = item.get("oblPact") or {} - name_blob = pact.get("name") - # name may be {"az": "..."} or a plain string depending on tenant. - if isinstance(name_blob, dict): - name = name_blob.get("az") or name_blob.get("en") or next(iter(name_blob.values()), "") - else: - name = name_blob or "" - rows.append([ - pact.get("code") or "", - name, - (item.get("validityDate") or "")[:10], - (item.get("expireDate") or "")[:10], - ]) - return {"headers": headers, "rows": rows} - - def _preview_presented_certs(raw): headers = [_("Cert №"), _("Category"), _("State"), _("Counterparty"), _("VÖEN"), _("Operation date")] data = _safe_parse(raw) @@ -569,7 +532,6 @@ def materialize_after_setup(args): ("cash_registers", company_api.load_company_cash_registers, "E-Taxes Cash Register"), ("pos_terminals", company_api.load_company_pos_terminals, "E-Taxes POS Terminal"), ("bank_accounts", company_api.load_company_bank_accounts, "E-Taxes Bank Account"), - ("obligation_pacts", company_api.load_company_obligation_pacts, "E-Taxes Obligation Pact"), ("presented_certs", company_api.load_company_presented_certificates, "E-Taxes Presented Certificate"), ] @@ -1453,8 +1415,6 @@ def _purge_inactive_etaxes_records(company): invoice_az.send_sales_api which filters status=='A' before send). - E-Taxes Cash Register: status_code='A' means active. - E-Taxes POS Terminal: status='A' means active. - - E-Taxes Obligation Pact: rows with expire_date in the past are - expired → drop. Presented Certificates carry historical state (cert_state) but are primarily an audit record — we leave them alone. @@ -1462,8 +1422,6 @@ def _purge_inactive_etaxes_records(company): Only deletes rows belonging to the freshly-created Company so prior data on the site stays untouched if anyone re-runs the materialize. """ - from frappe.utils import getdate, today - report = {} def _delete_where(doctype, filters, label): @@ -1516,27 +1474,6 @@ def _purge_inactive_etaxes_records(company): "pos_terminals_inactive", ) - # Expired obligation pacts: expire_date strictly in the past - try: - expired = frappe.get_all( - "E-Taxes Obligation Pact", - filters={"company": company, "expire_date": ("<", today())}, - pluck="name", - ) - deleted = 0 - for name in expired: - try: - frappe.delete_doc("E-Taxes Obligation Pact", name, ignore_permissions=True, delete_permanently=True) - deleted += 1 - except Exception as exc: - frappe.log_error( - f"_purge_inactive_etaxes_records: delete pact/{name}: {exc}", - "Jey Wizard purge inactive", - ) - report["obligation_pacts_expired"] = {"deleted": deleted, "matched": len(expired)} - except Exception as exc: - report["obligation_pacts_expired"] = {"error": str(exc)[:200]} - frappe.db.commit() frappe.log_error( json.dumps(report, ensure_ascii=False, indent=2), @@ -1872,7 +1809,6 @@ def _log_materialize_entry(args): "cash_registers_json_len": len(c.cash_registers_json or ""), "pos_terminals_json_len": len(c.pos_terminals_json or ""), "bank_accounts_json_len": len(c.bank_accounts_json or ""), - "obligation_pacts_json_len": len(c.obligation_pacts_json or ""), "presented_certs_json_len": len(c.presented_certs_json or ""), "amas_selected_employees_json_len": len(c.amas_selected_employees_json or ""), } diff --git a/jey_wizard/jey_wizard/doctype/jey_wizard_etaxes_cache/jey_wizard_etaxes_cache.json b/jey_wizard/jey_wizard/doctype/jey_wizard_etaxes_cache/jey_wizard_etaxes_cache.json index cb1a597..02cf557 100644 --- a/jey_wizard/jey_wizard/doctype/jey_wizard_etaxes_cache/jey_wizard_etaxes_cache.json +++ b/jey_wizard/jey_wizard/doctype/jey_wizard_etaxes_cache/jey_wizard_etaxes_cache.json @@ -14,7 +14,6 @@ "cash_registers_json", "pos_terminals_json", "bank_accounts_json", - "obligation_pacts_json", "presented_certs_json", "company_profile_section", "company_profile_json", @@ -79,13 +78,6 @@ "options": "JSON", "read_only": 1 }, - { - "fieldname": "obligation_pacts_json", - "fieldtype": "Code", - "label": "Obligation Pacts", - "options": "JSON", - "read_only": 1 - }, { "fieldname": "presented_certs_json", "fieldtype": "Code", diff --git a/jey_wizard/patches.txt b/jey_wizard/patches.txt index f15c3a9..8e12950 100644 --- a/jey_wizard/patches.txt +++ b/jey_wizard/patches.txt @@ -3,4 +3,5 @@ # Read docs to understand patches: https://frappeframework.com/docs/v14/user/en/database-migrations [post_model_sync] -# Patches added in this section will be executed after doctypes are migrated \ No newline at end of file +# Patches added in this section will be executed after doctypes are migrated +jey_wizard.patches.v0_1_27_remove_obligation_pacts \ No newline at end of file diff --git a/jey_wizard/patches/v0_1_27_remove_obligation_pacts.py b/jey_wizard/patches/v0_1_27_remove_obligation_pacts.py new file mode 100644 index 0000000..803c10f --- /dev/null +++ b/jey_wizard/patches/v0_1_27_remove_obligation_pacts.py @@ -0,0 +1,56 @@ +"""Drop the E-Taxes Obligation Pact doctype and its leftovers. + +The doctype is gone from invoice_az on disk, so `bench migrate` would leave +the DB rows (table + DocType metadata + Custom Field rows + orphan single +values) behind. This patch cleans those up on existing sites. +""" + +import frappe + + +def execute(): + # 1. Drop the Company Custom Fields that hosted the in-form list. + for fn in ("obligation_pacts_list_section", "obligation_pacts_list_html"): + for name in frappe.get_all( + "Custom Field", + filters={"dt": "Company", "fieldname": fn}, + pluck="name", + ): + try: + frappe.delete_doc( + "Custom Field", name, ignore_permissions=True, delete_permanently=True + ) + except Exception as exc: + frappe.log_error( + f"remove Custom Field {name}: {exc}", + "jey_wizard patch: remove obligation pacts", + ) + + # 2. Drop the doctype itself. delete_doc handles meta + DocField + table. + if frappe.db.exists("DocType", "E-Taxes Obligation Pact"): + try: + frappe.delete_doc( + "DocType", "E-Taxes Obligation Pact", ignore_permissions=True, force=True + ) + except Exception as exc: + frappe.log_error( + f"delete DocType failed, falling back to manual cleanup: {exc}", + "jey_wizard patch: remove obligation pacts", + ) + frappe.db.sql_ddl("DROP TABLE IF EXISTS `tabE-Taxes Obligation Pact`") + frappe.db.delete("DocType", {"name": "E-Taxes Obligation Pact"}) + frappe.db.delete("DocField", {"parent": "E-Taxes Obligation Pact"}) + else: + # DocType row already gone, make sure the table doesn't linger. + frappe.db.sql_ddl("DROP TABLE IF EXISTS `tabE-Taxes Obligation Pact`") + + # 3. Orphan value left in tabSingles after we dropped the field from the + # Jey Wizard Etaxes Cache JSON. Single docs store rows as + # (doctype, field, value) — clear it so frappe.get_single doesn't surface + # the obsolete payload anywhere. + frappe.db.delete( + "Singles", + {"doctype": "Jey Wizard Etaxes Cache", "field": "obligation_pacts_json"}, + ) + + frappe.db.commit() diff --git a/jey_wizard/public/js/jey_setup.js b/jey_wizard/public/js/jey_setup.js index 9b41439..0340a99 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.26"; +const JEY_WIZARD_VERSION = "0.1.27"; // 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. @@ -269,7 +269,7 @@ frappe.setup.SetupWizard = class JeySetupWizard { } else if (this.asan_state === "fetching") { $body.html(`

${__("Loading data from tax portal...")}

-

${__("Pulling objects, cash registers, POS terminals, bank accounts, obligation pacts and presented certificates. This usually takes 10-30 seconds.")}

+

${__("Pulling objects, cash registers, POS terminals, bank accounts and presented certificates. This usually takes 10-30 seconds.")}

${__("Fetching...")}
@@ -284,9 +284,12 @@ frappe.setup.SetupWizard = class JeySetupWizard { ["cash_registers_json", "cash_registers", __("Cash registers")], ["pos_terminals_json", "pos_terminals", __("POS terminals")], ["bank_accounts_json", "bank_accounts", __("Bank accounts")], - ["obligation_pacts_json", "obligation_pacts", __("Obligation pacts")], ["presented_certs_json", "presented_certs", __("Presented certificates")], ]; + // Whole row is the clickable target so users don't have to aim + // at the digit. Anchor strips default underline + color, gets a + // soft hover background. + const linkStyle = "display:block;padding:4px 6px;border-radius:3px;text-decoration:none;color:inherit;cursor:pointer"; const rows = datasets.map(([field, kind, label]) => { if (errors[field]) { return `
  • ${label}: ${__("failed")} (${frappe.utils.escape_html(errors[field])})
  • `; @@ -296,17 +299,18 @@ frappe.setup.SetupWizard = class JeySetupWizard { return `
  • ${label}:
  • `; } if (n > 0) { - return `
  • ${label}: ${n} ${__("(click to preview)")}
  • `; + return `
  • ${label}: ${n} ${__("(click to preview)")}
  • `; } return `
  • ${label}: ${n}
  • `; }).join(""); $body.html(` +

    ✓ ${__("Authenticated & data loaded")}

    ${__("Pulled from the tax portal:")}

    -