Trace materialize_after_setup decision points to Error Log
Adds seven 'Jey Wizard trace: ...' breadcrumbs (all using frappe.log_error so they show up in the same place actual failures already do, with a distinct title prefix to filter them out from real errors): - fetch_all_etaxes done — confirms the Asan-step fetch ran, with summary and per-endpoint errors - materialize start — args, Company existence, default Asan Login auth state, full cache snapshot - loaders done — per-loader before/after E-Taxes row counts (or error) - bank native done — input rows from cache, materialised count, parent - amas skipped / amas enqueued — which branch ran and why Used to diagnose 'no doctypes created after setup' on a remote test machine where I can't reproduce locally.
This commit is contained in:
parent
3812a06c3c
commit
322aa211b0
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.1.6"
|
__version__ = "0.1.7"
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,13 @@ def fetch_all_etaxes():
|
||||||
cache.save()
|
cache.save()
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
|
|
||||||
|
# Diagnostic breadcrumb so we can confirm from Error Log alone that the Asan-step
|
||||||
|
# fetch ran and what it produced (counts per endpoint, per-endpoint errors).
|
||||||
|
frappe.log_error(
|
||||||
|
json.dumps({"summary": summary, "errors": errors}, ensure_ascii=False, indent=2),
|
||||||
|
"Jey Wizard trace: fetch_all_etaxes done",
|
||||||
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ok": True,
|
"ok": True,
|
||||||
"summary": summary,
|
"summary": summary,
|
||||||
|
|
@ -153,6 +160,15 @@ def materialize_after_setup(args):
|
||||||
call invoice_az's loaders to persist everything into E-Taxes DocTypes with the
|
call invoice_az's loaders to persist everything into E-Taxes DocTypes with the
|
||||||
real Company link. Best-effort: per-loader failures are logged, not raised.
|
real Company link. Best-effort: per-loader failures are logged, not raised.
|
||||||
"""
|
"""
|
||||||
|
# Single trace at entry: confirms the hook fires and dumps every input the rest
|
||||||
|
# of materialize depends on (args, Company existence, Asan auth state, cache
|
||||||
|
# state). Without this we can't tell from logs alone whether materialize even ran.
|
||||||
|
try:
|
||||||
|
_log_materialize_entry(args)
|
||||||
|
except Exception:
|
||||||
|
# Diagnostic must never break the actual hook.
|
||||||
|
pass
|
||||||
|
|
||||||
company_name = (args or {}).get("company_name")
|
company_name = (args or {}).get("company_name")
|
||||||
if not company_name:
|
if not company_name:
|
||||||
frappe.log_error(
|
frappe.log_error(
|
||||||
|
|
@ -198,25 +214,37 @@ def materialize_after_setup(args):
|
||||||
|
|
||||||
from invoice_az import company_api
|
from invoice_az import company_api
|
||||||
|
|
||||||
|
# (kind, loader, doctype-with-company-link). Doctype is used purely to
|
||||||
|
# count rows before/after each loader as a diagnostic breadcrumb.
|
||||||
loaders = [
|
loaders = [
|
||||||
("objects", company_api.load_company_objects),
|
("objects", company_api.load_company_objects, "E-Taxes Object"),
|
||||||
("cash_registers", company_api.load_company_cash_registers),
|
("cash_registers", company_api.load_company_cash_registers, "E-Taxes Cash Register"),
|
||||||
("pos_terminals", company_api.load_company_pos_terminals),
|
("pos_terminals", company_api.load_company_pos_terminals, "E-Taxes POS Terminal"),
|
||||||
("bank_accounts", company_api.load_company_bank_accounts),
|
("bank_accounts", company_api.load_company_bank_accounts, "E-Taxes Bank Account"),
|
||||||
("obligation_pacts", company_api.load_company_obligation_pacts),
|
("obligation_pacts", company_api.load_company_obligation_pacts, "E-Taxes Obligation Pact"),
|
||||||
("presented_certs", company_api.load_company_presented_certificates),
|
("presented_certs", company_api.load_company_presented_certificates, "E-Taxes Presented Certificate"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for name, loader in loaders:
|
loader_trace = {}
|
||||||
|
for name, loader, doctype in loaders:
|
||||||
|
before = _safe_count(doctype, company_name)
|
||||||
try:
|
try:
|
||||||
loader(company_name)
|
loader(company_name)
|
||||||
|
after = _safe_count(doctype, company_name)
|
||||||
|
loader_trace[name] = {"before": before, "after": after, "delta": (after - before) if (before is not None and after is not None) else None}
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
loader_trace[name] = {"before": before, "error": str(exc)[:200]}
|
||||||
frappe.log_error(
|
frappe.log_error(
|
||||||
f"materialize_after_setup: {name} loader failed for {company_name}: {exc}\n"
|
f"materialize_after_setup: {name} loader failed for {company_name}: {exc}\n"
|
||||||
f"{traceback.format_exc()}",
|
f"{traceback.format_exc()}",
|
||||||
"Jey Wizard materialize",
|
"Jey Wizard materialize",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
frappe.log_error(
|
||||||
|
json.dumps(loader_trace, ensure_ascii=False, indent=2),
|
||||||
|
"Jey Wizard trace: loaders done",
|
||||||
|
)
|
||||||
|
|
||||||
# invoice_az's bank loader only populates the E-Taxes Bank Account cache doctype.
|
# 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
|
# 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
|
# the user can post transactions on day one, plus we clear out unused CoA
|
||||||
|
|
@ -290,10 +318,12 @@ def _materialize_native_banks(company):
|
||||||
|
|
||||||
_delete_bank_placeholders(company, parent)
|
_delete_bank_placeholders(company, parent)
|
||||||
frappe.db.commit()
|
frappe.db.commit()
|
||||||
# Success log is loud on purpose — makes it easy to verify the hook ran end-to-end.
|
# Success breadcrumb in Error Log so we can verify end-to-end run from the same
|
||||||
frappe.logger().info(
|
# place where loader/cache traces live.
|
||||||
f"materialize_native_banks: company={company} materialised={created} "
|
frappe.log_error(
|
||||||
f"skipped_closed={skipped_closed} parent={parent}"
|
f"company={company} materialised={created} skipped_closed={skipped_closed} "
|
||||||
|
f"input_rows={len(accounts)} parent={parent}",
|
||||||
|
"Jey Wizard trace: bank native done",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -415,6 +445,10 @@ def _materialize_amas_employees(company_name):
|
||||||
cache = frappe.get_single("Jey Wizard Etaxes Cache")
|
cache = frappe.get_single("Jey Wizard Etaxes Cache")
|
||||||
raw = (cache.amas_selected_employees_json or "").strip()
|
raw = (cache.amas_selected_employees_json or "").strip()
|
||||||
if not raw:
|
if not raw:
|
||||||
|
frappe.log_error(
|
||||||
|
f"company={company_name} reason=amas_cache_empty (user skipped AMAS step or fetch never ran)",
|
||||||
|
"Jey Wizard trace: amas skipped",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -428,6 +462,10 @@ def _materialize_amas_employees(company_name):
|
||||||
|
|
||||||
employees = payload.get("employees") or []
|
employees = payload.get("employees") or []
|
||||||
if not employees:
|
if not employees:
|
||||||
|
frappe.log_error(
|
||||||
|
f"company={company_name} reason=amas_payload_empty employees=0",
|
||||||
|
"Jey Wizard trace: amas skipped",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
create_designation = payload.get("create_designation", 0)
|
create_designation = payload.get("create_designation", 0)
|
||||||
|
|
@ -449,6 +487,10 @@ def _materialize_amas_employees(company_name):
|
||||||
company=company_name,
|
company=company_name,
|
||||||
create_designation=create_designation,
|
create_designation=create_designation,
|
||||||
)
|
)
|
||||||
|
frappe.log_error(
|
||||||
|
f"company={company_name} asan_login={asan_login} employees={len(employees)} create_designation={create_designation}",
|
||||||
|
"Jey Wizard trace: amas enqueued",
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
frappe.log_error(
|
frappe.log_error(
|
||||||
f"materialize_after_setup: amas import enqueue failed: {exc}\n{traceback.format_exc()}",
|
f"materialize_after_setup: amas import enqueue failed: {exc}\n{traceback.format_exc()}",
|
||||||
|
|
@ -525,3 +567,71 @@ def _count_items(data, paginated):
|
||||||
def _only_admin():
|
def _only_admin():
|
||||||
if frappe.session.user != "Administrator":
|
if frappe.session.user != "Administrator":
|
||||||
frappe.throw(_("Only Administrator may run setup"), frappe.PermissionError)
|
frappe.throw(_("Only Administrator may run setup"), frappe.PermissionError)
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_count(doctype, company):
|
||||||
|
"""Count rows in `doctype` filtered by company. Returns None on any failure
|
||||||
|
(missing doctype, missing company field, db error) — used purely for trace
|
||||||
|
breadcrumbs, must never throw.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not frappe.db.exists("DocType", doctype):
|
||||||
|
return None
|
||||||
|
return frappe.db.count(doctype, {"company": company})
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
return frappe.db.count(doctype)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _log_materialize_entry(args):
|
||||||
|
"""Dump everything materialize_after_setup decides on at entry: input args,
|
||||||
|
Company existence, default Asan Login auth state, cache freshness/sizes.
|
||||||
|
"""
|
||||||
|
company_name = (args or {}).get("company_name")
|
||||||
|
asan = frappe.db.get_value(
|
||||||
|
"Asan Login",
|
||||||
|
{"is_default": 1},
|
||||||
|
["name", "auth_status", "main_token", "bearer_token"],
|
||||||
|
as_dict=True,
|
||||||
|
)
|
||||||
|
cache_present = frappe.db.exists("DocType", "Jey Wizard Etaxes Cache")
|
||||||
|
cache_info = {}
|
||||||
|
if cache_present:
|
||||||
|
try:
|
||||||
|
c = frappe.get_single("Jey Wizard Etaxes Cache")
|
||||||
|
cache_info = {
|
||||||
|
"fetched_at": str(c.fetched_at) if c.fetched_at else None,
|
||||||
|
"last_summary": c.last_summary,
|
||||||
|
"last_error": c.last_error,
|
||||||
|
"objects_json_len": len(c.objects_json or ""),
|
||||||
|
"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 ""),
|
||||||
|
}
|
||||||
|
except Exception as exc:
|
||||||
|
cache_info = {"_load_error": str(exc)[:200]}
|
||||||
|
|
||||||
|
trace = {
|
||||||
|
"args_keys": sorted(list((args or {}).keys())),
|
||||||
|
"company_name": company_name,
|
||||||
|
"company_exists": bool(company_name and frappe.db.exists("Company", company_name)),
|
||||||
|
"valuation_method": (args or {}).get("valuation_method"),
|
||||||
|
"chart_of_accounts": (args or {}).get("chart_of_accounts"),
|
||||||
|
"country": (args or {}).get("country"),
|
||||||
|
"currency": (args or {}).get("currency"),
|
||||||
|
"asan_default_login": asan.name if asan else None,
|
||||||
|
"asan_auth_status": asan.auth_status if asan else None,
|
||||||
|
"asan_has_main_token": bool(asan and asan.main_token),
|
||||||
|
"asan_has_bearer_token": bool(asan and asan.bearer_token),
|
||||||
|
"cache_doctype_exists": bool(cache_present),
|
||||||
|
"cache": cache_info,
|
||||||
|
}
|
||||||
|
frappe.log_error(
|
||||||
|
json.dumps(trace, ensure_ascii=False, indent=2),
|
||||||
|
"Jey Wizard trace: materialize start",
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ frappe.provide("jey_wizard");
|
||||||
// Bump this string in every commit that changes wizard code. Displayed in the badge so
|
// 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
|
// 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.
|
// sync with __version__ in jey_wizard/__init__.py.
|
||||||
const JEY_WIZARD_VERSION = "0.1.6";
|
const JEY_WIZARD_VERSION = "0.1.7";
|
||||||
|
|
||||||
// Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners
|
// 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.
|
// don't try to mutate a wizard that isn't slide-based anymore.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue