Show all open Tally companies in cash payment review
This commit is contained in:
@@ -273,7 +273,7 @@ async def cash_payment_ledgers(request: Request):
|
|||||||
date_from = str(form.get("date_from") or date.today().isoformat()).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"}
|
force_refresh = str(form.get("force_refresh") or "").strip().lower() in {"1","true","yes","on"}
|
||||||
if not tally_guid:
|
if not tally_guid:
|
||||||
return JSONResponse({"ok": False, "error": "Select a mapped Tally company."}, status_code=400)
|
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)
|
node = get_active_storage_node_for_branch(db, scope.tenant_id, scope.branch_id)
|
||||||
if not node or not _node_online(node):
|
if not node or not _node_online(node):
|
||||||
return JSONResponse({"ok": False, "error": "ERP Local Agent is offline."}, status_code=409)
|
return JSONResponse({"ok": False, "error": "ERP Local Agent is offline."}, status_code=409)
|
||||||
@@ -351,6 +351,7 @@ async def start_cash_payment_cache(request: Request):
|
|||||||
if not selected_client:
|
if not selected_client:
|
||||||
return JSONResponse({"ok": False, "error": "Select a valid client."}, status_code=400)
|
return JSONResponse({"ok": False, "error": "Select a valid client."}, status_code=400)
|
||||||
tally_guid = str(form.get("tally_guid") or "").strip()
|
tally_guid = str(form.get("tally_guid") or "").strip()
|
||||||
|
company_name = str(form.get("company_name") or "").strip()
|
||||||
cash_ledger_name = str(form.get("cash_ledger_name") or "").strip()
|
cash_ledger_name = str(form.get("cash_ledger_name") or "").strip()
|
||||||
date_from = str(form.get("date_from") or "").strip()
|
date_from = str(form.get("date_from") or "").strip()
|
||||||
date_to = str(form.get("date_to") or "").strip()
|
date_to = str(form.get("date_to") or "").strip()
|
||||||
@@ -362,7 +363,7 @@ async def start_cash_payment_cache(request: Request):
|
|||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return JSONResponse({"ok": False, "error": str(exc)}, status_code=400)
|
return JSONResponse({"ok": False, "error": str(exc)}, status_code=400)
|
||||||
if not tally_guid:
|
if not tally_guid:
|
||||||
return JSONResponse({"ok": False, "error": "Select a mapped Tally company."}, status_code=400)
|
return JSONResponse({"ok": False, "error": "Select an open Tally company."}, status_code=400)
|
||||||
if not cash_ledger_name:
|
if not cash_ledger_name:
|
||||||
return JSONResponse({"ok": False, "error": "Load the Tally ledgers and confirm the Cash ledger."}, status_code=400)
|
return JSONResponse({"ok": False, "error": "Load the Tally ledgers and confirm the Cash ledger."}, status_code=400)
|
||||||
node = get_active_storage_node_for_branch(db, scope.tenant_id, scope.branch_id)
|
node = get_active_storage_node_for_branch(db, scope.tenant_id, scope.branch_id)
|
||||||
@@ -376,6 +377,7 @@ async def start_cash_payment_cache(request: Request):
|
|||||||
{
|
{
|
||||||
**_accounting_storage_payload(selected_client, _financial_year_for_date(parsed_from)),
|
**_accounting_storage_payload(selected_client, _financial_year_for_date(parsed_from)),
|
||||||
"tally_guid": tally_guid,
|
"tally_guid": tally_guid,
|
||||||
|
"company_name": company_name,
|
||||||
"date_from": date_from,
|
"date_from": date_from,
|
||||||
"date_to": date_to,
|
"date_to": date_to,
|
||||||
"cash_ledger_name": cash_ledger_name,
|
"cash_ledger_name": cash_ledger_name,
|
||||||
|
|||||||
@@ -32,11 +32,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label class="text-xs font-semibold uppercase text-slate-500">Tally Company</label>
|
<label class="text-xs font-semibold uppercase text-slate-500">Tally Company</label>
|
||||||
<select name="tally_guid" class="mt-1 w-full rounded-xl border-slate-300 text-sm" {% if selected_client %}required{% endif %}>
|
<select id="cash-tally-company" name="tally_guid" class="mt-1 w-full rounded-xl border-slate-300 text-sm" {% if selected_client %}required{% endif %}>
|
||||||
<option value="">Select open/mapped company</option>
|
<option value="">Select open Tally company</option>
|
||||||
|
{% set mapped_guids = [] %}
|
||||||
{% if live_result and live_result.accounting %}
|
{% if live_result and live_result.accounting %}
|
||||||
{% for mapping in live_result.accounting.mappings or [] %}
|
{% for mapping in live_result.accounting.mappings or [] %}
|
||||||
<option value="{{ mapping.tally_guid }}" data-company-name="{{ mapping.company_name or mapping.tally_company_name or '' }}" {% if selected_tally_guid == mapping.tally_guid %}selected{% endif %}>{{ mapping.company_name or mapping.tally_company_name or mapping.tally_guid }}</option>
|
{% if mapping.tally_guid %}{% set _ = mapped_guids.append(mapping.tally_guid) %}{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if live_result and live_result.tally %}
|
||||||
|
{% for company in live_result.tally.companies or [] %}
|
||||||
|
{% set is_mapped = company.guid in mapped_guids %}
|
||||||
|
<option value="{{ company.guid }}" data-company-name="{{ company.name or '' }}" data-open-company="1" {% if selected_tally_guid == company.guid or (not selected_tally_guid and is_mapped) %}selected{% endif %}>{{ company.name or company.guid }}{% if is_mapped %} • Mapped{% endif %}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if live_result and live_result.accounting %}
|
||||||
|
{% for mapping in live_result.accounting.mappings or [] %}
|
||||||
|
{% if mapping.tally_guid and mapping.tally_guid not in ((live_result.tally.companies or [])|map(attribute='guid')|list if live_result and live_result.tally else []) %}
|
||||||
|
<option value="{{ mapping.tally_guid }}" data-company-name="{{ mapping.company_name or mapping.tally_company_name or '' }}" data-open-company="0" {% if selected_tally_guid == mapping.tally_guid %}selected{% endif %}>{{ mapping.company_name or mapping.tally_company_name or mapping.tally_guid }} • Mapped (not open)</option>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
@@ -284,6 +298,12 @@
|
|||||||
}
|
}
|
||||||
if (ledgerButton) ledgerButton.addEventListener('click', function(){loadCashLedgers(false);});
|
if (ledgerButton) ledgerButton.addEventListener('click', function(){loadCashLedgers(false);});
|
||||||
if (ledgerRefreshButton) ledgerRefreshButton.addEventListener('click', function(){loadCashLedgers(true);});
|
if (ledgerRefreshButton) ledgerRefreshButton.addEventListener('click', function(){loadCashLedgers(true);});
|
||||||
|
const companySelect = document.getElementById('cash-tally-company');
|
||||||
|
if (companySelect) companySelect.addEventListener('change', function(){
|
||||||
|
ledgerSelect.innerHTML = '<option value="">Load and confirm cash ledger</option>';
|
||||||
|
ledgerHelp.textContent = this.value ? 'Company changed. Click Load to use that company's cached ledgers, or Refresh from Tally to re-sync.' : 'Select an open Tally company first.';
|
||||||
|
ledgerProgress.classList.add('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
overlay.classList.remove('hidden');
|
overlay.classList.remove('hidden');
|
||||||
@@ -366,6 +386,10 @@
|
|||||||
if (!form.reportValidity()) return;
|
if (!form.reportValidity()) return;
|
||||||
const fd = new FormData(form);
|
const fd = new FormData(form);
|
||||||
fd.set('csrf_token', document.getElementById('cash-csrf-token').value);
|
fd.set('csrf_token', document.getElementById('cash-csrf-token').value);
|
||||||
|
const selectedCompany = document.getElementById('cash-tally-company');
|
||||||
|
const selectedCompanyOption = selectedCompany && selectedCompany.options[selectedCompany.selectedIndex];
|
||||||
|
const selectedCompanyName = selectedCompanyOption ? String(selectedCompanyOption.dataset.companyName || selectedCompanyOption.textContent || '').replace(' • Mapped','').replace(' • Mapped (not open)','').trim() : '';
|
||||||
|
if (selectedCompanyName) fd.set('company_name', selectedCompanyName);
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
show();
|
show();
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import io
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
ERP_LOCAL_AGENT_VERSION = "1.22.16"
|
ERP_LOCAL_AGENT_VERSION = "1.22.17"
|
||||||
ERP_LOCAL_AGENT_NAME = "ERP Local Agent"
|
ERP_LOCAL_AGENT_NAME = "ERP Local Agent"
|
||||||
RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime"
|
RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime"
|
||||||
_DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0)
|
_DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0)
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
__version__ = "1.22.16"
|
__version__ = "1.22.17"
|
||||||
AGENT_NAME = "ERP Local Agent"
|
AGENT_NAME = "ERP Local Agent"
|
||||||
|
|||||||
@@ -174,6 +174,7 @@ class AgentCommandProcessor:
|
|||||||
"cash_payment_dual_progress_capability": True,
|
"cash_payment_dual_progress_capability": True,
|
||||||
"cash_payment_async_ledger_master_capability": True,
|
"cash_payment_async_ledger_master_capability": True,
|
||||||
"cash_payment_ledger_cache_capability": True,
|
"cash_payment_ledger_cache_capability": True,
|
||||||
|
"cash_payment_open_company_selection_capability": True,
|
||||||
"opening_balance_balance_sheet_only_capability": True,
|
"opening_balance_balance_sheet_only_capability": True,
|
||||||
"tally_writeback_capability": True,
|
"tally_writeback_capability": True,
|
||||||
}
|
}
|
||||||
@@ -518,7 +519,7 @@ class AgentCommandProcessor:
|
|||||||
def _resolve_open_company(self, payload: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
def _resolve_open_company(self, payload: dict[str, Any]) -> tuple[dict[str, Any], str]:
|
||||||
requested_guid = str(payload.get("tally_guid") or "").strip()
|
requested_guid = str(payload.get("tally_guid") or "").strip()
|
||||||
if not requested_guid:
|
if not requested_guid:
|
||||||
raise ValueError("Mapped Tally company GUID is required.")
|
raise ValueError("Open Tally company GUID is required.")
|
||||||
tally_status = self.tally.status()
|
tally_status = self.tally.status()
|
||||||
if not tally_status.get("connected"):
|
if not tally_status.get("connected"):
|
||||||
raise ValueError(str(tally_status.get("error") or "TallyPrime is not connected."))
|
raise ValueError(str(tally_status.get("error") or "TallyPrime is not connected."))
|
||||||
@@ -801,7 +802,7 @@ class AgentCommandProcessor:
|
|||||||
client_id = int(payload.get("client_id"))
|
client_id = int(payload.get("client_id"))
|
||||||
tally_guid = str(payload.get("tally_guid") or "").strip()
|
tally_guid = str(payload.get("tally_guid") or "").strip()
|
||||||
if not tally_guid:
|
if not tally_guid:
|
||||||
raise ValueError("Mapped Tally company GUID is required.")
|
raise ValueError("Open Tally company GUID is required.")
|
||||||
company_name = str(payload.get("company_name") or "").strip()
|
company_name = str(payload.get("company_name") or "").strip()
|
||||||
cached = self._cash_payment_cached_ledgers(client_id, tally_guid)
|
cached = self._cash_payment_cached_ledgers(client_id, tally_guid)
|
||||||
if cached:
|
if cached:
|
||||||
@@ -827,7 +828,7 @@ class AgentCommandProcessor:
|
|||||||
client_id = int(payload.get("client_id"))
|
client_id = int(payload.get("client_id"))
|
||||||
tally_guid = str(payload.get("tally_guid") or "").strip()
|
tally_guid = str(payload.get("tally_guid") or "").strip()
|
||||||
if not tally_guid:
|
if not tally_guid:
|
||||||
raise ValueError("Mapped Tally company GUID is required.")
|
raise ValueError("Open Tally company GUID is required.")
|
||||||
expected_company_name = str(payload.get("company_name") or "").strip()
|
expected_company_name = str(payload.get("company_name") or "").strip()
|
||||||
self._ensure_cash_ledger_schema(client_id)
|
self._ensure_cash_ledger_schema(client_id)
|
||||||
|
|
||||||
@@ -891,12 +892,12 @@ class AgentCommandProcessor:
|
|||||||
with self.store.connect(client_id) as db:
|
with self.store.connect(client_id) as db:
|
||||||
db.execute(
|
db.execute(
|
||||||
"UPDATE cash_payment_ledger_jobs SET status='running',stage=?,percent=? WHERE job_id=?",
|
"UPDATE cash_payment_ledger_jobs SET status='running',stage=?,percent=? WHERE job_id=?",
|
||||||
("Validating mapped company with Tally", 8, job_id),
|
("Validating selected open company with Tally", 8, job_id),
|
||||||
)
|
)
|
||||||
db.commit()
|
db.commit()
|
||||||
_cash_progress_snapshot({
|
_cash_progress_snapshot({
|
||||||
"job_id": job_id, "job_kind": "ledger_master", "status": "running",
|
"job_id": job_id, "job_kind": "ledger_master", "status": "running",
|
||||||
"stage": "Validating mapped company with Tally", "percent": 8,
|
"stage": "Validating selected open company with Tally", "percent": 8,
|
||||||
"company_name": company_name, "ledger_count": 0,
|
"company_name": company_name, "ledger_count": 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1127,7 +1128,7 @@ class AgentCommandProcessor:
|
|||||||
date_from = str(payload.get("date_from") or "").strip()
|
date_from = str(payload.get("date_from") or "").strip()
|
||||||
date_to = str(payload.get("date_to") or "").strip()
|
date_to = str(payload.get("date_to") or "").strip()
|
||||||
if not tally_guid:
|
if not tally_guid:
|
||||||
raise ValueError("Select a mapped Tally company before starting extraction.")
|
raise ValueError("Select an open Tally company before starting extraction.")
|
||||||
selected_cash_ledgers = [str(x or "").strip() for x in (payload.get("cash_ledger_names") or []) if str(x or "").strip()]
|
selected_cash_ledgers = [str(x or "").strip() for x in (payload.get("cash_ledger_names") or []) if str(x or "").strip()]
|
||||||
single_cash_ledger = str(payload.get("cash_ledger_name") or "").strip()
|
single_cash_ledger = str(payload.get("cash_ledger_name") or "").strip()
|
||||||
if single_cash_ledger and single_cash_ledger not in selected_cash_ledgers:
|
if single_cash_ledger and single_cash_ledger not in selected_cash_ledgers:
|
||||||
@@ -1224,10 +1225,19 @@ class AgentCommandProcessor:
|
|||||||
if not self.store.exists(client_id):
|
if not self.store.exists(client_id):
|
||||||
raise ValueError("Accounting local storage is not initialized for this client.")
|
raise ValueError("Accounting local storage is not initialized for this client.")
|
||||||
self._ensure_cash_cache_schema(client_id)
|
self._ensure_cash_cache_schema(client_id)
|
||||||
mapping = self.store.get_active_mapping_by_guid(client_id, tally_guid)
|
mapping = self.store.get_active_mapping_by_guid(client_id, tally_guid) or {}
|
||||||
company_name = str(mapping.get("company_name") or "").strip()
|
company_name = str(payload.get("company_name") or mapping.get("company_name") or "").strip()
|
||||||
if not company_name:
|
if not company_name:
|
||||||
raise ValueError("The mapped Tally company name is not available in local accounting storage. Refresh the Tally mapping first.")
|
# Read-only cash compliance may work against any company that is currently
|
||||||
|
# open in TallyPrime. Do not create or alter the client's permanent mapping.
|
||||||
|
company, live_company_name = self._resolve_open_company(payload)
|
||||||
|
company_name = live_company_name
|
||||||
|
mapping = {
|
||||||
|
"tally_guid": str(company.get("guid") or tally_guid),
|
||||||
|
"company_name": company_name,
|
||||||
|
"gstin": str(company.get("gstin") or ""),
|
||||||
|
"transient_open_company": True,
|
||||||
|
}
|
||||||
|
|
||||||
# Reuse a paused/interrupted identical cache only inside the worker.
|
# Reuse a paused/interrupted identical cache only inside the worker.
|
||||||
with self.store.connect(client_id) as db:
|
with self.store.connect(client_id) as db:
|
||||||
|
|||||||
Reference in New Issue
Block a user