From 0b46271628592c996bb1e77b8266ae4ef0a26057 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Tue, 3 Mar 2026 16:52:15 +0400 Subject: [PATCH] e-taxes settings is single doctype now --- invoice_az/migrate_utils.py | 69 ++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/invoice_az/migrate_utils.py b/invoice_az/migrate_utils.py index 89b4d88..d3db114 100644 --- a/invoice_az/migrate_utils.py +++ b/invoice_az/migrate_utils.py @@ -2,10 +2,10 @@ Migration utilities for E-Taxes Settings → Single doctype conversion. backup_etaxes_settings() is called by the before_migrate hook — at that point -the doctype is still a regular doctype, so frappe.db works normally. +the doctype is still a regular doctype and ORM works normally. restore_etaxes_settings() is called by the patch — at that point the doctype -is already Single, so we read from the backup file and write via raw SQL. +is already Single, so we use raw SQL and restore everything from the backup file. """ import json @@ -26,13 +26,14 @@ SCALAR_FIELDS = [ "default_payment_terms", ] -CHILD_TABLES = [ - "tabE-Taxes Item Mapping", - "tabE-Taxes Customer Mappings", - "tabE-Taxes Supplier Mappings", - "tabE-Taxes Unit Mapping", - "tabE-Taxes VAT Account Mapping", -] +# SQL table name → parentfield name in E-Taxes Settings +CHILD_TABLES = { + "tabE-Taxes Item Mapping": "item_mappings", + "tabE-Taxes Customer Mappings": "customer_mappings", + "tabE-Taxes Supplier Mappings": "supplier_mappings", + "tabE-Taxes Unit Mapping": "unit_mappings", + "tabE-Taxes VAT Account Mapping": "vat_account_mappings", +} def _backup_path(): @@ -41,14 +42,13 @@ def _backup_path(): def backup_etaxes_settings(): """ - Called before_migrate. - Dumps the active E-Taxes Settings record (scalar fields + child rows) to a JSON file. + Called before_migrate (before schema sync). + Dumps scalar fields + all child table rows to a JSON file. """ if not frappe.db.table_exists("tabE-Taxes Settings"): return - # Find the best record using raw SQL — ORM still works normally here, - # but we avoid referencing is_default/is_active which may have been dropped. + # Find the best old record — ORM still works normally here rows = None for query in [ "SELECT * FROM `tabE-Taxes Settings` WHERE name != 'E-Taxes Settings' ORDER BY modified DESC LIMIT 1", @@ -73,6 +73,7 @@ def backup_etaxes_settings(): "children": {}, } + # Save ALL columns of each child table row so we can re-insert them if needed for table in CHILD_TABLES: if frappe.db.table_exists(table): child_rows = frappe.db.sql( @@ -89,8 +90,8 @@ def backup_etaxes_settings(): def restore_etaxes_settings(): """ Called from the migration patch (after schema sync). - Reads the backup file, writes scalar fields into tabSingles, - re-parents child rows, then deletes the file. + Reads backup file → writes scalar fields to tabSingles → + deletes + re-inserts child table rows → deletes the file. """ path = _backup_path() @@ -100,7 +101,7 @@ def restore_etaxes_settings(): with open(path, encoding="utf-8") as f: backup = json.load(f) - # Write scalar fields into tabSingles + # --- Scalar fields → tabSingles --- for field, value in backup.get("scalar", {}).items(): if value is None: continue @@ -113,23 +114,29 @@ def restore_etaxes_settings(): (field, str(value)), ) - # Re-parent child rows - old_name = backup.get("old_name") - if old_name: - for table in CHILD_TABLES: - if frappe.db.table_exists(table): - frappe.db.sql( - f""" - UPDATE `{table}` - SET parent = 'E-Taxes Settings', - parenttype = 'E-Taxes Settings' - WHERE parent = %s - """, - (old_name,), - ) + # --- Child tables: delete existing rows, then re-insert from backup --- + for table, rows in backup.get("children", {}).items(): + if not frappe.db.table_exists(table) or not rows: + continue + + # Remove any rows already parented to the Single (e.g., from a broken previous run) + frappe.db.sql( + f"DELETE FROM `{table}` WHERE parent = 'E-Taxes Settings'" + ) + + for row in rows: + row["parent"] = "E-Taxes Settings" + row["parenttype"] = "E-Taxes Settings" + + columns = ", ".join(f"`{col}`" for col in row) + placeholders = ", ".join(["%s"] * len(row)) + + frappe.db.sql( + f"INSERT INTO `{table}` ({columns}) VALUES ({placeholders})", + list(row.values()), + ) frappe.db.commit() frappe.clear_cache(doctype="E-Taxes Settings") - # Clean up — file is no longer needed os.remove(path)