Fix Accounting Mirror trial balance reconciliation v1.26.22

This commit is contained in:
A R R R Associates
2026-09-24 20:25:34 +05:30
parent 595252c609
commit 76e13aa379
3 changed files with 82 additions and 9 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ import io
from pathlib import Path from pathlib import Path
import zipfile import zipfile
ERP_LOCAL_AGENT_VERSION = "1.26.21" ERP_LOCAL_AGENT_VERSION = "1.26.22"
ERP_LOCAL_AGENT_NAME = "ERP Local Agent" ERP_LOCAL_AGENT_NAME = "ERP Local Agent"
RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime" RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime"
_DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0) _DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0)
@@ -1 +1 @@
__version__ = "1.26.21" __version__ = "1.26.22"
@@ -4558,14 +4558,87 @@ class AgentCommandProcessor:
(*params,limit)).fetchall()] (*params,limit)).fetchall()]
return {"rows":rows,"count":len(rows)} return {"rows":rows,"count":len(rows)}
if query == "trial_balance": if query == "trial_balance":
# Tally Trial Balance excludes cancelled and optional vouchers. Older
# mirror queries summed voucher_ledger_entry directly, so those
# non-accounting vouchers could make mirror debit/credit movement
# differ from Tally even though Tally itself was perfectly balanced.
#
# Keep Tally's master opening/closing balances as the authoritative
# control figures and independently reconstruct closing from booked
# voucher movement. The extra calculated/difference columns are
# backward compatible: existing callers continue using the original
# opening_balance, closing_balance, debit and credit fields.
rows=[dict(r) for r in db.execute( rows=[dict(r) for r in db.execute(
"""SELECT lm.ledger_name,lm.parent_group,lm.opening_balance,lm.closing_balance, """WITH booked_movement AS (
ROUND(COALESCE(SUM(CASE WHEN vle.dr_cr='DR' THEN vle.amount ELSE 0 END),0),2) debit, SELECT lower(trim(COALESCE(vle.ledger_name,''))) AS ledger_key,
ROUND(COALESCE(SUM(CASE WHEN vle.dr_cr='CR' THEN vle.amount ELSE 0 END),0),2) credit ROUND(COALESCE(SUM(CASE WHEN vle.dr_cr='DR' THEN vle.amount ELSE 0 END),0),2) AS debit,
FROM ledger_master lm LEFT JOIN voucher_ledger_entry vle ON vle.ledger_name=lm.ledger_name ROUND(COALESCE(SUM(CASE WHEN vle.dr_cr='CR' THEN vle.amount ELSE 0 END),0),2) AS credit
GROUP BY lm.ledger_guid,lm.ledger_name,lm.parent_group,lm.opening_balance,lm.closing_balance FROM voucher_ledger_entry vle
JOIN voucher v ON v.voucher_guid=vle.voucher_guid
WHERE COALESCE(v.is_cancelled,0)=0
AND COALESCE(v.is_optional,0)=0
GROUP BY lower(trim(COALESCE(vle.ledger_name,'')))
)
SELECT lm.ledger_name,lm.parent_group,lm.opening_balance,lm.closing_balance,
ROUND(COALESCE(bm.debit,0),2) AS debit,
ROUND(COALESCE(bm.credit,0),2) AS credit,
ROUND(COALESCE(lm.opening_balance,0)
+ COALESCE(bm.credit,0) - COALESCE(bm.debit,0),2) AS calculated_closing_balance,
ROUND(COALESCE(lm.closing_balance,0)
- (COALESCE(lm.opening_balance,0)
+ COALESCE(bm.credit,0) - COALESCE(bm.debit,0)),2) AS reconciliation_difference
FROM ledger_master lm
LEFT JOIN booked_movement bm
ON bm.ledger_key=lower(trim(COALESCE(lm.ledger_name,'')))
ORDER BY lm.parent_group,lm.ledger_name LIMIT ?""",(limit,)).fetchall()] ORDER BY lm.parent_group,lm.ledger_name LIMIT ?""",(limit,)).fetchall()]
return {"rows":rows,"count":len(rows)}
# Diagnostics are deliberately returned alongside the existing rows
# instead of changing/removing any existing Trial Balance behaviour.
# This makes extraction defects visible without ever inserting a
# balancing ledger or silently changing Tally control balances.
difference_rows = [
r for r in rows
if abs(float(r.get("reconciliation_difference") or 0)) > 0.01
]
totals = {
"opening_debit": round(sum(abs(float(r.get("opening_balance") or 0)) for r in rows if float(r.get("opening_balance") or 0) < 0), 2),
"opening_credit": round(sum(float(r.get("opening_balance") or 0) for r in rows if float(r.get("opening_balance") or 0) > 0), 2),
"debit": round(sum(float(r.get("debit") or 0) for r in rows), 2),
"credit": round(sum(float(r.get("credit") or 0) for r in rows), 2),
"closing_debit": round(sum(abs(float(r.get("closing_balance") or 0)) for r in rows if float(r.get("closing_balance") or 0) < 0), 2),
"closing_credit": round(sum(float(r.get("closing_balance") or 0) for r in rows if float(r.get("closing_balance") or 0) > 0), 2),
}
totals["movement_difference"] = round(totals["debit"] - totals["credit"], 2)
totals["closing_difference"] = round(totals["closing_debit"] - totals["closing_credit"], 2)
unmatched = [dict(r) for r in db.execute(
"""SELECT vle.ledger_name, COUNT(*) AS entry_count,
ROUND(SUM(CASE WHEN vle.dr_cr='DR' THEN vle.amount ELSE 0 END),2) AS debit,
ROUND(SUM(CASE WHEN vle.dr_cr='CR' THEN vle.amount ELSE 0 END),2) AS credit
FROM voucher_ledger_entry vle
JOIN voucher v ON v.voucher_guid=vle.voucher_guid
LEFT JOIN ledger_master lm
ON lower(trim(COALESCE(lm.ledger_name,'')))=lower(trim(COALESCE(vle.ledger_name,'')))
WHERE COALESCE(v.is_cancelled,0)=0
AND COALESCE(v.is_optional,0)=0
AND lm.ledger_name IS NULL
GROUP BY vle.ledger_name
ORDER BY ABS(COALESCE(SUM(CASE WHEN vle.dr_cr='DR' THEN vle.amount ELSE -vle.amount END),0)) DESC
LIMIT 100"""
).fetchall()]
return {
"rows": rows,
"count": len(rows),
"reconciliation": {
"ok": not difference_rows and not unmatched and abs(totals["movement_difference"]) <= 0.01,
"difference_count": len(difference_rows),
"differences": difference_rows[:100],
"unmatched_ledger_count": len(unmatched),
"unmatched_ledgers": unmatched,
"totals": totals,
"basis": "Booked vouchers only; cancelled and optional vouchers excluded; Tally ledger closing balance retained as control figure.",
},
}
if query == "group_master": if query == "group_master":
rows=[dict(r) for r in db.execute( rows=[dict(r) for r in db.execute(
"""SELECT master_guid,name,parent,reserved_name,is_revenue,is_deemed_positive,is_active """SELECT master_guid,name,parent,reserved_name,is_revenue,is_deemed_positive,is_active