Add Phase 16 Chart of Accounts and ledger group intelligence
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
__version__ = "1.15.1"
|
||||
__version__ = "1.16.0"
|
||||
AGENT_NAME = "ERP Local Agent"
|
||||
|
||||
@@ -1077,6 +1077,61 @@ class LocalAccountingStore:
|
||||
).fetchall()
|
||||
return [dict(row) for row in rows]
|
||||
|
||||
|
||||
def chart_of_accounts_snapshot(self, client_id: int, *, tally_guid: str) -> dict:
|
||||
if not self.exists(client_id):
|
||||
raise ValueError("Accounting storage is not initialized for this client.")
|
||||
guid = str(tally_guid or "").strip()
|
||||
if not guid:
|
||||
raise ValueError("Tally company GUID is required.")
|
||||
|
||||
mapping = self.get_active_mapping_by_guid(client_id, guid)
|
||||
with self.connect(client_id) as db:
|
||||
groups = [
|
||||
dict(row)
|
||||
for row in db.execute(
|
||||
"""SELECT master_guid AS guid, name, parent, reserved_name,
|
||||
is_revenue, is_deemed_positive, payload_json
|
||||
FROM tally_groups
|
||||
WHERE tally_guid=?
|
||||
ORDER BY name COLLATE NOCASE""",
|
||||
(guid,),
|
||||
).fetchall()
|
||||
]
|
||||
ledgers = [
|
||||
dict(row)
|
||||
for row in db.execute(
|
||||
"""SELECT master_guid AS guid, name, parent,
|
||||
opening_balance, closing_balance, is_billwise_on,
|
||||
tax_type, gst_applicable, gst_registration_type,
|
||||
gst_type_of_supply, hsn_code, is_revenue,
|
||||
is_deemed_positive, payload_json
|
||||
FROM tally_ledgers
|
||||
WHERE tally_guid=?
|
||||
ORDER BY name COLLATE NOCASE""",
|
||||
(guid,),
|
||||
).fetchall()
|
||||
]
|
||||
|
||||
import json as _json
|
||||
for row in ledgers:
|
||||
try:
|
||||
payload = _json.loads(row.get("payload_json") or "{}")
|
||||
except Exception:
|
||||
payload = {}
|
||||
row["party_gstin"] = str(payload.get("party_gstin") or "")
|
||||
row.pop("payload_json", None)
|
||||
|
||||
for row in groups:
|
||||
row.pop("payload_json", None)
|
||||
|
||||
return {
|
||||
"tally_guid": guid,
|
||||
"company_name": str(mapping.get("company_name") or ""),
|
||||
"groups": groups,
|
||||
"ledgers": ledgers,
|
||||
}
|
||||
|
||||
def historical_learning_evidence(self, client_id: int, *, tally_guid: str, date_from: str = "", date_to: str = "", voucher_scope: str = "purchase") -> dict:
|
||||
"""Return neutral aggregated historical ledger facts from the local .act store.
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ class AgentCommandProcessor:
|
||||
result = self._unmap_company(payload)
|
||||
elif action == "accounting_sync_masters":
|
||||
result = self._sync_masters(payload)
|
||||
elif action == "accounting_chart_of_accounts":
|
||||
result = self._chart_of_accounts(payload)
|
||||
elif action == "accounting_sync_transactions":
|
||||
result = self._sync_transactions(payload)
|
||||
elif action == "accounting_historical_evidence":
|
||||
@@ -76,7 +78,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,
|
||||
"tally_mapping_capability": True, "tally_master_sync_capability": True, "chart_of_accounts_capability": True,
|
||||
"tally_transaction_sync_capability": True,
|
||||
"historical_learning_read_capability": True,
|
||||
"purchase_posting_preflight_capability": True,
|
||||
@@ -322,6 +324,21 @@ class AgentCommandProcessor:
|
||||
return evidence
|
||||
|
||||
|
||||
|
||||
def _chart_of_accounts(self, payload: dict[str, Any]) -> dict[str, Any]:
|
||||
# Read-only: refresh the existing master snapshot, then return Groups/Ledgers.
|
||||
sync_result = self._sync_masters(payload)
|
||||
client_id = int(payload.get("client_id"))
|
||||
tally_guid = str(payload.get("tally_guid") or "").strip()
|
||||
chart = self.store.chart_of_accounts_snapshot(
|
||||
client_id,
|
||||
tally_guid=tally_guid,
|
||||
)
|
||||
return {
|
||||
**sync_result,
|
||||
"chart_of_accounts": chart,
|
||||
}
|
||||
|
||||
def _resolve_open_company(self, payload: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
||||
requested_guid = str(payload.get("tally_guid") or "").strip()
|
||||
if not requested_guid:
|
||||
|
||||
@@ -114,7 +114,7 @@ class TallyLiveConnector:
|
||||
"collection": "ARRRAccountingLedgers",
|
||||
"type": "Ledger",
|
||||
"tag": "LEDGER",
|
||||
"fetch": "Name,GUID,Parent,OpeningBalance,ClosingBalance,IsBillWiseOn,TaxType,GSTApplicable,GSTRegistrationType",
|
||||
"fetch": "Name,GUID,Parent,OpeningBalance,ClosingBalance,IsBillWiseOn,TaxType,GSTApplicable,GSTRegistrationType,GSTTypeOfSupply,HSNCode,PartyGSTIN,GSTIN,GSTRegistrationNumber,IsRevenue,IsDeemedPositive,IsActive",
|
||||
},
|
||||
"voucher_types": {
|
||||
"collection": "ARRRAccountingVoucherTypes",
|
||||
@@ -1095,6 +1095,10 @@ class TallyLiveConnector:
|
||||
"gst_registration_type": _child_text(element, "GSTREGISTRATIONTYPE"),
|
||||
"gst_type_of_supply": _child_text(element, "GSTTYPEOFSUPPLY"),
|
||||
"hsn_code": _first_text(element, ("HSNCODE", "GSTHSNCODE")),
|
||||
"party_gstin": _first_text(
|
||||
element,
|
||||
("PARTYGSTIN", "GSTIN", "GSTREGISTRATIONNUMBER", "GSTNO", "GSTNUMBER"),
|
||||
),
|
||||
"is_revenue": _child_text(element, "ISREVENUE"),
|
||||
"is_deemed_positive": _child_text(element, "ISDEEMEDPOSITIVE"),
|
||||
"is_billwise_on": _child_text(element, "ISBILLWISEON"),
|
||||
|
||||
Reference in New Issue
Block a user