From e1ea661855a7d1ee6948bf8e753576672ab932f9 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 12 Jun 2026 12:43:21 +0000 Subject: [PATCH] Hide & exclude inactive e-taxes rows; drop Status column Inactive rows (objects/cash registers/POS with status != A; bank accounts with status = C) are no longer counted, previewed, or kept in the DB. - Single active-status source of truth: _extract_items / _is_active / _active_items, mirroring _purge_inactive_etaxes_records. - fetch_all_etaxes summary counts active rows only (drop _count_items). - _preview_* filter inactive and remove the Status column (4 lists). - Presented certificates (audit records) left untouched. DB side was already covered by the post-load purge; this makes the wizard list/counter consistent with what survives finalize. Bump version 0.1.28 -> 0.1.29. Co-Authored-By: Claude Opus 4.8 (1M context) --- jey_wizard/__init__.py | 2 +- jey_wizard/etaxes.py | 108 ++++++++++++++++-------------- jey_wizard/public/js/jey_setup.js | 2 +- 3 files changed, 58 insertions(+), 54 deletions(-) diff --git a/jey_wizard/__init__.py b/jey_wizard/__init__.py index f7ee773..a5f3762 100644 --- a/jey_wizard/__init__.py +++ b/jey_wizard/__init__.py @@ -1 +1 @@ -__version__ = "0.1.28" +__version__ = "0.1.29" diff --git a/jey_wizard/etaxes.py b/jey_wizard/etaxes.py index b44edb7..50ae80e 100644 --- a/jey_wizard/etaxes.py +++ b/jey_wizard/etaxes.py @@ -98,7 +98,8 @@ def fetch_all_etaxes(): try: data = _fetch_endpoint(method, url, payload, paginated) cache.set(field, json.dumps(data, ensure_ascii=False)) - summary[field] = _count_items(data, paginated) + # Count only active rows so the digit matches the (filtered) preview. + summary[field] = len(_active_items(field, data)) except Exception as exc: errors[field] = str(exc) frappe.log_error( @@ -260,45 +261,81 @@ def _flatten_pages(data, list_key): return [] +# Active-status semantics — single source of truth for counts AND preview. +# Mirrors _purge_inactive_etaxes_records on the materialize side, so what the +# user sees in the wizard list matches what actually survives into the +# E-Taxes doctypes after finalize. Inactive rows are never counted or shown. +_ACTIVE_STATUS = {"A", "ACTIVE"} + + +def _extract_items(field, data): + """Pull the raw item list out of a cached endpoint payload, handling the + paginated list-of-pages vs single-dict shapes.""" + if field == "objects_json": + return (data.get("objectInfoShortList") or data.get("objects") or []) if isinstance(data, dict) else [] + if field == "cash_registers_json": + return _flatten_pages(data, "cashRegisters") + if field == "pos_terminals_json": + return _flatten_pages(data, "posTerminals") + if field == "bank_accounts_json": + if isinstance(data, dict): + return data.get("bankAccounts") or [] + if isinstance(data, list): + return data + return [] + if field == "presented_certs_json": + return (data.get("certificateList") or []) if isinstance(data, dict) else [] + return [] + + +def _is_active(field, item): + """Active-row predicate per endpoint. Presented certificates are audit + records with no active/inactive notion — always kept.""" + if not isinstance(item, dict): + return False + if field == "bank_accounts_json": + # 'C' = closed; anything else (incl. blank) counts as open. + return (item.get("status") or "").strip().upper() != "C" + if field in ("objects_json", "cash_registers_json", "pos_terminals_json"): + return (item.get("status") or "").strip().upper() in _ACTIVE_STATUS + return True + + +def _active_items(field, data): + """Extracted items minus the inactive ones — the list the wizard counts, + previews, and (indirectly) loads.""" + return [it for it in _extract_items(field, data) if _is_active(field, it)] + + def _empty_preview(headers): return {"headers": headers, "rows": []} def _preview_objects(raw): - headers = [_("Code"), _("Name"), _("Status"), _("Address")] + headers = [_("Code"), _("Name"), _("Address")] data = _safe_parse(raw) if data is None: return _empty_preview(headers) - items = [] - if isinstance(data, dict): - items = data.get("objectInfoShortList") or data.get("objects") or [] rows = [] - for obj in items[:PREVIEW_ROW_LIMIT]: - if not isinstance(obj, dict): - continue + for obj in _active_items("objects_json", data)[:PREVIEW_ROW_LIMIT]: rows.append([ obj.get("objectCode") or "", (obj.get("objectName") or "").strip(), - obj.get("status") or "", obj.get("address") or "", ]) return {"headers": headers, "rows": rows} def _preview_cash_registers(raw): - headers = [_("Number"), _("Model"), _("Status"), _("Object"), _("Operator")] + headers = [_("Number"), _("Model"), _("Object"), _("Operator")] data = _safe_parse(raw) if data is None: return _empty_preview(headers) - items = _flatten_pages(data, "cashRegisters") rows = [] - for reg in items[:PREVIEW_ROW_LIMIT]: - if not isinstance(reg, dict): - continue + for reg in _active_items("cash_registers_json", data)[:PREVIEW_ROW_LIMIT]: rows.append([ reg.get("number") or "", reg.get("model") or "", - reg.get("status") or "", reg.get("object") or "", reg.get("operatorName") or "", ]) @@ -306,18 +343,14 @@ def _preview_cash_registers(raw): def _preview_pos_terminals(raw): - headers = [_("Serial number"), _("Status"), _("Registration date"), _("Bank")] + headers = [_("Serial number"), _("Registration date"), _("Bank")] data = _safe_parse(raw) if data is None: return _empty_preview(headers) - items = _flatten_pages(data, "posTerminals") rows = [] - for term in items[:PREVIEW_ROW_LIMIT]: - if not isinstance(term, dict): - continue + for term in _active_items("pos_terminals_json", data)[:PREVIEW_ROW_LIMIT]: rows.append([ term.get("serialNumber") or "", - term.get("status") or "", (term.get("registrationDate") or "")[:10], term.get("bankName") or "", ]) @@ -325,23 +358,15 @@ def _preview_pos_terminals(raw): def _preview_bank_accounts(raw): - headers = [_("IBAN"), _("Currency"), _("Status"), _("Bank")] + headers = [_("IBAN"), _("Currency"), _("Bank")] data = _safe_parse(raw) if data is None: return _empty_preview(headers) - items = [] - if isinstance(data, dict): - items = data.get("bankAccounts") or [] - elif isinstance(data, list): - items = data rows = [] - for acc in items[:PREVIEW_ROW_LIMIT]: - if not isinstance(acc, dict): - continue + for acc in _active_items("bank_accounts_json", data)[:PREVIEW_ROW_LIMIT]: rows.append([ acc.get("number") or "", acc.get("currency") or "", - acc.get("status") or "", acc.get("bankName") or "", ]) return {"headers": headers, "rows": rows} @@ -1364,27 +1389,6 @@ def _auth_headers(): return headers -def _count_items(data, paginated): - """Lightweight count for UI summary. Digs one level deep to find the list.""" - if paginated and isinstance(data, list): - total = 0 - for page in data: - if not isinstance(page, dict): - continue - for value in page.values(): - if isinstance(value, list): - total += len(value) - break - return total - if isinstance(data, dict): - for value in data.values(): - if isinstance(value, list): - return len(value) - if isinstance(data, list): - return len(data) - return 0 - - def _find_default_warehouse(company): """Pick a sensible default warehouse for Stock Settings. ERPNext creates 'Stores' for every new company (is_group=0); under language=az the diff --git a/jey_wizard/public/js/jey_setup.js b/jey_wizard/public/js/jey_setup.js index c2a8ad8..e8d05d9 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.28"; +const JEY_WIZARD_VERSION = "0.1.29"; // 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.