Fix case insensitive Accounting Mirror master persistence

This commit is contained in:
A R R R Associates
2026-09-09 12:22:26 +05:30
parent 88bcd4d0a4
commit 4ef6b1fc5d
4 changed files with 40 additions and 8 deletions
@@ -1,2 +1,2 @@
__version__ = "1.26.9"
__version__ = "1.26.10"
AGENT_NAME = "ERP Local Agent"
@@ -140,7 +140,21 @@ class AccountingMirrorEngine:
reader = csv.DictReader(f)
if not reader.fieldnames:
return []
return [{str(k or "").lstrip("$").strip(): (v or "") for k, v in row.items()} for row in reader]
result: list[dict[str, str]] = []
for raw in reader:
row: dict[str, str] = {}
for key, value in raw.items():
clean = str(key or "").lstrip("$").strip()
if not clean:
continue
text = value or ""
row[clean] = text
# Alias every field by case-folded name. This fixes Tally
# variants such as Guid/GUID and GstRegistrationType/
# GSTRegistrationType without changing the extracted CSV.
row[clean.casefold()] = text
result.append(row)
return result
@staticmethod
def _summary(db_path: Path) -> dict[str, Any]:
@@ -228,6 +242,14 @@ class AccountingMirrorEngine:
if not rows:
diagnostics[table] = {"source_rows": 0, "stored_rows": 0}
continue
if table == "group_master":
sample = rows[0] if rows else {}
diagnostics["group_csv"] = {
"source_rows": len(rows),
"sample_name": _text(sample.get("Name", sample.get("name", ""))),
"sample_parent": _text(sample.get("Parent", sample.get("parent", ""))),
"sample_guid": _text(sample.get("GUID", sample.get("guid", ""))),
}
names = [name for name,_ in cols]
placeholders = ",".join("?" for _ in names)
for row in rows:
@@ -240,7 +262,7 @@ class AccountingMirrorEngine:
"gst_type_of_supply":"GSTTypeofSupply","original_name":"OriginalName",
"is_simple_unit":"IsSimpleUnit","additional_units":"AdditionalUnits","conversion":"Conversion",
}.get(name, name)
value = row.get(source, "")
value = row.get(source, row.get(str(source).casefold(), ""))
if name == "conversion":
value = _number(value)
else:
@@ -66,16 +66,21 @@ def csv_rows_expected(src, name, expected_fields):
return
clean=[ck(x) for x in headers]
print(f"{name} headers:",clean)
expected_map={str(x).casefold(): str(x) for x in expected_fields}
header_keys={x.casefold() for x in clean if x}
expected_keys={str(x).casefold() for x in expected_fields}
expected_keys=set(expected_map)
use_headers=bool(expected_keys.intersection(header_keys)) and "name" in header_keys
for values in raw:
if use_headers:
row={}
for idx,key in enumerate(clean):
if key:
row[key]=values[idx] if idx < len(values) else ""
yield norm(row)
if not key:
continue
canonical=expected_map.get(key.casefold(), key)
row[canonical]=values[idx] if idx < len(values) else ""
# Keep exact expected key names (GUID, AlterID, Name...) so the
# existing proven loader never loses a row due only to header case.
yield row
else:
row={}
for idx,key in enumerate(expected_fields):
@@ -396,6 +401,11 @@ def main():
lname=t(r.get("Name"))
if not lg or not lname:
ledger_skipped_rows+=1
if ledger_skipped_rows <= 3:
print(
"LEDGER IMPORT - SKIPPED SAMPLE:",
{"GUID": lg, "Name": lname, "keys": sorted(str(k) for k in r.keys())}
)
continue
aid=integer(r.get("AlterID")) or 0
max_ledger_alter=max(max_ledger_alter,aid)