Remove Obligation Pacts from wizard + widen click-to-preview hit area
- Drop obligation_pacts from the Asan-step fetch list, cache doctype, preview endpoint, finalize-time loader/purge, and translations. - v0_1_27 patch cleans up the doctype, its Custom Fields on Company, and the orphan Singles row on existing sites. - Asan/done counters now sit inside full-row anchors with a hover highlight — clicking anywhere on the line opens the preview modal, no more aiming at the digit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b982825c71
commit
55174552c0
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = "0.1.26"
|
||||
__version__ = "0.1.27"
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 ""),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@
|
|||
|
||||
[post_model_sync]
|
||||
# Patches added in this section will be executed after doctypes are migrated
|
||||
jey_wizard.patches.v0_1_27_remove_obligation_pacts
|
||||
|
|
@ -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()
|
||||
|
|
@ -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(`
|
||||
<h3 style="margin-bottom:16px">${__("Loading data from tax portal...")}</h3>
|
||||
<p style="color:#666">${__("Pulling objects, cash registers, POS terminals, bank accounts, obligation pacts and presented certificates. This usually takes 10-30 seconds.")}</p>
|
||||
<p style="color:#666">${__("Pulling objects, cash registers, POS terminals, bank accounts and presented certificates. This usually takes 10-30 seconds.")}</p>
|
||||
<div style="display:flex;align-items:center;gap:12px;margin-top:20px">
|
||||
<div class="jey-spinner" style="width:18px;height:18px;border:3px solid #ddd;border-top-color:#444;border-radius:50%;animation:jey-spin 0.8s linear infinite"></div>
|
||||
<div style="color:#666">${__("Fetching...")}</div>
|
||||
|
|
@ -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 `<li><b>${label}:</b> <span style="color:#c00">${__("failed")}</span> <span style="color:#888;font-size:12px">(${frappe.utils.escape_html(errors[field])})</span></li>`;
|
||||
|
|
@ -296,17 +299,18 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
|||
return `<li><b>${label}:</b> <span style="color:#888">—</span></li>`;
|
||||
}
|
||||
if (n > 0) {
|
||||
return `<li><b>${label}:</b> <a href="#" class="jey-preview-link" data-kind="${kind}" data-title="${frappe.utils.escape_html(label)}">${n}</a> <span style="color:#888;font-size:12px">${__("(click to preview)")}</span></li>`;
|
||||
return `<li style="list-style:none;margin-left:-20px"><a href="#" class="jey-preview-link" data-kind="${kind}" data-title="${frappe.utils.escape_html(label)}" style="${linkStyle}"><b>${label}:</b> ${n} <span style="color:#888;font-size:12px">${__("(click to preview)")}</span></a></li>`;
|
||||
}
|
||||
return `<li><b>${label}:</b> ${n}</li>`;
|
||||
}).join("");
|
||||
|
||||
$body.html(`
|
||||
<style>.jey-preview-link:hover{background:#eef3fb;color:inherit;text-decoration:none}</style>
|
||||
<h3 style="margin-bottom:16px;color:#080">✓ ${__("Authenticated & data loaded")}</h3>
|
||||
<p>${__("Pulled from the tax portal:")}</p>
|
||||
<ul style="line-height:1.8">
|
||||
<li><b>${__("Company")}:</b> <a href="#" class="jey-preview-link" data-kind="profile" data-title="${frappe.utils.escape_html(__("Company profile"))}">${frappe.utils.escape_html(this.data.company_name)}</a> <span style="color:#888;font-size:12px">${__("(click to preview)")}</span></li>
|
||||
<li><b>${__("VÖEN")}:</b> ${frappe.utils.escape_html(this.data.asan_voen)}</li>
|
||||
<ul style="line-height:1.8;list-style:none;padding-left:0">
|
||||
<li><a href="#" class="jey-preview-link" data-kind="profile" data-title="${frappe.utils.escape_html(__("Company profile"))}" style="${linkStyle}"><b>${__("Company")}:</b> ${frappe.utils.escape_html(this.data.company_name)} <span style="color:#888;font-size:12px">${__("(click to preview)")}</span></a></li>
|
||||
<li style="padding:4px 6px"><b>${__("VÖEN")}:</b> ${frappe.utils.escape_html(this.data.asan_voen)}</li>
|
||||
</ul>
|
||||
<div style="margin-top:16px;padding:12px;background:#f7f7f7;border-radius:6px">
|
||||
<div style="font-weight:600;margin-bottom:6px">${__("Loaded datasets")}</div>
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ Company,Şirkət
|
|||
VÖEN,VÖEN
|
||||
"No legal-entity certificates available on this Asan ID. Use a phone/ID linked to a company.","Bu Asan ID üzrə hüquqi şəxs sertifikatı yoxdur. Şirkətə bağlı telefon/ID istifadə edin."
|
||||
Loading data from tax portal...,Vergi portalından məlumat yüklənir...
|
||||
"Pulling objects, cash registers, POS terminals, bank accounts, obligation pacts and presented certificates. This usually takes 10-30 seconds.","Obyektlər, kassa aparatları, POS terminallar, bank hesabları, öhdəlik razılaşmaları və təqdim edilmiş sertifikatlar yüklənir. Adətən 10–30 saniyə çəkir."
|
||||
"Pulling objects, cash registers, POS terminals, bank accounts and presented certificates. This usually takes 10-30 seconds.","Obyektlər, kassa aparatları, POS terminallar, bank hesabları və təqdim edilmiş sertifikatlar yüklənir. Adətən 10–30 saniyə çəkir."
|
||||
Fetching...,Yüklənir...
|
||||
Authenticated & data loaded,"Giriş edildi, məlumat yükləndi"
|
||||
Pulled from the tax portal:,Vergi portalından yükləndi:
|
||||
|
|
@ -39,7 +39,6 @@ Objects,Obyektlər
|
|||
Cash registers,Kassa aparatları
|
||||
POS terminals,POS terminallar
|
||||
Bank accounts,Bank hesabları
|
||||
Obligation pacts,Öhdəlik razılaşmaları
|
||||
Presented certificates,Təqdim edilmiş sertifikatlar
|
||||
failed,uğursuz
|
||||
Cached datasets,Keşlənmiş məlumatlar
|
||||
|
|
|
|||
|
|
|
@ -31,7 +31,7 @@ Company,Компания
|
|||
VÖEN,ВÖЕН
|
||||
"No legal-entity certificates available on this Asan ID. Use a phone/ID linked to a company.","На этом Asan ID нет сертификатов юр. лиц. Используйте телефон/ID привязанный к компании."
|
||||
Loading data from tax portal...,Загрузка данных с налогового портала...
|
||||
"Pulling objects, cash registers, POS terminals, bank accounts, obligation pacts and presented certificates. This usually takes 10-30 seconds.","Загружаем объекты, кассовые аппараты, POS-терминалы, банковские счета, договоры и представленные сертификаты. Обычно занимает 10–30 секунд."
|
||||
"Pulling objects, cash registers, POS terminals, bank accounts and presented certificates. This usually takes 10-30 seconds.","Загружаем объекты, кассовые аппараты, POS-терминалы, банковские счета и представленные сертификаты. Обычно занимает 10–30 секунд."
|
||||
Fetching...,Загрузка...
|
||||
Authenticated & data loaded,"Аутентификация пройдена, данные загружены"
|
||||
Pulled from the tax portal:,Загружено с налогового портала:
|
||||
|
|
@ -39,7 +39,6 @@ Objects,Объекты
|
|||
Cash registers,Кассовые аппараты
|
||||
POS terminals,POS-терминалы
|
||||
Bank accounts,Банковские счета
|
||||
Obligation pacts,Договоры-обязательства
|
||||
Presented certificates,Представленные сертификаты
|
||||
failed,ошибка
|
||||
Cached datasets,Закэшированные данные
|
||||
|
|
|
|||
|
Loading…
Reference in New Issue