Unify accounting analysis on Client FY mirror registry

This commit is contained in:
A R R R Associates
2026-09-20 16:36:14 +05:30
parent 24b13e5d6e
commit c63fc2773c
11 changed files with 103 additions and 45 deletions
@@ -21,7 +21,7 @@ from app.core.security.csrf import get_or_create_csrf_token, validate_csrf
from app.core.settings import get_settings
from app.core.templating import templates
from app.modules.accounting.agent_bridge import request_agent_command
from app.modules.accounting.ui import _accounting_storage_payload, _find_visible_client, _require_partner, _visible_clients, _node_online
from app.modules.accounting.ui import _accounting_storage_payload, _analysis_accounting_storage_payload, _find_visible_client, _require_partner, _visible_clients, _node_online
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
from app.modules.credential_vault.crypto import decrypt_value
from app.modules.credential_vault.models import CredentialVaultEntry
@@ -256,13 +256,18 @@ def _vault_entries(db, user, request, tenant_id: int, client_id: int, registrati
return sorted(eligible, key=rank)
def _storage_payload(client, fy: str, gstin: str) -> tuple[str, str]:
def _storage_payload(client, fy: str, gstin: str, *, db=None, tenant_id: int | None = None, require_registered: bool = False) -> tuple[dict, str]:
fy_folder = sanitize_segment(f"FY{fy}", "FY")
letter, client_folder = client_folder_parts(client, int(client.id))
root = Path(fy_folder) / "Clients" / letter / client_folder
accounting = _accounting_storage_payload(client, fy)
accounting_dir = str(accounting.get("accounting_relative_dir") or (root / "Accounting").as_posix()).strip()
return accounting_dir, (root / "GST" / sanitize_segment(f"GSTIN_{gstin}", "GSTIN")).as_posix()
if require_registered:
accounting = _analysis_accounting_storage_payload(
client, fy, db=db, tenant_id=tenant_id
)
else:
accounting = _accounting_storage_payload(client, fy, db=db, tenant_id=tenant_id)
accounting.setdefault("accounting_relative_dir", (root / "Accounting").as_posix())
return accounting, (root / "GST" / sanitize_segment(f"GSTIN_{gstin}", "GSTIN")).as_posix()
def _redirect(client_id: int, **params):
@@ -490,7 +495,8 @@ def start_download(
# Ensure FY is consistent in single-month mode.
if download_mode == "single":
financial_year=_fy_for_period(periods[0])
accounting_dir,gst_dir=_storage_payload(client,financial_year,gstin)
accounting_payload,gst_dir=_storage_payload(client,financial_year,gstin,db=db,tenant_id=scope.tenant_id)
accounting_dir=str(accounting_payload.get("accounting_relative_dir") or "")
jti=uuid.uuid4().hex
token=_encode_operator_token({
"jti":jti,"user_id":int(user.id),"tenant_id":int(scope.tenant_id),"branch_id":int(scope.branch_id),
@@ -610,7 +616,8 @@ async def import_downloaded_returns(
allowed_periods = set(_selected_periods(download_mode, financial_year, period))
if download_mode == "single":
financial_year = _fy_for_period(next(iter(allowed_periods)))
accounting_dir, gst_dir = _storage_payload(client, financial_year, gstin)
accounting_payload, gst_dir = _storage_payload(client, financial_year, gstin, db=db, tenant_id=scope.tenant_id)
accounting_dir = str(accounting_payload.get("accounting_relative_dir") or "")
groups = {
"GSTR1": gstr1_files or [], "GSTR2B": gstr2b_files or [],
"GSTR3B": gstr3b_files or [], "GSTR2A": gstr2a_files or [],
@@ -719,13 +726,14 @@ def analyze(request: Request, client_id: int=Form(...), registration_id: int=For
reg,_=pair; gstin=_norm_gstin(reg.registration_number)
periods=_periods_for_fy(financial_year) if analyze_mode=="full_fy" else [re.sub(r"\D","",period or "")]
if any(len(p)!=6 for p in periods): raise ValueError("Enter a valid MMYYYY period.")
accounting_dir,gst_dir=_storage_payload(client,financial_year,gstin)
accounting_payload,gst_dir=_storage_payload(client,financial_year,gstin,db=db,tenant_id=scope.tenant_id,require_registered=True)
accounting_dir=str(accounting_payload.get("accounting_relative_dir") or "")
node=get_active_storage_node_for_branch(db,scope.tenant_id,scope.branch_id)
if not node or not _node_online(node): return _redirect(client_id,registration_id=registration_id,period=period,financial_year=financial_year,error="Local Storage Agent is offline.")
results=[]
for p in periods:
date_from,date_to=_period_bounds(p)
res=request_agent_command(node.node_code,"gst_reconciliation_analyze",{"client_id":client.id,"gstin":gstin,"financial_year":financial_year,"period":p,"gst_relative_dir":gst_dir,"accounting_relative_dir":accounting_dir,"date_from":date_from,"date_to":date_to},timeout_seconds=30)
res=request_agent_command(node.node_code,"gst_reconciliation_analyze",{**accounting_payload,"client_id":client.id,"gstin":gstin,"financial_year":financial_year,"period":p,"gst_relative_dir":gst_dir,"accounting_relative_dir":accounting_dir,"date_from":date_from,"date_to":date_to},timeout_seconds=30)
if res.get("ok"):
results.append((res.get("result") or {}).get("analysis") or {})
if not results: raise RuntimeError("No stored GST periods could be reconciled.")