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()
|
setup_token_renewal()
|
||||||
|
|
||||||
|
|
||||||
|
before_migrate = ["invoice_az.migrate_utils.backup_etaxes_settings"]
|
||||||
|
|
||||||
|
|
||||||
def after_migrate():
|
def after_migrate():
|
||||||
"""Run migration tasks"""
|
"""Run migration tasks"""
|
||||||
from invoice_az.auth import setup_token_renewal
|
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.
|
Migrate E-Taxes Settings from multi-record to Single doctype.
|
||||||
|
|
||||||
IMPORTANT: patches run after schema sync, so Frappe's ORM already treats
|
Data is backed up to a JSON file by the before_migrate hook
|
||||||
E-Taxes Settings as a Single. All reads from the old table use raw SQL.
|
(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
|
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():
|
def execute():
|
||||||
if not frappe.db.table_exists("tabE-Taxes Settings"):
|
from invoice_az.migrate_utils import restore_etaxes_settings
|
||||||
return
|
|
||||||
|
|
||||||
# Find the best old record via raw SQL.
|
restore_etaxes_settings()
|
||||||
# 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
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue