e-taxes settings is single doctype now
This commit is contained in:
parent
331aabe1d7
commit
2ba3a97227
|
|
@ -12,17 +12,17 @@ frappe.ui.form.on('E-Taxes Settings', {
|
|||
},
|
||||
|
||||
refresh: function(frm) {
|
||||
frm.add_custom_button(__('Restore from old data'), function() {
|
||||
frm.add_custom_button(__('Restore from file'), function() {
|
||||
frappe.confirm(
|
||||
__('This will restore all settings and mappings from the pre-migration database record. Continue?'),
|
||||
__('Restore all settings and mappings from backup file? Current data will be overwritten.'),
|
||||
function() {
|
||||
frappe.call({
|
||||
method: 'invoice_az.migrate_utils.restore_etaxes_settings_from_old_table',
|
||||
method: 'invoice_az.migrate_utils.restore_etaxes_from_file',
|
||||
freeze: true,
|
||||
freeze_message: __('Restoring...'),
|
||||
callback: function(r) {
|
||||
if (r.message && r.message.success) {
|
||||
frappe.show_alert({ message: __(r.message.message), indicator: 'green' }, 5);
|
||||
frappe.show_alert({ message: r.message.message, indicator: 'green' }, 5);
|
||||
frm.reload_doc();
|
||||
} else {
|
||||
frappe.msgprint({
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"""
|
||||
Migration utilities for E-Taxes Settings → Single doctype.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
||||
import frappe
|
||||
|
||||
BACKUP_FILENAME = "etaxes_settings_backup.json"
|
||||
|
||||
SCALAR_FIELDS = [
|
||||
"similarity_threshold",
|
||||
"consider_azeri_chars",
|
||||
|
|
@ -15,47 +16,80 @@ 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",
|
||||
]
|
||||
CHILD_TABLES = {
|
||||
"item_mappings": "tabE-Taxes Item Mapping",
|
||||
"customer_mappings": "tabE-Taxes Customer Mappings",
|
||||
"supplier_mappings": "tabE-Taxes Supplier Mappings",
|
||||
"unit_mappings": "tabE-Taxes Unit Mapping",
|
||||
"vat_account_mappings": "tabE-Taxes VAT Account Mapping",
|
||||
}
|
||||
|
||||
|
||||
def _backup_path():
|
||||
return frappe.get_site_path("private", BACKUP_FILENAME)
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def restore_etaxes_settings_from_old_table():
|
||||
def export_etaxes_to_file():
|
||||
"""
|
||||
Called from the E-Taxes Settings form button.
|
||||
Reads data from the old tabE-Taxes Settings (still exists after migration)
|
||||
and populates the current Single doctype.
|
||||
Run BEFORE bench migrate:
|
||||
bench --site <site> execute invoice_az.migrate_utils.export_etaxes_to_file
|
||||
Saves all E-Taxes Settings data to site/private/etaxes_settings_backup.json
|
||||
"""
|
||||
if not frappe.db.table_exists("tabE-Taxes Settings"):
|
||||
return {"success": False, "message": "Old table not found"}
|
||||
print("ERROR: tabE-Taxes Settings not found")
|
||||
return
|
||||
|
||||
rows = frappe.db.sql("SELECT * FROM `tabE-Taxes Settings` LIMIT 1", as_dict=True)
|
||||
if not rows:
|
||||
print("ERROR: no records in tabE-Taxes Settings")
|
||||
return
|
||||
|
||||
# Get the old record
|
||||
old_row = None
|
||||
for query in [
|
||||
"SELECT * FROM `tabE-Taxes Settings` WHERE name != 'E-Taxes Settings' LIMIT 1",
|
||||
"SELECT * FROM `tabE-Taxes Settings` LIMIT 1",
|
||||
]:
|
||||
try:
|
||||
rows = frappe.db.sql(query, as_dict=True)
|
||||
if rows:
|
||||
old_row = rows[0]
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
old_name = old_row["name"]
|
||||
|
||||
if not old_row:
|
||||
return {"success": False, "message": "No old settings record found in database"}
|
||||
backup = {
|
||||
"old_name": old_name,
|
||||
"scalar": {},
|
||||
"children": {},
|
||||
}
|
||||
|
||||
old_name = old_row.get("name")
|
||||
|
||||
# Write scalar fields to tabSingles
|
||||
for field in SCALAR_FIELDS:
|
||||
value = old_row.get(field)
|
||||
backup["scalar"][field] = old_row.get(field)
|
||||
|
||||
for fieldname, table in CHILD_TABLES.items():
|
||||
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"][fieldname] = [dict(r) for r in child_rows]
|
||||
|
||||
path = _backup_path()
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(backup, f, default=str, ensure_ascii=False, indent=2)
|
||||
|
||||
total_children = sum(len(v) for v in backup["children"].values())
|
||||
print(f"Saved to: {path}")
|
||||
print(f"Record: '{old_name}'")
|
||||
print(f"Child rows: {total_children}")
|
||||
return path
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def restore_etaxes_from_file():
|
||||
"""Called from the E-Taxes Settings form button."""
|
||||
path = _backup_path()
|
||||
|
||||
if not os.path.exists(path):
|
||||
return {"success": False, "message": f"Backup file not found: {path}"}
|
||||
|
||||
with open(path, encoding="utf-8") as f:
|
||||
backup = json.load(f)
|
||||
|
||||
# Scalar fields → tabSingles
|
||||
for field, value in backup.get("scalar", {}).items():
|
||||
if value is None:
|
||||
continue
|
||||
frappe.db.sql(
|
||||
|
|
@ -67,26 +101,15 @@ def restore_etaxes_settings_from_old_table():
|
|||
(field, str(value)),
|
||||
)
|
||||
|
||||
# Restore child table rows
|
||||
restored_children = {}
|
||||
for table in CHILD_TABLES:
|
||||
if not frappe.db.table_exists(table):
|
||||
continue
|
||||
try:
|
||||
child_rows = frappe.db.sql(
|
||||
f"SELECT * FROM `{table}` WHERE parent = %s ORDER BY idx",
|
||||
(old_name,),
|
||||
as_dict=True,
|
||||
)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not child_rows:
|
||||
# Child tables → DELETE existing + INSERT from backup
|
||||
for fieldname, rows in backup.get("children", {}).items():
|
||||
table = CHILD_TABLES.get(fieldname)
|
||||
if not table or not frappe.db.table_exists(table) or not rows:
|
||||
continue
|
||||
|
||||
frappe.db.sql(f"DELETE FROM `{table}` WHERE parent = 'E-Taxes Settings'")
|
||||
|
||||
for row in child_rows:
|
||||
for row in rows:
|
||||
row["parent"] = "E-Taxes Settings"
|
||||
row["parenttype"] = "E-Taxes Settings"
|
||||
columns = ", ".join(f"`{col}`" for col in row)
|
||||
|
|
@ -99,100 +122,16 @@ def restore_etaxes_settings_from_old_table():
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
restored_children[table] = len(child_rows)
|
||||
|
||||
frappe.db.commit()
|
||||
frappe.clear_cache(doctype="E-Taxes Settings")
|
||||
|
||||
total = sum(len(v) for v in backup.get("children", {}).values())
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Restored from record '{old_name}'",
|
||||
"children": restored_children,
|
||||
"message": f"Restored from '{backup.get('old_name')}' — {total} child rows",
|
||||
}
|
||||
|
||||
|
||||
def migrate_etaxes_settings_to_single():
|
||||
"""
|
||||
Called from after_migrate hook.
|
||||
Reads the old tabE-Taxes Settings (Frappe never drops old tables during sync)
|
||||
and writes scalar fields to tabSingles + re-parents child table rows.
|
||||
Safe to call multiple times — skips if tabSingles already has data.
|
||||
"""
|
||||
# Skip if already migrated
|
||||
already_migrated = frappe.db.sql(
|
||||
"SELECT COUNT(*) as cnt FROM `tabSingles` WHERE doctype = 'E-Taxes Settings'",
|
||||
as_dict=True,
|
||||
)
|
||||
if already_migrated and already_migrated[0].get("cnt", 0) > 0:
|
||||
return
|
||||
|
||||
# Old table must exist
|
||||
if not frappe.db.table_exists("tabE-Taxes Settings"):
|
||||
return
|
||||
|
||||
# Get the old record — try any row (old name could even be "E-Taxes Settings")
|
||||
old_row = None
|
||||
for query in [
|
||||
"SELECT * FROM `tabE-Taxes Settings` WHERE name != 'E-Taxes Settings' LIMIT 1",
|
||||
"SELECT * FROM `tabE-Taxes Settings` LIMIT 1",
|
||||
]:
|
||||
try:
|
||||
rows = frappe.db.sql(query, as_dict=True)
|
||||
if rows:
|
||||
old_row = rows[0]
|
||||
break
|
||||
except Exception:
|
||||
"""Called from after_migrate hook — no-op if old table is gone."""
|
||||
pass
|
||||
|
||||
if not old_row:
|
||||
return
|
||||
|
||||
old_name = old_row.get("name")
|
||||
|
||||
# Write scalar fields to tabSingles
|
||||
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)),
|
||||
)
|
||||
|
||||
# Restore child table rows
|
||||
for table in CHILD_TABLES:
|
||||
if not frappe.db.table_exists(table):
|
||||
continue
|
||||
try:
|
||||
child_rows = frappe.db.sql(
|
||||
f"SELECT * FROM `{table}` WHERE parent = %s ORDER BY idx",
|
||||
(old_name,),
|
||||
as_dict=True,
|
||||
)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if not child_rows:
|
||||
continue
|
||||
|
||||
frappe.db.sql(f"DELETE FROM `{table}` WHERE parent = 'E-Taxes Settings'")
|
||||
|
||||
for row in child_rows:
|
||||
row["parent"] = "E-Taxes Settings"
|
||||
row["parenttype"] = "E-Taxes Settings"
|
||||
columns = ", ".join(f"`{col}`" for col in row)
|
||||
placeholders = ", ".join(["%s"] * len(row))
|
||||
try:
|
||||
frappe.db.sql(
|
||||
f"INSERT INTO `{table}` ({columns}) VALUES ({placeholders})",
|
||||
list(row.values()),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
frappe.db.commit()
|
||||
frappe.clear_cache(doctype="E-Taxes Settings")
|
||||
|
|
|
|||
Loading…
Reference in New Issue