Add TDS review drilldowns and exclude capital accounts

This commit is contained in:
A R R R Associates
2026-09-06 21:12:14 +05:30
parent cbe594e73b
commit f211d9e6a8
4 changed files with 81 additions and 7 deletions
@@ -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)