e-taxes settings is single doctype now
This commit is contained in:
parent
61ec366149
commit
74bd74b7ba
|
|
@ -75,6 +75,9 @@ def after_install():
|
|||
setup_token_renewal()
|
||||
|
||||
|
||||
before_migrate = ["invoice_az.migrate_utils.backup_etaxes_settings"]
|
||||
|
||||
|
||||
def after_migrate():
|
||||
"""Run migration tasks"""
|
||||
from invoice_az.auth import setup_token_renewal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
"""
|
||||
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.
|
||||
|
||||
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.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
import frappe
|
||||
|
||||
BACKUP_FILENAME = "etaxes_settings_migration.json"
|
||||
|
||||
SCALAR_FIELDS = [
|
||||
"similarity_threshold",
|
||||
"consider_azeri_chars",
|
||||
"default_item_group",
|
||||
"default_uom",
|
||||
"default_item_tax_template",
|
||||
"default_supplier_group",
|
||||
"default_customer_group",
|
||||
"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",
|
||||
]
|
||||
|
||||
|
||||
def _backup_path():
|
||||
return frappe.get_site_path("private", BACKUP_FILENAME)
|
||||
|
||||
|
||||
def backup_etaxes_settings():
|
||||
"""
|
||||
Called before_migrate.
|
||||
Dumps the active E-Taxes Settings record (scalar fields + child rows) to a JSON file.
|
||||
"""
|
||||
if not frappe.db.table_exists("tabE-Taxes Settings"):
|
||||
return
|
||||
|
||||
# Find the best record — ORM still works normally here
|
||||
rows = frappe.db.sql(
|
||||
"""
|
||||
SELECT * FROM `tabE-Taxes Settings`
|
||||
WHERE name != 'E-Taxes Settings'
|
||||
ORDER BY is_default DESC, is_active DESC, modified DESC
|
||||
LIMIT 1
|
||||
""",
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
if not rows:
|
||||
return
|
||||
|
||||
old_row = rows[0]
|
||||
old_name = old_row["name"]
|
||||
|
||||
backup = {
|
||||
"old_name": old_name,
|
||||
"scalar": {f: old_row.get(f) for f in SCALAR_FIELDS},
|
||||
"children": {},
|
||||
}
|
||||
|
||||
for table in CHILD_TABLES:
|
||||
if frappe.db.table_exists(table):
|
||||
child_rows = frappe.db.sql(
|
||||
f"SELECT * FROM `{table}` WHERE parent = %s ORDER BY idx",
|
||||
(old_name,),
|
||||
as_dict=True,
|
||||
)
|
||||
backup["children"][table] = [dict(r) for r in child_rows]
|
||||
|
||||
with open(_backup_path(), "w", encoding="utf-8") as f:
|
||||
json.dump(backup, f, default=str, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
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.
|
||||
"""
|
||||
path = _backup_path()
|
||||
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
|
||||
with open(path, encoding="utf-8") as f:
|
||||
backup = json.load(f)
|
||||
|
||||
# Write scalar fields into tabSingles
|
||||
for field, value in backup.get("scalar", {}).items():
|
||||
if value is None:
|
||||
continue
|
||||
frappe.db.sql(
|
||||
"""
|
||||
INSERT INTO `tabSingles` (doctype, field, value)
|
||||
VALUES ('E-Taxes Settings', %s, %s)
|
||||
ON DUPLICATE KEY UPDATE value = VALUES(value)
|
||||
""",
|
||||
(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,),
|
||||
)
|
||||
|
||||
frappe.db.commit()
|
||||
frappe.clear_cache(doctype="E-Taxes Settings")
|
||||
|
||||
# Clean up — file is no longer needed
|
||||
os.remove(path)
|
||||
|
|
@ -1,92 +1,18 @@
|
|||
"""
|
||||
Migrate E-Taxes Settings from multi-record to Single doctype.
|
||||
|
||||
IMPORTANT: patches run after schema sync, so Frappe's ORM already treats
|
||||
E-Taxes Settings as a Single. All reads from the old table use raw SQL.
|
||||
Data is backed up to a JSON file by the before_migrate hook
|
||||
(invoice_az.migrate_utils.backup_etaxes_settings) which runs before schema
|
||||
changes — at that point the ORM still works normally.
|
||||
|
||||
This patch runs after schema sync (when the doctype is already Single)
|
||||
and restores the data from the backup file via raw SQL.
|
||||
"""
|
||||
|
||||
import frappe
|
||||
|
||||
|
||||
SCALAR_FIELDS = [
|
||||
"similarity_threshold",
|
||||
"consider_azeri_chars",
|
||||
"default_item_group",
|
||||
"default_uom",
|
||||
"default_item_tax_template",
|
||||
"default_supplier_group",
|
||||
"default_customer_group",
|
||||
"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",
|
||||
]
|
||||
|
||||
|
||||
def execute():
|
||||
if not frappe.db.table_exists("tabE-Taxes Settings"):
|
||||
return
|
||||
from invoice_az.migrate_utils import restore_etaxes_settings
|
||||
|
||||
# Find the best old record via raw SQL.
|
||||
# Frappe ORM treats the doctype as Single by now, so we must bypass it.
|
||||
# Prefer is_default=1, then is_active=1, then any record with a non-standard name.
|
||||
# Wrap each attempt in try/except in case old columns were already dropped.
|
||||
old_row = None
|
||||
|
||||
for query in [
|
||||
"SELECT * FROM `tabE-Taxes Settings` WHERE `is_default` = 1 LIMIT 1",
|
||||
"SELECT * FROM `tabE-Taxes Settings` WHERE `is_active` = 1 LIMIT 1",
|
||||
"SELECT * FROM `tabE-Taxes Settings` WHERE `name` != 'E-Taxes Settings' LIMIT 1",
|
||||
]:
|
||||
try:
|
||||
old_row = _raw_get(query)
|
||||
except Exception:
|
||||
pass
|
||||
if old_row:
|
||||
break
|
||||
|
||||
if not old_row:
|
||||
return # Fresh install or already migrated
|
||||
|
||||
old_name = old_row.get("name")
|
||||
|
||||
# Write scalar fields into tabSingles via raw SQL
|
||||
for field in SCALAR_FIELDS:
|
||||
value = old_row.get(field)
|
||||
if value is None:
|
||||
continue
|
||||
frappe.db.sql(
|
||||
"""
|
||||
INSERT INTO `tabSingles` (doctype, field, value)
|
||||
VALUES ('E-Taxes Settings', %s, %s)
|
||||
ON DUPLICATE KEY UPDATE value = VALUES(value)
|
||||
""",
|
||||
(field, str(value)),
|
||||
)
|
||||
|
||||
# Re-parent child table rows from old name → "E-Taxes Settings"
|
||||
for table in CHILD_TABLES:
|
||||
if not frappe.db.table_exists(table):
|
||||
continue
|
||||
frappe.db.sql(
|
||||
f"""
|
||||
UPDATE `{table}`
|
||||
SET parent = 'E-Taxes Settings',
|
||||
parenttype = 'E-Taxes Settings'
|
||||
WHERE parent = %s
|
||||
""",
|
||||
(old_name,),
|
||||
)
|
||||
|
||||
frappe.db.commit()
|
||||
frappe.clear_cache(doctype="E-Taxes Settings")
|
||||
|
||||
|
||||
def _raw_get(query):
|
||||
rows = frappe.db.sql(query, as_dict=True)
|
||||
return rows[0] if rows else None
|
||||
restore_etaxes_settings()
|
||||
|
|
|
|||
Loading…
Reference in New Issue