Add Phase 19 bank accounting and reconciliation workflow
This commit is contained in:
@@ -4,7 +4,7 @@ import io
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
|
||||
ERP_LOCAL_AGENT_VERSION = "1.18.0"
|
||||
ERP_LOCAL_AGENT_VERSION = "1.19.0"
|
||||
ERP_LOCAL_AGENT_NAME = "ERP Local Agent"
|
||||
RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime"
|
||||
_DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
__version__ = "1.18.0"
|
||||
__version__ = "1.19.0"
|
||||
AGENT_NAME = "ERP Local Agent"
|
||||
|
||||
@@ -48,6 +48,8 @@ class AgentCommandProcessor:
|
||||
result = self._post_purchase_voucher(payload)
|
||||
elif action == "accounting_bank_posting_preflight":
|
||||
result = self._bank_posting_preflight(payload)
|
||||
elif action == "accounting_bank_reconciliation_extract":
|
||||
result = self._bank_reconciliation_extract(payload)
|
||||
elif action == "accounting_post_bank_voucher":
|
||||
result = self._post_bank_voucher(payload)
|
||||
elif action == "accounting_native_voucher_preflight":
|
||||
@@ -83,7 +85,7 @@ class AgentCommandProcessor:
|
||||
return {
|
||||
"name": "ERP Local Agent", "version": __version__,
|
||||
"tally_capability": True, "accounting_act_capability": True,
|
||||
"tally_mapping_capability": True, "tally_master_sync_capability": True, "chart_of_accounts_capability": True, "native_voucher_engine_capability": True, "stock_item_native_voucher_capability": True,
|
||||
"tally_mapping_capability": True, "tally_master_sync_capability": True, "chart_of_accounts_capability": True, "native_voucher_engine_capability": True, "stock_item_native_voucher_capability": True, "bank_reconciliation_read_capability": True,
|
||||
"tally_transaction_sync_capability": True,
|
||||
"historical_learning_read_capability": True,
|
||||
"purchase_posting_preflight_capability": True,
|
||||
@@ -492,6 +494,57 @@ class AgentCommandProcessor:
|
||||
}
|
||||
|
||||
|
||||
def _bank_reconciliation_extract(self, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
company, company_name = self._resolve_open_company(payload)
|
||||
|
||||
bank_ledger_name = str(payload.get("bank_ledger_name") or "").strip()
|
||||
if not bank_ledger_name:
|
||||
raise ValueError("Bank ledger is required for reconciliation.")
|
||||
|
||||
ledgers = self.tally.bank_posting_ledgers(company_name)
|
||||
bank_names = {
|
||||
str(row.get("name") or "").strip().casefold()
|
||||
for row in (ledgers.get("bank_ledgers") or [])
|
||||
if str(row.get("name") or "").strip()
|
||||
}
|
||||
if bank_ledger_name.casefold() not in bank_names:
|
||||
raise ValueError(
|
||||
f"'{bank_ledger_name}' is not a Tally Bank Accounts ledger in the open company."
|
||||
)
|
||||
|
||||
date_from = str(payload.get("date_from") or "").strip()
|
||||
date_to = str(payload.get("date_to") or "").strip()
|
||||
vouchers = self.tally.export_vouchers(company_name, date_from, date_to)
|
||||
|
||||
filtered = []
|
||||
target = bank_ledger_name.casefold()
|
||||
for voucher in vouchers:
|
||||
entries = list(voucher.get("ledger_entries") or [])
|
||||
if not any(
|
||||
str(entry.get("ledger_name") or "").strip().casefold() == target
|
||||
for entry in entries
|
||||
):
|
||||
continue
|
||||
filtered.append(
|
||||
{
|
||||
key: value
|
||||
for key, value in voucher.items()
|
||||
if key != "raw_xml"
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"company_name": company_name,
|
||||
"company_guid": str(company.get("guid") or ""),
|
||||
"bank_ledger_name": bank_ledger_name,
|
||||
"date_from": date_from,
|
||||
"date_to": date_to,
|
||||
"voucher_count": len(filtered),
|
||||
"vouchers": filtered,
|
||||
"read_only": True,
|
||||
"agent": self._agent_info(),
|
||||
}
|
||||
|
||||
def _bank_posting_preflight(self, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
company, company_name = self._resolve_open_company(payload)
|
||||
ledgers = self.tally.bank_posting_ledgers(company_name)
|
||||
|
||||
Reference in New Issue
Block a user