Move Tally accounting DB into FY client engagement folder

This commit is contained in:
A R R R Associates
2026-08-20 16:17:17 +05:30
parent 3912d2fd16
commit f7ebd32597
6 changed files with 63 additions and 27 deletions
+24 -13
View File
@@ -15,7 +15,7 @@ from app.core.templating import templates
from app.modules.clients.models import Client
from app.modules.core.rbac.deps import get_user_permissions, get_user_roles
from app.modules.core.rbac.permission_guard import require_permission
from app.modules.documents.services import build_document_scope, get_active_storage_node_for_branch, client_folder_parts
from app.modules.documents.services import build_document_scope, get_active_storage_node_for_branch, client_folder_parts, sanitize_segment
from app.modules.accounting.agent_bridge import request_agent_command
from app.modules.registrations.models import ClientRegistration, RegistrationType
@@ -56,14 +56,23 @@ def _find_visible_client(db, request: Request, user, client_id: int):
return client, clients, scope
def _accounting_storage_payload(client) -> dict:
"""Use the exact client folder naming policy already used by Permanent/Engagement storage."""
def _financial_year_for_date(value: date | None = None) -> str:
value = value or date.today()
start_year = value.year if value.month >= 4 else value.year - 1
return f"{start_year}-{str(start_year + 1)[-2:]}"
def _accounting_storage_payload(client, financial_year: str | None = None) -> dict:
"""Use the same FY + client-folder policy as existing Engagement storage."""
fy_value = str(financial_year or _financial_year_for_date()).strip()
fy_folder = sanitize_segment(f"FY{fy_value}", "FY")
letter, client_folder = client_folder_parts(client, int(client.id))
relative_dir = Path("Accounting") / "Clients" / letter / client_folder
relative_dir = Path(fy_folder) / "Clients" / letter / client_folder / "Accounting"
return {
"client_id": int(client.id),
"client_name": str(client.client_name or "").strip(),
"client_code": str(getattr(client, "client_code", "") or "").strip(),
"financial_year": fy_value,
"accounting_relative_dir": relative_dir.as_posix(),
}
@@ -462,7 +471,7 @@ def sync_tally_transactions(
node.node_code,
"accounting_sync_transactions",
{
**_accounting_storage_payload(client),
**_accounting_storage_payload(client, _financial_year_for_date(start)),
"tally_guid": str(tally_guid or "").strip(),
"date_from": start.isoformat(),
"date_to": end.isoformat(),
@@ -504,16 +513,16 @@ def depreciation_it_tool(
live_result = None; preview = None; depreciation_run = None; command_error = error or ""
if selected_client and node and online:
try:
status_response = request_agent_command(node.node_code,"phase6_status",_accounting_storage_payload(selected_client),timeout_seconds=20)
status_response = request_agent_command(node.node_code,"phase6_status",_accounting_storage_payload(selected_client, _financial_year_for_date(date.fromisoformat(start_text))),timeout_seconds=20)
if status_response.get("ok"): live_result=status_response.get("result") or {}
else: command_error=str(status_response.get("error") or "Local Agent status failed.")
chosen_guid=str(tally_guid or "").strip()
if chosen_guid:
preview_response=request_agent_command(node.node_code,"accounting_depreciation_preview",{**_accounting_storage_payload(selected_client),"tally_guid":chosen_guid,"fy_start":start_text,"fy_end":end_text},timeout_seconds=60)
preview_response=request_agent_command(node.node_code,"accounting_depreciation_preview",{**_accounting_storage_payload(selected_client, _financial_year_for_date(date.fromisoformat(start_text))),"tally_guid":chosen_guid,"fy_start":start_text,"fy_end":end_text},timeout_seconds=60)
if preview_response.get("ok"): preview=(preview_response.get("result") or {}).get("preview")
else: command_error=str(preview_response.get("error") or "Depreciation preview failed.")
if run_id:
run_response=request_agent_command(node.node_code,"accounting_get_it_depreciation_run",{**_accounting_storage_payload(selected_client),"run_id":int(run_id)},timeout_seconds=30)
run_response=request_agent_command(node.node_code,"accounting_get_it_depreciation_run",{**_accounting_storage_payload(selected_client, _financial_year_for_date(date.fromisoformat(start_text))),"run_id":int(run_id)},timeout_seconds=30)
if run_response.get("ok"): depreciation_run=(run_response.get("result") or {}).get("depreciation")
except Exception as exc: command_error=str(exc)
base={"request":request,"current_user":user,"current_user_roles":get_user_roles(db,user.id),"current_user_permissions":get_user_permissions(db,user.id),"csrf_token":get_or_create_csrf_token(request)}
@@ -545,7 +554,7 @@ async def calculate_it_depreciation(request: Request):
node=get_active_storage_node_for_branch(db,scope.tenant_id,scope.branch_id)
if not node or not _node_online(node): return RedirectResponse(url=f"/tools/tally/depreciation?client_id={client.id}&tally_guid={quote(tally_guid)}&fy_start={start.isoformat()}&fy_end={end.isoformat()}&error={quote('ERP Local Agent is offline for the active branch.')}",status_code=303)
try:
result=request_agent_command(node.node_code,"accounting_calculate_it_depreciation",{**_accounting_storage_payload(client),"tally_guid":tally_guid,"fy_start":start.isoformat(),"fy_end":end.isoformat(),"assignments":assignments,"depreciation_expense_ledger":str(form.get("depreciation_expense_ledger") or ""),"depreciation_reserve_ledger":str(form.get("depreciation_reserve_ledger") or ""),"requested_by_user_id":int(user.id)},timeout_seconds=120)
result=request_agent_command(node.node_code,"accounting_calculate_it_depreciation",{**_accounting_storage_payload(client, _financial_year_for_date(start)),"tally_guid":tally_guid,"fy_start":start.isoformat(),"fy_end":end.isoformat(),"assignments":assignments,"depreciation_expense_ledger":str(form.get("depreciation_expense_ledger") or ""),"depreciation_reserve_ledger":str(form.get("depreciation_reserve_ledger") or ""),"requested_by_user_id":int(user.id)},timeout_seconds=120)
if not result.get("ok"): raise RuntimeError(str(result.get("error") or "Income-tax depreciation calculation failed."))
dep=(result.get("result") or {}).get("depreciation") or {}; rid=int(dep.get("run_id"))
except Exception as exc:
@@ -565,8 +574,9 @@ async def approve_it_depreciation(request: Request):
if response: return response
try:
client_id = int(form.get("client_id")); run_id = int(form.get("run_id"))
approval_fy_start = date.fromisoformat(str(form.get("fy_start") or ""))
except Exception:
return RedirectResponse(url="/tools/tally/depreciation?error=" + quote("Invalid depreciation draft."), status_code=303)
return RedirectResponse(url="/tools/tally/depreciation?error=" + quote("Invalid depreciation draft or financial year."), status_code=303)
client, _clients, scope = _find_visible_client(db, request, user, client_id)
if not client: return _denied()
if str(form.get("confirm_approval") or "") != "yes":
@@ -577,7 +587,7 @@ async def approve_it_depreciation(request: Request):
try:
result = request_agent_command(
node.node_code, "accounting_approve_it_depreciation",
{**_accounting_storage_payload(client), "run_id": run_id, "approved_by_user_id": int(user.id), "approval_note": str(form.get("approval_note") or "")},
{**_accounting_storage_payload(client, _financial_year_for_date(approval_fy_start)), "run_id": run_id, "approved_by_user_id": int(user.id), "approval_note": str(form.get("approval_note") or "")},
timeout_seconds=30,
)
if not result.get("ok"): raise RuntimeError(str(result.get("error") or "Approval failed."))
@@ -600,8 +610,9 @@ async def post_it_depreciation_to_tally(request: Request):
if response: return response
try:
client_id = int(form.get("client_id")); run_id = int(form.get("run_id"))
posting_fy_start = date.fromisoformat(str(form.get("fy_start") or ""))
except Exception:
return RedirectResponse(url="/tools/tally/depreciation?error=" + quote("Invalid depreciation draft."), status_code=303)
return RedirectResponse(url="/tools/tally/depreciation?error=" + quote("Invalid depreciation draft or financial year."), status_code=303)
client, _clients, scope = _find_visible_client(db, request, user, client_id)
if not client: return _denied()
if str(form.get("post_confirmation") or "").strip().upper() != "POST":
@@ -614,7 +625,7 @@ async def post_it_depreciation_to_tally(request: Request):
try:
result = request_agent_command(
node.node_code, "accounting_post_it_depreciation",
{**_accounting_storage_payload(client), "run_id": run_id, "posted_by_user_id": int(user.id)},
{**_accounting_storage_payload(client, _financial_year_for_date(posting_fy_start)), "run_id": run_id, "posted_by_user_id": int(user.id)},
timeout_seconds=120,
)
if not result.get("ok"): raise RuntimeError(str(result.get("error") or "Tally write-back failed."))