Add direct Cash-in-Hand ledger selection for cash payment review

This commit is contained in:
A R R R Associates
2026-09-04 19:07:38 +05:30
parent 79896d72c1
commit 5c99d512c6
7 changed files with 136 additions and 22 deletions
+28 -14
View File
@@ -252,7 +252,7 @@ def cash_payment_review(
@router.post("/ledgers")
async def cash_payment_ledgers(request: Request):
"""Return cached ledgers immediately or start a non-blocking Tally master job."""
"""Load Cash-in-Hand ledgers directly; keep full-ledger sync only as manual fallback."""
form = await request.form()
validate_csrf(request, str(form.get("csrf_token") or ""))
db = CommonSessionLocal()
@@ -268,32 +268,46 @@ async def cash_payment_ledgers(request: Request):
selected_client = next((row for row in clients if int(row.id) == client_id), None)
if not selected_client:
return JSONResponse({"ok": False, "error": "Select a valid client."}, status_code=400)
tally_guid = str(form.get("tally_guid") or "").strip()
company_name = str(form.get("company_name") or "").strip()
date_from = str(form.get("date_from") or date.today().isoformat()).strip()
force_refresh = str(form.get("force_refresh") or "").strip().lower() in {"1","true","yes","on"}
ledger_scope = str(form.get("ledger_scope") or "cash").strip().lower()
force_refresh = str(form.get("force_refresh") or "").strip().lower() in {"1", "true", "yes", "on"}
if not tally_guid:
return JSONResponse({"ok": False, "error": "Select an open Tally company."}, status_code=400)
node = get_active_storage_node_for_branch(db, scope.tenant_id, scope.branch_id)
if not node or not _node_online(node):
return JSONResponse({"ok": False, "error": "ERP Local Agent is offline."}, status_code=409)
try:
fy = _financial_year_for_date(date.fromisoformat(date_from))
result = request_agent_command(
node.node_code,
"accounting_cash_payment_ledgers_start",
{
**_accounting_storage_payload(selected_client, fy),
"tally_guid": tally_guid,
"company_name": company_name,
"force_refresh": force_refresh,
},
timeout_seconds=20,
)
payload = {
**_accounting_storage_payload(selected_client, fy),
"tally_guid": tally_guid,
"company_name": company_name,
}
if ledger_scope == "all":
# Explicit manual fallback preserves the existing full-master async flow.
payload["force_refresh"] = force_refresh
result = request_agent_command(
node.node_code,
"accounting_cash_payment_ledgers_start",
payload,
timeout_seconds=20,
)
else:
# Normal path: small filtered Tally collection, no full ledger cache.
result = request_agent_command(
node.node_code,
"accounting_cash_payment_cash_ledgers",
payload,
timeout_seconds=30,
)
except Exception as exc:
return JSONResponse({"ok": False, "error": str(exc)}, status_code=502)
if not result.get("ok"):
return JSONResponse({"ok": False, "error": str(result.get("error") or "Could not start Tally ledger sync.")}, status_code=409)
return JSONResponse({"ok": False, "error": str(result.get("error") or "Could not load Tally ledgers.")}, status_code=409)
return JSONResponse({"ok": True, **(result.get("result") or {})})
finally:
db.close()
@@ -57,7 +57,7 @@
</div>
<div>
<label class="text-xs font-semibold uppercase text-slate-500">Cash Ledger</label>
<select id="cash-ledger-scope" class="mt-1 w-full rounded-xl border-slate-300 text-xs">
<select id="cash-ledger-scope" name="ledger_scope" class="mt-1 w-full rounded-xl border-slate-300 text-xs">
<option value="cash" selected>Ledgers under Cash-in-Hand</option>
<option value="all">All Tally ledgers — manual selection</option>
</select>
@@ -306,15 +306,27 @@
const companyOption = companySelect && companySelect.options[companySelect.selectedIndex];
const companyName = companyOption ? String(companyOption.dataset.companyName || companyOption.textContent || '').trim() : '';
if (companyName) fd.set('company_name', companyName);
const selectedScope = ledgerScope ? String(ledgerScope.value || 'cash') : 'cash';
fd.set('ledger_scope', selectedScope);
if(forceRefresh) fd.set('force_refresh','1');
ledgerButton.disabled = true; if(ledgerRefreshButton) ledgerRefreshButton.disabled=true;
ledgerHelp.textContent = forceRefresh ? 'Starting background refresh from Tally…' : 'Loading cached ledgers or starting background Tally sync…';
ledgerHelp.textContent = selectedScope === 'all'
? (forceRefresh ? 'Starting background full-ledger refresh from Tally…' : 'Loading the full ledger list for manual selection…')
: 'Reading Cash-in-Hand ledgers directly from the selected Tally company…';
try {
const response = await fetch('/tools/accounting/cash-payments/ledgers', {method:'POST', body:fd, headers:{'Accept':'application/json'}});
const data = await response.json();
if (!response.ok || !data.ok) throw new Error(data.error || 'Could not load Tally ledgers.');
if ((data.ledgers||[]).length) {
populateLedgers(data); ledgerButton.disabled=false; if(ledgerRefreshButton) ledgerRefreshButton.disabled=false; return;
if (Array.isArray(data.ledgers)) {
populateLedgers(data);
ledgerButton.disabled=false; if(ledgerRefreshButton) ledgerRefreshButton.disabled=false;
ledgerProgress.classList.remove('hidden');
ledgerProgressBar.style.width='100%'; ledgerProgressPct.textContent='100%';
ledgerProgressStage.textContent = data.cash_only
? String(data.ledger_count || 0)+' Cash-in-Hand ledger(s) ready'
: String(data.ledger_count || 0)+' ledger(s) ready';
window.setTimeout(()=>ledgerProgress.classList.add('hidden'),1200);
return;
}
const job=data.job||{};
if(!job.job_id) throw new Error('Local Agent did not return a ledger-sync job id.');
@@ -328,7 +340,10 @@
if (ledgerButton) ledgerButton.addEventListener('click', function(){loadCashLedgers(false);});
if (ledgerRefreshButton) ledgerRefreshButton.addEventListener('click', function(){loadCashLedgers(true);});
const companySelect = document.getElementById('cash-tally-company');
if (ledgerScope) ledgerScope.addEventListener('change', function(){ renderLedgerOptions(); });
if (ledgerScope) ledgerScope.addEventListener('change', function(){
ledgerSelect.innerHTML = '<option value="">Select Cash ledger</option>';
if (companySelect && companySelect.value) loadCashLedgers(false);
});
if (companySelect) companySelect.addEventListener('change', function(){
allLedgerRows = []; cashLedgerRows = []; lastLedgerMeta = {ledger_count:0, company_name:'', from_cache:false};
ledgerSelect.innerHTML = '<option value="">Select Cash ledger</option>';