# tally-to-xml-tdl — Guide Deep reference for how the library works internally and how to extend it. ← **[Back to README](../README.md)** • 🌐 **[Live HTML Guide](https://keshavsoft.github.io/tally-to-xml-tdl/guide.html)** • 🌐 **[Live Docs Home](https://keshavsoft.github.io/tally-to-xml-tdl/)** --- ## Table of contents - [Architecture](#architecture) - [The XML template](#the-xml-template) - [How TDL queries work](#how-tdl-queries-work) - [Core modules](#core-modules) - [Adding a new master query](#adding-a-new-master-query) - [Adding a new voucher type](#adding-a-new-voucher-type) - [Error handling](#error-handling) --- ## Architecture The library is organised into three layers: ``` src/v6/ body.xml ← shared XML request template company/ ← list open companies masters/ ← master data (stock, ledger, units ...) vouchers/ purchases/ ← purchase vouchers sales/ ← sales vouchers core/ buildXml.js ← fills the template transport/ ← HTTP POST to Tally response/ ← XML → JSON execute/ ← orchestrates the three steps ``` Every module (company, masters, vouchers) follows the same pattern: 1. Read `body.xml` once at module load time (`fs.readFileSync`) 2. Call `buildXml(body, { staticVariables, tdlMessage })` to fill the template 3. Call `executeXml(xml)` which sends the XML and returns parsed JSON --- ## The XML template `src/v6/body.xml` is a standard Tally HTTP export envelope with two placeholders: ```xml
Export Collection TDLID
$$SysName:XML {{STATICVARIABLES}} {{TDLMESSAGE}}
``` `buildXml` does a simple string replace: ```js body .replace("{{STATICVARIABLES}}", staticVariables) .replace("{{TDLMESSAGE}}", tdlMessage) ``` `staticVariables` carries context Tally needs before the query (company, dates). `tdlMessage` is the actual TDL collection definition (what to fetch). --- ## How TDL queries work Tally's HTTP API accepts a `` block inside TDL. The `TYPE` tag is the Tally object type, and `FETCH` tags select which fields to include. **Example — fetch ledger names with GSTIN:** ```xml Ledger $$Alias:Name GSTRegistrationType GSTIN ``` This maps to the `"ledgerNamesWithDetails"` key in `masters.json`: ```json { "ledgerNamesWithDetails": { "staticVariables": "$$SysName:XML", "tdlMessage": "Ledger$$Alias:NameGSTRegistrationTypeGSTIN" } } ``` **Example — purchase vouchers with inventory entries:** ```xml Vouchers:VoucherType $$$$VchTypePurchase Yes AllInventoryEntries Date ``` `$$$$VchTypePurchase` is Tally's built-in formula for the Purchase voucher type. `CHILDOF` + `BELONGSTO` filters the collection to only purchase-type vouchers. --- ## Core modules ### `buildXml(body, { staticVariables, tdlMessage })` Pure string replace. No side effects. ```js import { buildXml } from "tally-to-xml-tdl/src/v6/core/buildXml.js"; const xml = buildXml(body, { staticVariables: "MyCompany", tdlMessage: "Ledger$$Alias:Name" }); ``` --- ### `sendXml({ xml, url })` HTTP POST to Tally. Returns raw XML response string. ```js import { sendXml } from "tally-to-xml-tdl/src/v6/core/transport/http.js"; const rawXml = await sendXml({ xml, url: "http://localhost:9000" }); ``` --- ### `xmlToJson(xml)` Wraps `fast-xml-parser`. Returns a plain JavaScript object. ```js import { xmlToJson } from "tally-to-xml-tdl/src/v6/core/response/xmlToJson.js"; const json = xmlToJson(rawXml); ``` --- ### `executeXml(xml)` Combines `sendXml` + `xmlToJson`. This is what every public API call uses. ```js import { executeXml } from "tally-to-xml-tdl/src/v6/core/execute/executeXml.js"; const json = await executeXml(xml); ``` --- ## Adding a new master query 1. Open `src/v6/masters/masters.json` 2. Add an entry with a `tdlMessage` (and optional `staticVariables`): ```json { "costCentres": { "staticVariables": "$$SysName:XML", "tdlMessage": "CostCentre$$Alias:Name" } } ``` 3. Call it: ```js const result = await masters.get("My Company", "costCentres"); ``` That is the entire change. No code to write. --- ## Adding a new voucher type 1. Create a folder: `src/v6/vouchers/receipts/` 2. Add `info.json` with your TDL query 3. Add `index.js` following the same structure as `purchases/index.js` 4. Export it from `src/v6/vouchers/index.js`: ```js export * as receipts from "./receipts/index.js"; ``` --- ## Error handling The library does not catch or wrap errors. If Tally is not running, `fetch` will throw a `TypeError: fetch failed`. Handle it in your code: ```js try { const result = await masters.get("My Company", "stockItems"); } catch (err) { if (err.cause?.code === "ECONNREFUSED") { console.error("Tally is not running or HTTP port is not enabled."); } else { throw err; } } ``` Common causes: | Error | Cause | |---|---| | `ECONNREFUSED` | Tally not running, or HTTP port disabled | | `ECONNRESET` | Tally closed the connection mid-response | | Empty `COLLECTION` | Company name mismatch or no data for the date range |