diff --git a/app/modules/documents/agent_package.py b/app/modules/documents/agent_package.py index 34b52ba..26e38f7 100644 --- a/app/modules/documents/agent_package.py +++ b/app/modules/documents/agent_package.py @@ -4,7 +4,7 @@ import io from pathlib import Path import zipfile -ERP_LOCAL_AGENT_VERSION = "1.26.6" +ERP_LOCAL_AGENT_VERSION = "1.26.7" ERP_LOCAL_AGENT_NAME = "ERP Local Agent" RUNTIME_ROOT = Path(__file__).resolve().parent / "local_agent_runtime" _DETERMINISTIC_ZIP_TIMESTAMP = (2026, 1, 1, 0, 0, 0) diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/__init__.py b/app/modules/documents/local_agent_runtime/erp_local_agent/__init__.py index 7bfe20b..50fd0d1 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/__init__.py +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/__init__.py @@ -1,2 +1,2 @@ -__version__ = "1.26.6" +__version__ = "1.26.7" AGENT_NAME = "ERP Local Agent" diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/accounting_mirror.py b/app/modules/documents/local_agent_runtime/erp_local_agent/accounting_mirror.py index 815cd03..8cfc2f2 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/accounting_mirror.py +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/accounting_mirror.py @@ -317,6 +317,10 @@ class AccountingMirrorEngine: "COMPANY - ROWS READ:": (14, "Company read"), "LEDGER MASTER - BEFORE QUERY": (15, "Reading ledgers"), "LEDGER MASTER - ROWS READ:": (25, "Ledgers read"), + "GROUP MASTER - BEFORE QUERY": (91, "Reading group/subgroup hierarchy"), + "GROUP MASTER NAME/PARENT - BEFORE QUERY": (91, "Reading group/subgroup hierarchy"), + "GROUP MASTER COMPAT - BEFORE QUERY": (91, "Reading group/subgroup hierarchy"), + "GROUP SUMMARY": (93, "Group/subgroup hierarchy completed"), "STOCK MASTER - BEFORE QUERY": (26, "Reading stock items"), "STOCK MASTER - ROWS READ:": (34, "Stock items read"), "STOCK HSN MASTER - BEFORE QUERY": (35, "Reading HSN details"), diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_0_1.tdl b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_0_1.tdl index 178b838..81d5237 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_0_1.tdl +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_0_1.tdl @@ -19,11 +19,6 @@ Fetch : Name, Parent, GUID, AlterID, OpeningBalance, ClosingBalance, IsRevenue, PartyGSTIN, GSTRegistrationType Is ODBC Table : Yes -[Collection : ERPAMGroupMaster] - Type : Group - Fetch : Name, Parent, GUID - Is ODBC Table : Yes - [Collection : ERPAMStockMaster] Type : StockItem Fetch : Name, Parent, GUID, AlterID, BaseUnits, OpeningBalance, OpeningValue, GSTApplicable, GSTRepUoM, GSTTypeofSupply, GSTItemHSNCodeEx diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV301.cs b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV301.cs index 2286f5b..d4f49cd 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV301.cs +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV301.cs @@ -58,6 +58,74 @@ class TallyAccountingMirrorV301 Console.Out.Flush(); } + static bool TryExtractFresh(string dsn, string label, string sql, string path, + out int rows, out double sec) + { + rows = 0; + sec = 0; + try { + using (var fresh = new OdbcConnection("DSN=" + dsn + ";")) { + fresh.Open(); + Extract(fresh, label, sql, path, out rows, out sec); + } + return true; + } + catch(Exception ex) { + Console.WriteLine(label + " - OPTIONAL QUERY FAILED"); + Console.WriteLine(label + " - ERROR TYPE: " + ex.GetType().FullName); + Console.WriteLine(label + " - ERROR: " + ex.Message); + if(ex.InnerException != null) + Console.WriteLine(label + " - INNER: " + ex.InnerException.Message); + Console.Out.Flush(); + return false; + } + } + + static void WriteEmptyGroupCsv(string path) + { + using (var w = new StreamWriter(path, false, new UTF8Encoding(true))) { + w.WriteLine("GUID,Name,Parent"); + } + } + + static bool ExtractGroupHierarchy(string dsn, string outDir, + out int groupRows, out double groupSec) + { + groupRows = 0; + groupSec = 0; + string path = Path.Combine(outDir, "group_master.csv"); + + // Tally's built-in ODBC Groups table is queried on its own connection. + // This deliberately avoids a custom Group TDL collection and protects + // the proven Ledger/Voucher extraction connection from being disabled. + if (TryExtractFresh( + dsn, "GROUP MASTER", + "SELECT $GUID,$Name,$Parent FROM Groups", + path, out groupRows, out groupSec) && groupRows > 0) + return true; + + // Some builds expose the table but not GUID. Name + Parent are all the + // ERP needs for recursive Fixed Assets / Capital hierarchy traversal. + if (TryExtractFresh( + dsn, "GROUP MASTER NAME/PARENT", + "SELECT $Name,$Parent FROM Groups", + path, out groupRows, out groupSec) && groupRows > 0) + return true; + + // Last compatibility attempt: singular built-in collection/table name, + // again on a NEW connection so a rejected query cannot poison the core. + if (TryExtractFresh( + dsn, "GROUP MASTER COMPAT", + "SELECT $GUID,$Name,$Parent FROM Group", + path, out groupRows, out groupSec) && groupRows > 0) + return true; + + WriteEmptyGroupCsv(path); + Console.WriteLine("GROUP MASTER - NO GROUP ROWS EXTRACTED; CORE MIRROR DATA REMAINS VALID"); + Console.Out.Flush(); + return false; + } + static int Main(string[] args) { string dsn="TallyODBC64_9000", outDir="mirror_output_v3_0_1"; @@ -69,6 +137,8 @@ class TallyAccountingMirrorV301 try { var total=Stopwatch.StartNew(); + int groupRows = 0; + double groupSec = 0; Console.WriteLine("ERP ACCOUNTING MIRROR v3.0.1 - ERP INTEGRATION CANDIDATE"); Console.WriteLine("READ ONLY | ODBC | NO XML | NO TALLY WRITES"); Console.WriteLine("BEFORE CONNECT"); @@ -88,13 +158,6 @@ class TallyAccountingMirrorV301 "SELECT $GUID,$AlterID,$Name,$Parent,$OpeningBalance,$ClosingBalance,$IsRevenue,$PartyGSTIN,$GSTRegistrationType FROM ERPAMLedgerMaster", Path.Combine(outDir,"ledger_master.csv"),out l,out sl); - // Group hierarchy only. Ledger extraction above is intentionally - // the same proven ERPAMLedgerMaster path used before. - int groupRows; double groupSec; - Extract(cn,"GROUP MASTER", - "SELECT $GUID,$Name,$Parent FROM ERPAMGroupMaster", - Path.Combine(outDir,"group_master.csv"),out groupRows,out groupSec); - Extract(cn,"STOCK MASTER", "SELECT $GUID,$AlterID,$Name,$Parent,$BaseUnits,$OpeningBalance,$OpeningValue,$GSTApplicable,$GSTRepUoM,$GSTTypeofSupply,$GSTItemHSNCodeEx FROM ERPAMStockMaster", Path.Combine(outDir,"stock_master.csv"),out s,out ss); @@ -132,9 +195,8 @@ class TallyAccountingMirrorV301 "SELECT $VoucherGUID,$VoucherAlterID,$VoucherMasterID,$VoucherDate,$VoucherType,$VoucherNumber,$PartyLedger,$StockItemName,$HSNCode,$BilledQty,$ActualQty,$Rate,$IsDeemedPositive,$InventoryAmount FROM ERPAMInventoryMovement", Path.Combine(outDir,"inventory_movement.csv"),out im,out sim); - Console.WriteLine("SUMMARY | Company="+c+ + Console.WriteLine("CORE SUMMARY | Company="+c+ " | Ledger="+l+ - " | Group="+groupRows+ " | Stock="+s+ " | StockHSN="+tax+" | StockGST="+gstRows+ " | Voucher="+v+ @@ -143,6 +205,12 @@ class TallyAccountingMirrorV301 " | TotalSeconds="+total.Elapsed.TotalSeconds.ToString("0.000")); } + // Read only Group -> Parent hierarchy after all proven core reads have + // completed and the original connection has been disposed. + ExtractGroupHierarchy(dsn, outDir, out groupRows, out groupSec); + Console.WriteLine("GROUP SUMMARY | Rows="+groupRows+ + " | Seconds="+groupSec.ToString("0.000")); + Console.WriteLine("SUCCESS"); return 0; }