From 6411cb14fa66732a2d299f3115d13edfa3f438db Mon Sep 17 00:00:00 2001 From: A R R R Associates Date: Sun, 6 Sep 2026 17:59:34 +0530 Subject: [PATCH] Repair accounting mirror TDL and add stable TDL link --- app/modules/documents/agent_package.py | 4 +- .../erp_local_agent/__init__.py | 2 +- .../erp_local_agent/accounting_mirror.py | 16 ++--- .../erp_local_agent/dashboard.py | 72 ++++++++++++++++++- .../ERP_Accounting_Mirror_v3_1.tdl | 42 ----------- .../TallyAccountingMirrorV31.cs | 59 ++------------- .../erp_local_agent/mirror_tally.py | 22 +++++- 7 files changed, 106 insertions(+), 111 deletions(-) diff --git a/app/modules/documents/agent_package.py b/app/modules/documents/agent_package.py index 24f043a..ea565de 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.24.1" +ERP_LOCAL_AGENT_VERSION = "1.24.2" 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) @@ -65,7 +65,7 @@ def _build_zip(*, env_text: str | None, include_env: bool, include_admin_readme: text = ( f"ERP Local Agent {ERP_LOCAL_AGENT_VERSION}\n" "Existing storage, WebSocket tunnel, dashboard, Tally mapping and client .act functionality are preserved.\n" - "Existing master/transaction sync and depreciation are preserved. Phase 5 adds neutral historical-ledger evidence read capability for server-side learning.\n" + "Existing master/transaction sync, accounting tools and controlled write-back are preserved.\nAccounting Mirror uses the proven v3.0.1 ODBC runtime for ledgers, vouchers, stock movement, HSN and GST rates.\nTally TDL is exposed through a stable local path and localhost URL so later agent updates can repair/replace the TDL without changing the Tally link.\n" "Dashboard: http://127.0.0.1:8788\nDesktop dashboard is single-instance: repeated shortcut clicks focus the existing window without starting another Local Agent.\nUpdate dashboard shows check, download, install, restart and completion progress.\n" ) _write_zip_bytes(dst, "README_ERP_LOCAL_AGENT.txt", text.encode("utf-8")) 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 be00b9f..9e1022d 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.24.1" +__version__ = "1.24.2" 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 269152a..7e67b09 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 @@ -14,7 +14,7 @@ import subprocess import sys from typing import Any -MIRROR_SCHEMA_VERSION = "3.1" +MIRROR_SCHEMA_VERSION = "3.0.1" DEFAULT_DSN = "TallyODBC64_9000" def _utc_now() -> str: @@ -64,9 +64,9 @@ class AccountingMirrorEngine: current_mirror=accounting_db.with_name(f"{stem}_mirror.act"), cache_root=cache_root, work_root=cache_root / "sync_work", - extractor_exe=runtime_dir / "TallyAccountingMirrorV31.exe", - tdl_file=self.runtime_root / "ERP_Accounting_Mirror_v3_1.tdl", - loader_file=self.runtime_root / "build_act_v3_1.py", + extractor_exe=runtime_dir / "TallyAccountingMirrorV301.exe", + tdl_file=self.runtime_root / "ERP_Accounting_Mirror_v3_0_1.tdl", + loader_file=self.runtime_root / "build_act_v3_0_1.py", ) @staticmethod @@ -81,7 +81,7 @@ class AccountingMirrorEngine: raise RuntimeError("Microsoft .NET Framework 4.x C# compiler was not found.") def _ensure_extractor(self, paths: MirrorPaths) -> None: - source = self.runtime_root / "TallyAccountingMirrorV31.cs" + source = self.runtime_root / "TallyAccountingMirrorV301.cs" rebuild = not paths.extractor_exe.is_file() if not rebuild: try: @@ -227,7 +227,7 @@ class AccountingMirrorEngine: self._ensure_extractor(paths) shutil.rmtree(paths.work_root, ignore_errors=True) paths.work_root.mkdir(parents=True, exist_ok=True) - output_dir = paths.work_root / "mirror_output_v3_1" + output_dir = paths.work_root / "mirror_output_v3_0_1" cp = subprocess.run( [str(paths.extractor_exe), "--dsn", dsn or DEFAULT_DSN, "--out", str(output_dir)], capture_output=True, text=True, timeout=max(60, int(timeout_seconds)) @@ -237,7 +237,7 @@ class AccountingMirrorEngine: if cp.returncode != 0: raise RuntimeError("Accounting Mirror ODBC extraction failed: " + log[-4000:]) - loader_copy = paths.work_root / "build_act_v3_1.py" + loader_copy = paths.work_root / "build_act_v3_0_1.py" shutil.copy2(paths.loader_file, loader_copy) lp = subprocess.run( [sys.executable, str(loader_copy), "--source", output_dir.name], @@ -249,7 +249,7 @@ class AccountingMirrorEngine: if lp.returncode != 0: raise RuntimeError("Accounting Mirror SQLite build failed: " + llog[-4000:]) - # Loader v3.0.1 writes this name even when invoked as v3.1. + # Proven v3.0.1 loader output. candidate = output_dir / "accounting_mirror_v3_0_1.act" if not candidate.is_file(): raise RuntimeError("Accounting Mirror database was not produced.") diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/dashboard.py b/app/modules/documents/local_agent_runtime/erp_local_agent/dashboard.py index c0d8657..c2c558c 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/dashboard.py +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/dashboard.py @@ -1,5 +1,6 @@ from __future__ import annotations +import hashlib import json import shutil import threading @@ -22,9 +23,56 @@ class AgentDashboard: self.install_dir = Path(install_dir).resolve() self.server: ThreadingHTTPServer | None = None + @staticmethod + def _sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + def _embedded_tdl(self) -> Path: + preferred = self.install_dir / "erp_local_agent" / "mirror_runtime" / "ERP_Accounting_Mirror_v3_0_1.tdl" + if preferred.is_file(): + return preferred + compatibility = self.install_dir / "erp_local_agent" / "mirror_runtime" / "ERP_Accounting_Mirror_v3_1.tdl" + if compatibility.is_file(): + return compatibility + raise RuntimeError("ERP Accounting Mirror TDL is missing from the Local Agent runtime.") + + def _managed_tdl(self) -> Path: + return self.install_dir / "tally" / "ERP_Accounting_Mirror.tdl" + + def _ensure_managed_tdl(self, force: bool = False) -> dict[str, Any]: + source = self._embedded_tdl() + target = self._managed_tdl() + target.parent.mkdir(parents=True, exist_ok=True) + source_hash = self._sha256(source) + target_hash = self._sha256(target) if target.is_file() else "" + repaired = False + if force or source_hash != target_hash: + temp = target.with_suffix(".tdl.new") + shutil.copy2(source, temp) + temp.replace(target) + target_hash = self._sha256(target) + repaired = True + return { + "version": "3.0.1", + "path": str(target), + "url": f"http://{self.config.dashboard_host}:{self.config.dashboard_port}/tally/ERP_Accounting_Mirror.tdl", + "sha256": target_hash, + "source_path": str(source), + "repaired": repaired, + "exists": target.is_file(), + } + def start(self) -> None: if not self.config.dashboard_enabled: return + try: + self._ensure_managed_tdl() + except Exception as exc: + self.logger.warning("Could not prepare managed Tally TDL: %s", exc) dashboard = self class Handler(BaseHTTPRequestHandler): @@ -58,6 +106,17 @@ class AgentDashboard: return self._json(dashboard.history()) if self.path.startswith("/api/cash-progress"): return self._json(dashboard.cash_progress()) + if self.path.split("?", 1)[0] == "/tally/ERP_Accounting_Mirror.tdl": + info = dashboard._ensure_managed_tdl() + payload = Path(info["path"]).read_bytes() + self.send_response(HTTPStatus.OK) + self.send_header("Content-Type", "text/plain; charset=utf-8") + self.send_header("Cache-Control", "no-store") + self.send_header("Content-Disposition", 'inline; filename="ERP_Accounting_Mirror.tdl"') + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + return self.send_error(404) def do_POST(self): @@ -76,6 +135,10 @@ class AgentDashboard: status = TallyLiveConnector().status() dashboard.db.record_tally_status(status) return self._json({"ok": True, "tally": status}) + if self.path == "/api/tally/tdl/repair": + info = dashboard._ensure_managed_tdl(force=True) + dashboard.db.record_event("INFO", "tally_tdl_repaired", f"Managed TDL refreshed: {info['path']}") + return self._json({"ok": True, "tdl": info}) self.send_error(404) except Exception as exc: dashboard.logger.exception("Dashboard action failed: %s", exc) @@ -120,6 +183,7 @@ class AgentDashboard: "free_bytes": free, }, "tally": tally, + "tdl": self._ensure_managed_tdl(), "update": self.updater.status(), "dashboard": {"host": self.config.dashboard_host, "port": self.config.dashboard_port}, } @@ -149,7 +213,7 @@ class AgentDashboard: ERP Local Agent

ERP Local Agent

Local dashboard — available only on this computer
@@ -162,6 +226,7 @@ body{font-family:Segoe UI,Arial,sans-serif;background:#f4f6f8;color:#17202a;marg

Tally

Tally is checked locally at 127.0.0.1:9000. Port 9000 is not exposed to the internet.

+

Tally Accounting Mirror TDL

Link Tally once to the stable local path below. Local Agent updates keep this same file path and refresh its contents, so future TDL repairs do not require a new Tally link.

Stable Local TDL Path
Local TDL URL

For Tally's Local TDL setting, use the stable file path if your TallyPrime build does not accept an HTTP URL. The URL is also kept stable for tools that support URL loading.

Recent History

Loading…
@@ -171,13 +236,14 @@ function gb(n){return (n/1073741824).toFixed(1)+' GB'} function setProgress(title,pct,text,active=true){let b=document.getElementById('progressBox');b.style.display='block';document.getElementById('progressTitle').textContent=title;let p=Math.max(0,Math.min(100,Number(pct)||0));lastServerPercent=Math.max(lastServerPercent,p);document.getElementById('progressPct').textContent=Math.round(p)+'%';document.getElementById('progressFill').style.width=p+'%';document.getElementById('progressMsg').textContent=text||'';document.getElementById('progressFill').className='progressfill'+(active&&p<100?' pulse':'')} function applyProgress(u){let p=(u&&u.progress)||{};if(!p.operation)return;let title=p.operation==='check'?'Checking for Updates':p.operation==='download'?'Downloading Update':'Applying Update';setProgress(title,p.percent||0,p.message||p.phase||'',!['updated','downloaded','current','available','error'].includes(p.status));if(p.operation==='install'&&p.target_version){installTarget=p.target_version}} function setCashStep(id,state){let e=document.getElementById(id);e.className='cashstep'+(state?' '+state:'')} -async function refreshCashProgress(){try{const r=await fetch('/api/cash-progress',{cache:'no-store'});const d=await r.json();const j=d.job||{};if(!j.job_id){document.getElementById('cashJobSection').style.display='none';return}document.getElementById('cashJobSection').style.display='block';let p=Math.max(0,Math.min(100,Number(j.percent)||0));document.getElementById('cashJobPct').textContent=Math.round(p)+'%';document.getElementById('cashJobFill').style.width=p+'%';document.getElementById('cashJobStage').textContent=j.stage||j.status||'Working…';let kind=String(j.job_kind||'');let isLedger=(kind==='ledger_master'||kind==='cash_ledger_discovery');document.querySelector('#cashJobSection h2').textContent=isLedger?'Cash Payment — Tally Ledger Sync':'Cash Payment Compliance';document.getElementById('cashJobSub').textContent=(j.company_name||'Tally company')+(j.cash_ledgers&&j.cash_ledgers.length?' • Cash ledger: '+j.cash_ledgers.join(', '):'');if(isLedger){document.getElementById('cashDays').parentElement.querySelector('.label').textContent='Ledgers';document.getElementById('cashDays').textContent=String(j.ledger_count||0);document.getElementById('cashVouchers').parentElement.querySelector('.label').textContent='Status';document.getElementById('cashVouchers').textContent=j.status||'working';document.getElementById('cashRequests').parentElement.querySelector('.label').textContent='Progress';document.getElementById('cashRequests').textContent=Math.round(p)+'%';document.getElementById('cashDate').parentElement.querySelector('.label').textContent='Source';document.getElementById('cashDate').textContent=(kind==='cash_ledger_discovery'?'Cash-in-Hand':'Tally ledger master');}else{document.getElementById('cashDays').parentElement.querySelector('.label').textContent='Days';document.getElementById('cashDays').textContent=String(j.completed_days||0)+' / '+String(j.total_days||0);document.getElementById('cashVouchers').parentElement.querySelector('.label').textContent='Cash vouchers';document.getElementById('cashVouchers').textContent=String(j.vouchers_cached||0);document.getElementById('cashRequests').parentElement.querySelector('.label').textContent='Tally requests';document.getElementById('cashRequests').textContent=String(j.tally_requests||0);document.getElementById('cashDate').parentElement.querySelector('.label').textContent='Current date';document.getElementById('cashDate').textContent=j.current_date||'—';}let st=String(j.stage||'').toLowerCase(),status=String(j.status||'').toLowerCase();if(isLedger){setCashStep('cs1',(p>=15?'done':(p>0?'run':'')));setCashStep('cs2','');setCashStep('cs3','');setCashStep('cs4','');setCashStep('cs5','');}else{setCashStep('cs1',(p>=10?'done':(p>0?'run':'')));setCashStep('cs2',(p>=20?'done':(st.includes('ledger')?'run':'')));setCashStep('cs3',(p>=93?'done':(p>=20?'run':'')));setCashStep('cs4',(status==='completed'?'done':(st.includes('analys')?'run':'')));setCashStep('cs5',(status==='completed'?'done':''));}let er=document.getElementById('cashError');if(j.error){er.style.display='block';er.textContent=j.error}else{er.style.display='none'}}catch(e){}} +async function refreshCashProgress(){try{const r=await fetch('/api/cash-progress',{cache:'no-store'});const d=await r.json();const j=d.job||{};if(!j.job_id){document.getElementById('cashJobSection').style.display='none';return}document.getElementById('cashJobSection').style.display='block';let p=Math.max(0,Math.min(100,Number(j.percent)||0));document.getElementById('cashJobPct').textContent=Math.round(p)+'%';document.getElementById('cashJobFill').style.width=p+'%';document.getElementById('cashJobStage').textContent=j.stage||j.status||'Working…';document.getElementById('cashJobSub').textContent=(j.company_name||'Tally company')+(j.cash_ledgers&&j.cash_ledgers.length?' • Cash ledger: '+j.cash_ledgers.join(', '):'');document.getElementById('cashDays').textContent=String(j.completed_days||0)+' / '+String(j.total_days||0);document.getElementById('cashVouchers').textContent=String(j.vouchers_cached||0);document.getElementById('cashRequests').textContent=String(j.tally_requests||0);document.getElementById('cashDate').textContent=j.current_date||'—';let st=String(j.stage||'').toLowerCase(),status=String(j.status||'').toLowerCase();setCashStep('cs1',(p>=10?'done':(p>0?'run':'')));setCashStep('cs2',(p>=20?'done':(st.includes('ledger')?'run':'')));setCashStep('cs3',(p>=93?'done':(p>=20?'run':'')));setCashStep('cs4',(status==='completed'?'done':(st.includes('analys')?'run':'')));setCashStep('cs5',(status==='completed'?'done':''));let er=document.getElementById('cashError');if(j.error){er.style.display='block';er.textContent=j.error}else{er.style.display='none'}}catch(e){}} async function refresh(){try{const r=await fetch('/api/status',{cache:'no-store'});if(!r.ok)throw new Error('status unavailable');const s=await r.json();offlineTicks=0; let c=s.agent.connection_state||'unknown';let ce=document.getElementById('connection');ce.textContent=c.charAt(0).toUpperCase()+c.slice(1);ce.className='value '+(c==='connected'?'ok':'bad'); document.getElementById('heartbeat').textContent=s.agent.last_heartbeat_utc?'Last heartbeat: '+s.agent.last_heartbeat_utc:'No heartbeat recorded'; document.getElementById('version').textContent=s.agent.version;document.getElementById('latest').textContent='Latest: '+s.update.latest_version+(s.update.update_available?' • update available':' • current'); let te=document.getElementById('tally');let known=s.tally.connected!==null;te.textContent=!known?'Not checked':(s.tally.connected?'Connected':'Offline');te.className='value '+(!known?'warn':(s.tally.connected?'ok':'bad'));document.getElementById('companies').textContent=!known?'Use Test Tally Connection':(s.tally.connected?(s.tally.company_count+' loaded compan'+(s.tally.company_count===1?'y':'ies')):(s.tally.error||'')); document.getElementById('storage').textContent=gb(s.storage.free_bytes);document.getElementById('storageRoot').textContent=s.storage.root; +if(s.tdl){document.getElementById('tdlPath').value=s.tdl.path||'';document.getElementById('tdlUrl').value=s.tdl.url||'';document.getElementById('tdlMeta').textContent='Mirror '+(s.tdl.version||'')+' • SHA256 '+String(s.tdl.sha256||'').slice(0,16)+'…'+(s.tdl.repaired?' • refreshed now':'');} document.getElementById('check').disabled=!!s.update.busy;document.getElementById('download').disabled=!s.update.update_available||!!s.update.busy;document.getElementById('install').disabled=!s.update.downloaded||!!s.update.busy;applyProgress(s.update); if(installWatching&&installTarget&&s.agent.version===installTarget){setProgress('Update Complete',100,'ERP Local Agent '+installTarget+' is running. Updated dashboard loaded.',false);msg('Update completed successfully.',true);installWatching=false;setTimeout(()=>location.reload(),1200)} await refreshHistory();await refreshCashProgress();}catch(e){if(installWatching){offlineTicks++;let estimated=Math.min(92,Math.max(lastServerPercent,35+offlineTicks*3));setProgress('Applying Update',estimated,'Local Agent is restarting. Waiting for the updated dashboard to come back online…',true)}else{console.log(e)}}} @@ -187,6 +253,8 @@ async function checkUpdate(){setProgress('Checking for Updates',10,'Checking ERP async function downloadUpdate(){setProgress('Downloading Update',5,'Starting download…',true);msg('Downloading update…',true);try{const r=await fetch('/api/update/download',{method:'POST'});const j=await r.json();if(!r.ok||!j.ok)throw new Error(j.error||'Download failed');msg('Download started. You can keep this dashboard open.',true);await refresh()}catch(e){setProgress('Download Update',100,e.message,false);msg(e.message,false)}} async function action(url){msg('Working…',true);try{const r=await fetch(url,{method:'POST'});const j=await r.json();if(!r.ok||!j.ok)throw new Error(j.error||'Operation failed');msg('Completed successfully.',true);await refresh()}catch(e){msg(e.message,false)}} async function installUpdate(){if(!confirm('Install the downloaded update now? The Local Agent worker will restart safely and this dashboard will show progress until the updated dashboard returns.'))return;let latest=document.getElementById('latest').textContent.replace('Latest: ','').split(' •')[0];installTarget=latest;installWatching=true;offlineTicks=0;lastServerPercent=5;setProgress('Applying Update',5,'Queuing update with the Local Agent supervisor…',true);msg('Starting safe update installation…',true);try{const r=await fetch('/api/update/install',{method:'POST'});const j=await r.json();if(!r.ok||!j.ok)throw new Error(j.error||'Install failed');if(j.target_version)installTarget=j.target_version;msg(j.message||'Update queued. Keep this dashboard open.',true);setProgress('Applying Update',8,'Update queued. Waiting for supervisor…',true)}catch(e){installWatching=false;setProgress('Apply Update',100,e.message,false);msg(e.message,false)}} +async function copyText(id){let e=document.getElementById(id);let v=e.value||'';try{await navigator.clipboard.writeText(v);msg('Copied to clipboard.',true)}catch(err){e.focus();e.select();document.execCommand('copy');msg('Copied to clipboard.',true)}} +async function repairTdl(){msg('Refreshing the managed TDL…',true);try{const r=await fetch('/api/tally/tdl/repair',{method:'POST'});const j=await r.json();if(!r.ok||!j.ok)throw new Error(j.error||'TDL repair failed');msg('TDL refreshed successfully. Restart/reload TDL in TallyPrime if it is already open.',true);await refresh()}catch(e){msg(e.message,false)}} function msg(t,ok){let e=document.getElementById('message');e.textContent=t;e.className=ok?'msgok':'msgbad'} refresh();setInterval(refresh,1000); ''' diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_1.tdl b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_1.tdl index 16838b7..81d5237 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_1.tdl +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/ERP_Accounting_Mirror_v3_1.tdl @@ -163,45 +163,3 @@ ;; ============================================================ ;; END ;; ============================================================ - -;; ================================================================ -;; ACCOUNTING MIRROR v3.1 - ADDITIONAL MASTER COLLECTIONS -;; These are flat read-only ODBC master tables used to replace the -;; former XML master synchronization path. -;; ================================================================ - -[Collection : ERPAMGroupMaster] - Type : Group - Fetch : Name, GUID, Parent, ReservedName, IsRevenue, IsDeemedPositive, IsActive - Is ODBC Table : Yes - -[Collection : ERPAMVoucherTypeMaster] - Type : VoucherType - Fetch : Name, GUID, Parent, NumberingMethod, IsActive - Is ODBC Table : Yes - -[Collection : ERPAMStockGroupMaster] - Type : StockGroup - Fetch : Name, GUID, Parent, BaseUnits, GSTApplicable, GSTTypeofSupply, IsActive - Is ODBC Table : Yes - -[Collection : ERPAMStockCategoryMaster] - Type : StockCategory - Fetch : Name, GUID, Parent, IsActive - Is ODBC Table : Yes - -[Collection : ERPAMUnitMaster] - Type : Unit - Fetch : Name, GUID, OriginalName, IsSimpleUnit, BaseUnits, AdditionalUnits, Conversion - Is ODBC Table : Yes - -[Collection : ERPAMCostCentreMaster] - Type : CostCentre - Fetch : Name, GUID, Parent, IsActive - Is ODBC Table : Yes - -[Collection : ERPAMCostCategoryMaster] - Type : CostCategory - Fetch : Name, GUID, Parent, IsActive - Is ODBC Table : Yes - diff --git a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV31.cs b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV31.cs index 0f35c98..e5b27d8 100644 --- a/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV31.cs +++ b/app/modules/documents/local_agent_runtime/erp_local_agent/mirror_runtime/TallyAccountingMirrorV31.cs @@ -6,7 +6,7 @@ using System.Globalization; using System.IO; using System.Text; -class TallyAccountingMirrorV31 +class TallyAccountingMirrorV301 { static string Safe(object v) { if (v == null || v == DBNull.Value) return ""; @@ -58,29 +58,9 @@ class TallyAccountingMirrorV31 Console.Out.Flush(); } - - static void TryExtract(OdbcConnection cn, string label, string sql, string path, - out int rows, out double sec) - { - try - { - Extract(cn, label, sql, path, out rows, out sec); - } - catch (Exception ex) - { - rows = 0; - sec = 0; - Console.WriteLine(label + " - OPTIONAL QUERY FAILED: " + ex.Message); - using (var w = new StreamWriter(path, false, new UTF8Encoding(true))) - { - w.WriteLine(""); - } - } - } - static int Main(string[] args) { - string dsn="TallyODBC64_9000", outDir="mirror_output_v3_1"; + string dsn="TallyODBC64_9000", outDir="mirror_output_v3_0_1"; for(int i=0;i