Add TDS review drilldowns and exclude capital accounts
This commit is contained in:
@@ -4,7 +4,7 @@ import io
|
||||
from pathlib import Path
|
||||
import zipfile
|
||||
|
||||
ERP_LOCAL_AGENT_VERSION = "1.25.4"
|
||||
ERP_LOCAL_AGENT_VERSION = "1.25.5"
|
||||
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.25.4"
|
||||
__version__ = "1.25.5"
|
||||
AGENT_NAME = "ERP Local Agent"
|
||||
|
||||
@@ -3142,13 +3142,54 @@ class AgentCommandProcessor:
|
||||
# TDS ledgers are identified from the local mirror ledger master only.
|
||||
masters = (self.tally.mirror.master_snapshot(client_id, company_name, company_guid).get("ledgers") or [])
|
||||
tds_ledger_names = set()
|
||||
ledger_parent_by_name: dict[str, str] = {}
|
||||
for led in masters:
|
||||
name = str(led.get("name") or "").strip()
|
||||
parent = str(led.get("parent") or "").strip().casefold()
|
||||
parent_raw = str(led.get("parent") or "").strip()
|
||||
parent = parent_raw.casefold()
|
||||
if name:
|
||||
ledger_parent_by_name[name.casefold()] = parent_raw
|
||||
text = (name + " " + parent).casefold()
|
||||
if name and ("tds" in text or "tax deducted" in text or "duties & taxes" in parent and "income tax" in text):
|
||||
tds_ledger_names.add(name.casefold())
|
||||
|
||||
def _capital_account_parent(parent_name: str) -> bool:
|
||||
"""Exclude owners'/partners' capital-account ledgers from TDS candidates.
|
||||
|
||||
This does not exclude fixed assets or capital expenditure merely because
|
||||
they are assets. Only ledgers whose immediate Tally parent is a capital /
|
||||
owners' equity style group are ignored.
|
||||
"""
|
||||
value = re.sub(r"[^a-z0-9]+", " ", str(parent_name or "").casefold()).strip()
|
||||
if not value:
|
||||
return False
|
||||
exact = {
|
||||
"capital account",
|
||||
"capital accounts",
|
||||
"partners capital",
|
||||
"partner capital",
|
||||
"partners capital accounts",
|
||||
"partner capital accounts",
|
||||
"proprietors capital",
|
||||
"proprietor capital",
|
||||
"owners capital",
|
||||
"owner capital",
|
||||
"share capital",
|
||||
"reserves surplus",
|
||||
"reserves and surplus",
|
||||
}
|
||||
if value in exact:
|
||||
return True
|
||||
return (
|
||||
value.startswith("capital account ")
|
||||
or value.endswith(" capital account")
|
||||
or value.endswith(" capital accounts")
|
||||
or value.startswith("partners capital")
|
||||
or value.startswith("partner capital")
|
||||
or value.startswith("proprietor capital")
|
||||
or value.startswith("owner capital")
|
||||
)
|
||||
|
||||
candidates = []
|
||||
for v in vouchers:
|
||||
if str(v.get("is_cancelled") or "").lower() in {"yes","true","1"} or str(v.get("is_optional") or "").lower() in {"yes","true","1"}:
|
||||
@@ -3162,6 +3203,9 @@ class AgentCommandProcessor:
|
||||
amount = abs(float(e.get("amount") or 0))
|
||||
if not lname or amount <= 0 or (party and lname.casefold() == party.casefold()):
|
||||
continue
|
||||
parent_group = str(ledger_parent_by_name.get(lname.casefold()) or "").strip()
|
||||
if _capital_account_parent(parent_group):
|
||||
continue
|
||||
text = lname.casefold()
|
||||
matches=[]
|
||||
for r in rules:
|
||||
@@ -3170,7 +3214,7 @@ class AgentCommandProcessor:
|
||||
if not matches: continue
|
||||
# More specific/longer keyword match first; user can refine keywords in Rule Master.
|
||||
rule=max(matches,key=lambda r:max([len(k.strip()) for k in str(r.get("nature_keywords") or "").split(',') if k.strip()] or [0]))
|
||||
candidates.append({"date":str(v.get("date") or v.get("effective_date") or ""),"party":party or "Unidentified party","nature_ledger":lname,"taxable_base":round(amount,2),"actual_tds":actual_tds,"voucher_number":str(v.get("voucher_number") or ""),"voucher_type":str(v.get("voucher_type_name") or ""),"reference":str(v.get("reference") or ""),"rule":rule})
|
||||
candidates.append({"date":str(v.get("date") or v.get("effective_date") or ""),"party":party or "Unidentified party","nature_ledger":lname,"parent_group":parent_group,"taxable_base":round(amount,2),"actual_tds":actual_tds,"voucher_number":str(v.get("voucher_number") or ""),"voucher_type":str(v.get("voucher_type_name") or ""),"reference":str(v.get("reference") or ""),"rule":rule})
|
||||
|
||||
by_party_rule=defaultdict(list)
|
||||
for x in candidates: by_party_rule[(x["party"].casefold(),str(x["rule"].get("rule_code")))].append(x)
|
||||
|
||||
Reference in New Issue
Block a user