@paprflare/tally 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/index.cjs +788 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +478 -0
- package/dist/index.d.ts +478 -0
- package/dist/index.js +750 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var zod = require('zod');
|
|
4
|
+
var fastXmlParser = require('fast-xml-parser');
|
|
5
|
+
|
|
6
|
+
// src/types/result.ts
|
|
7
|
+
function ok(value) {
|
|
8
|
+
return { ok: true, value };
|
|
9
|
+
}
|
|
10
|
+
function err(error) {
|
|
11
|
+
return { ok: false, error };
|
|
12
|
+
}
|
|
13
|
+
function tallyError(code, message, extra) {
|
|
14
|
+
return { code, message, ...extra };
|
|
15
|
+
}
|
|
16
|
+
function unwrap(result) {
|
|
17
|
+
if (result.ok) return result.value;
|
|
18
|
+
const err2 = result.error;
|
|
19
|
+
const e = new Error(`[${err2.code}] ${err2.message}`);
|
|
20
|
+
e.cause = err2.cause ?? err2;
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
var gstinSchema = zod.z.string().regex(
|
|
24
|
+
/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/,
|
|
25
|
+
"Invalid GSTIN format"
|
|
26
|
+
).optional();
|
|
27
|
+
var LedgerInputSchema = zod.z.object({
|
|
28
|
+
name: zod.z.string().min(1),
|
|
29
|
+
/** Tally group name, e.g. "Sundry Debtors", "Sundry Creditors", "Bank Accounts" */
|
|
30
|
+
group: zod.z.string().min(1),
|
|
31
|
+
gstin: gstinSchema,
|
|
32
|
+
openingBalance: zod.z.number().optional(),
|
|
33
|
+
/** "Debit" | "Credit" — required by Tally when openingBalance is set */
|
|
34
|
+
openingBalanceType: zod.z.enum(["Debit", "Credit"]).optional(),
|
|
35
|
+
address: zod.z.array(zod.z.string()).optional(),
|
|
36
|
+
state: zod.z.string().optional(),
|
|
37
|
+
pincode: zod.z.string().optional(),
|
|
38
|
+
email: zod.z.string().email().optional(),
|
|
39
|
+
phone: zod.z.string().optional()
|
|
40
|
+
});
|
|
41
|
+
var LedgerSchema = zod.z.object({
|
|
42
|
+
name: zod.z.string(),
|
|
43
|
+
guid: zod.z.string(),
|
|
44
|
+
group: zod.z.string(),
|
|
45
|
+
gstin: zod.z.string().optional(),
|
|
46
|
+
/** Signed: positive = debit balance, negative = credit balance (normalized
|
|
47
|
+
* at the parser layer — Tally's raw XML encodes sign via a separate
|
|
48
|
+
* DR/CR-style attribute, never as a literal minus on the export). */
|
|
49
|
+
closingBalance: zod.z.number().optional(),
|
|
50
|
+
state: zod.z.string().optional()
|
|
51
|
+
});
|
|
52
|
+
var StockItemSchema = zod.z.object({
|
|
53
|
+
name: zod.z.string(),
|
|
54
|
+
guid: zod.z.string(),
|
|
55
|
+
unit: zod.z.string(),
|
|
56
|
+
closingQty: zod.z.number().optional(),
|
|
57
|
+
closingValue: zod.z.number().optional(),
|
|
58
|
+
/** HSN/SAC code, when GST is enabled in the company */
|
|
59
|
+
hsnCode: zod.z.string().optional(),
|
|
60
|
+
gstRate: zod.z.number().optional()
|
|
61
|
+
});
|
|
62
|
+
var StockItemInputSchema = zod.z.object({
|
|
63
|
+
name: zod.z.string().min(1),
|
|
64
|
+
/** Tally stock group name, e.g. "Primary" */
|
|
65
|
+
group: zod.z.string().default("Primary"),
|
|
66
|
+
unit: zod.z.string().min(1),
|
|
67
|
+
hsnCode: zod.z.string().optional(),
|
|
68
|
+
gstRate: zod.z.number().optional(),
|
|
69
|
+
openingQty: zod.z.number().optional(),
|
|
70
|
+
openingRate: zod.z.number().optional()
|
|
71
|
+
});
|
|
72
|
+
var CompanySchema = zod.z.object({
|
|
73
|
+
name: zod.z.string(),
|
|
74
|
+
guid: zod.z.string(),
|
|
75
|
+
startingFrom: zod.z.string().optional(),
|
|
76
|
+
endingAt: zod.z.string().optional()
|
|
77
|
+
});
|
|
78
|
+
var OutstandingEntrySchema = zod.z.object({
|
|
79
|
+
ledgerName: zod.z.string(),
|
|
80
|
+
voucherNumber: zod.z.string(),
|
|
81
|
+
voucherDate: zod.z.coerce.date(),
|
|
82
|
+
dueDate: zod.z.coerce.date().optional(),
|
|
83
|
+
/** Positive = they owe you, negative = you owe them */
|
|
84
|
+
pendingAmount: zod.z.number(),
|
|
85
|
+
overdueDays: zod.z.number().optional()
|
|
86
|
+
});
|
|
87
|
+
var baseVoucherFields = {
|
|
88
|
+
date: zod.z.coerce.date(),
|
|
89
|
+
narration: zod.z.string().optional(),
|
|
90
|
+
/** Tally auto-numbers if omitted; only set this if you're syncing from an
|
|
91
|
+
* external system that owns numbering (e.g. an e-invoice generator). */
|
|
92
|
+
voucherNumber: zod.z.string().optional(),
|
|
93
|
+
reference: zod.z.string().optional()
|
|
94
|
+
};
|
|
95
|
+
var lineItemSchema = zod.z.object({
|
|
96
|
+
/** Must match an existing Tally stock item name exactly (case-sensitive) */
|
|
97
|
+
stockItem: zod.z.string().min(1),
|
|
98
|
+
quantity: zod.z.number().positive(),
|
|
99
|
+
rate: zod.z.number().nonnegative(),
|
|
100
|
+
/** Defaults to quantity * rate; pass explicitly to override rounding */
|
|
101
|
+
amount: zod.z.number().optional()
|
|
102
|
+
});
|
|
103
|
+
var taxLedgerSchema = zod.z.object({
|
|
104
|
+
/** e.g. "Output CGST", "Output SGST", "Output IGST" — must exist in Tally */
|
|
105
|
+
ledger: zod.z.string().min(1),
|
|
106
|
+
amount: zod.z.number()
|
|
107
|
+
});
|
|
108
|
+
var SalesVoucherInputSchema = zod.z.object({
|
|
109
|
+
voucherType: zod.z.literal("Sales"),
|
|
110
|
+
...baseVoucherFields,
|
|
111
|
+
/** Sundry Debtor ledger name being billed */
|
|
112
|
+
party: zod.z.string().min(1),
|
|
113
|
+
items: zod.z.array(lineItemSchema).min(1),
|
|
114
|
+
/** Sales/revenue ledger to credit; defaults to "Sales" */
|
|
115
|
+
salesLedger: zod.z.string().default("Sales"),
|
|
116
|
+
taxes: zod.z.array(taxLedgerSchema).optional()
|
|
117
|
+
});
|
|
118
|
+
var PurchaseVoucherInputSchema = zod.z.object({
|
|
119
|
+
voucherType: zod.z.literal("Purchase"),
|
|
120
|
+
...baseVoucherFields,
|
|
121
|
+
/** Sundry Creditor ledger name being paid */
|
|
122
|
+
party: zod.z.string().min(1),
|
|
123
|
+
items: zod.z.array(lineItemSchema).min(1),
|
|
124
|
+
purchaseLedger: zod.z.string().default("Purchase"),
|
|
125
|
+
taxes: zod.z.array(taxLedgerSchema).optional()
|
|
126
|
+
});
|
|
127
|
+
var PaymentVoucherInputSchema = zod.z.object({
|
|
128
|
+
voucherType: zod.z.literal("Payment"),
|
|
129
|
+
...baseVoucherFields,
|
|
130
|
+
/** Ledger being debited — typically an expense or a creditor being paid off */
|
|
131
|
+
debitLedger: zod.z.string().min(1),
|
|
132
|
+
/** Bank or Cash ledger being credited */
|
|
133
|
+
creditLedger: zod.z.string().min(1),
|
|
134
|
+
amount: zod.z.number().positive()
|
|
135
|
+
});
|
|
136
|
+
var ReceiptVoucherInputSchema = zod.z.object({
|
|
137
|
+
voucherType: zod.z.literal("Receipt"),
|
|
138
|
+
...baseVoucherFields,
|
|
139
|
+
/** Bank or Cash ledger being debited */
|
|
140
|
+
debitLedger: zod.z.string().min(1),
|
|
141
|
+
/** Ledger being credited — typically the debtor paying you */
|
|
142
|
+
creditLedger: zod.z.string().min(1),
|
|
143
|
+
amount: zod.z.number().positive()
|
|
144
|
+
});
|
|
145
|
+
var journalEntrySchema = zod.z.object({
|
|
146
|
+
ledger: zod.z.string().min(1),
|
|
147
|
+
type: zod.z.enum(["Debit", "Credit"]),
|
|
148
|
+
amount: zod.z.number().positive()
|
|
149
|
+
});
|
|
150
|
+
var JournalVoucherInputSchema = zod.z.object({
|
|
151
|
+
voucherType: zod.z.literal("Journal"),
|
|
152
|
+
...baseVoucherFields,
|
|
153
|
+
entries: zod.z.array(journalEntrySchema).min(2)
|
|
154
|
+
}).refine(
|
|
155
|
+
(v) => {
|
|
156
|
+
const debit = v.entries.filter((e) => e.type === "Debit").reduce((s, e) => s + e.amount, 0);
|
|
157
|
+
const credit = v.entries.filter((e) => e.type === "Credit").reduce((s, e) => s + e.amount, 0);
|
|
158
|
+
return Math.abs(debit - credit) < 5e-3;
|
|
159
|
+
},
|
|
160
|
+
{ message: "Journal voucher debit and credit totals must balance" }
|
|
161
|
+
);
|
|
162
|
+
var VoucherInputSchema = zod.z.discriminatedUnion("voucherType", [
|
|
163
|
+
SalesVoucherInputSchema,
|
|
164
|
+
PurchaseVoucherInputSchema,
|
|
165
|
+
PaymentVoucherInputSchema,
|
|
166
|
+
ReceiptVoucherInputSchema
|
|
167
|
+
// Journal isn't included directly here because z.discriminatedUnion can't
|
|
168
|
+
// take a refined (ZodEffects) member — see VoucherInput union type below
|
|
169
|
+
// and validateVoucherInput() in client.ts, which validates Journal
|
|
170
|
+
// separately via JournalVoucherInputSchema.
|
|
171
|
+
]);
|
|
172
|
+
function assertNever(x) {
|
|
173
|
+
throw new Error(`Unhandled voucher type: ${JSON.stringify(x)}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/xml/envelope.ts
|
|
177
|
+
var EMPTY_MARKER = "";
|
|
178
|
+
function escapeXml(value) {
|
|
179
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
180
|
+
}
|
|
181
|
+
function formatTallyDate(date) {
|
|
182
|
+
const y = date.getFullYear();
|
|
183
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
184
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
185
|
+
return `${y}${m}${d}`;
|
|
186
|
+
}
|
|
187
|
+
function formatSignedAmount(amount, isDebit) {
|
|
188
|
+
const magnitude = Math.abs(amount).toFixed(2);
|
|
189
|
+
return isDebit ? magnitude : `-${magnitude}`;
|
|
190
|
+
}
|
|
191
|
+
function buildEnvelope(options, bodyXml) {
|
|
192
|
+
const staticVars = {
|
|
193
|
+
...options.company ? { SVCURRENTCOMPANY: options.company } : {},
|
|
194
|
+
...options.staticVariables ?? {}
|
|
195
|
+
};
|
|
196
|
+
const staticVarsXml = Object.entries(staticVars).map(([key, value]) => `<${key}>${escapeXml(value)}</${key}>`).join("");
|
|
197
|
+
const isImport = options.requestType === "Import Data";
|
|
198
|
+
const sectionTag = isImport ? "IMPORTDATA" : "EXPORTDATA";
|
|
199
|
+
return `<ENVELOPE><HEADER><TALLYREQUEST>${escapeXml(options.requestType)}</TALLYREQUEST></HEADER><BODY><${sectionTag}><REQUESTDESC><REPORTNAME>${escapeXml(options.id)}</REPORTNAME>` + (staticVarsXml ? `<STATICVARIABLES>${staticVarsXml}</STATICVARIABLES>` : "") + `</REQUESTDESC>` + (isImport && bodyXml ? `<REQUESTDATA>${bodyXml}</REQUESTDATA>` : "") + `</${sectionTag}></BODY></ENVELOPE>`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/xml/builders/ledger.ts
|
|
203
|
+
function buildCreateLedgerXml(input) {
|
|
204
|
+
const addressXml = (input.address ?? []).map((line) => `<ADDRESS>${escapeXml(line)}</ADDRESS>`).join("");
|
|
205
|
+
const openingBalanceXml = input.openingBalance != null ? `<OPENINGBALANCE>${input.openingBalanceType === "Credit" ? "-" : ""}${Math.abs(input.openingBalance).toFixed(2)}</OPENINGBALANCE>` : "";
|
|
206
|
+
return `<TALLYMESSAGE xmlns:UDF="TallyUDF"><LEDGER NAME="${escapeXml(input.name)}" ACTION="Create"><NAME>${escapeXml(input.name)}</NAME><PARENT>${escapeXml(input.group)}</PARENT>` + (input.gstin ? `<GSTIN>${escapeXml(input.gstin)}</GSTIN>` : "") + (input.state ? `<LEDSTATENAME>${escapeXml(input.state)}</LEDSTATENAME>` : "") + (input.pincode ? `<PINCODE>${escapeXml(input.pincode)}</PINCODE>` : "") + openingBalanceXml + addressXml + (input.email ? `<EMAIL>${escapeXml(input.email)}</EMAIL>` : "") + (input.phone ? `<LEDGERPHONE>${escapeXml(input.phone)}</LEDGERPHONE>` : "") + `</LEDGER></TALLYMESSAGE>`;
|
|
207
|
+
}
|
|
208
|
+
function buildCreateStockItemXml(input) {
|
|
209
|
+
const openingXml = input.openingQty != null ? `<OPENINGBALANCE>${input.openingQty} ${escapeXml(input.unit)}</OPENINGBALANCE>` + (input.openingRate != null ? `<OPENINGRATE>${input.openingRate.toFixed(2)}/${escapeXml(input.unit)}</OPENINGRATE><OPENINGVALUE>${(input.openingQty * input.openingRate).toFixed(2)}</OPENINGVALUE>` : "") : "";
|
|
210
|
+
return `<TALLYMESSAGE xmlns:UDF="TallyUDF"><STOCKITEM NAME="${escapeXml(input.name)}" ACTION="Create"><NAME>${escapeXml(input.name)}</NAME><PARENT>${escapeXml(input.group)}</PARENT><BASEUNITS>${escapeXml(input.unit)}</BASEUNITS>` + (input.hsnCode ? `<HSNCODE>${escapeXml(input.hsnCode)}</HSNCODE>` : "") + (input.gstRate != null ? `<GSTRATE>${input.gstRate}</GSTRATE>` : "") + openingXml + `</STOCKITEM></TALLYMESSAGE>`;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/xml/builders/voucher.ts
|
|
214
|
+
function lineItemAmount(item) {
|
|
215
|
+
return item.amount ?? item.quantity * item.rate;
|
|
216
|
+
}
|
|
217
|
+
function buildInventoryEntryXml(item, isDebit) {
|
|
218
|
+
const qty = `${item.quantity}`;
|
|
219
|
+
return `<ALLINVENTORYENTRIES.LIST><STOCKITEMNAME>${escapeXml(item.stockItem)}</STOCKITEMNAME><ISDEEMEDPOSITIVE>${isDebit ? "Yes" : "No"}</ISDEEMEDPOSITIVE><RATE>${item.rate.toFixed(2)}</RATE><AMOUNT>${formatSignedAmount(lineItemAmount(item), isDebit)}</AMOUNT><ACTUALQTY>${qty}</ACTUALQTY><BILLEDQTY>${qty}</BILLEDQTY></ALLINVENTORYENTRIES.LIST>`;
|
|
220
|
+
}
|
|
221
|
+
function buildLedgerEntryXml(ledgerName, amount, isDebit) {
|
|
222
|
+
return `<ALLLEDGERENTRIES.LIST><LEDGERNAME>${escapeXml(ledgerName)}</LEDGERNAME><ISDEEMEDPOSITIVE>${isDebit ? "Yes" : "No"}</ISDEEMEDPOSITIVE><AMOUNT>${formatSignedAmount(amount, isDebit)}</AMOUNT></ALLLEDGERENTRIES.LIST>`;
|
|
223
|
+
}
|
|
224
|
+
function buildSalesXml(input) {
|
|
225
|
+
const itemsTotal = input.items.reduce(
|
|
226
|
+
(sum, item) => sum + lineItemAmount(item),
|
|
227
|
+
0
|
|
228
|
+
);
|
|
229
|
+
const taxTotal = (input.taxes ?? []).reduce((sum, t) => sum + t.amount, 0);
|
|
230
|
+
const partyTotal = itemsTotal + taxTotal;
|
|
231
|
+
const partyEntry = buildLedgerEntryXml(input.party, partyTotal, true);
|
|
232
|
+
const salesEntry = `<ALLLEDGERENTRIES.LIST><LEDGERNAME>${escapeXml(input.salesLedger)}</LEDGERNAME><ISDEEMEDPOSITIVE>No</ISDEEMEDPOSITIVE><AMOUNT>${formatSignedAmount(itemsTotal, false)}</AMOUNT>` + input.items.map((item) => buildInventoryEntryXml(item, false)).join("") + `</ALLLEDGERENTRIES.LIST>`;
|
|
233
|
+
const taxEntries = (input.taxes ?? []).map((t) => buildLedgerEntryXml(t.ledger, t.amount, false)).join("");
|
|
234
|
+
return buildVoucherEnvelope({
|
|
235
|
+
voucherTypeName: "Sales",
|
|
236
|
+
date: input.date,
|
|
237
|
+
narration: input.narration,
|
|
238
|
+
voucherNumber: input.voucherNumber,
|
|
239
|
+
reference: input.reference,
|
|
240
|
+
isInvoice: true,
|
|
241
|
+
partyName: input.party,
|
|
242
|
+
body: partyEntry + salesEntry + taxEntries
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
function buildPurchaseXml(input) {
|
|
246
|
+
const itemsTotal = input.items.reduce(
|
|
247
|
+
(sum, item) => sum + lineItemAmount(item),
|
|
248
|
+
0
|
|
249
|
+
);
|
|
250
|
+
const taxTotal = (input.taxes ?? []).reduce((sum, t) => sum + t.amount, 0);
|
|
251
|
+
const partyTotal = itemsTotal + taxTotal;
|
|
252
|
+
const partyEntry = buildLedgerEntryXml(input.party, partyTotal, false);
|
|
253
|
+
const purchaseEntry = `<ALLLEDGERENTRIES.LIST><LEDGERNAME>${escapeXml(input.purchaseLedger)}</LEDGERNAME><ISDEEMEDPOSITIVE>Yes</ISDEEMEDPOSITIVE><AMOUNT>${formatSignedAmount(itemsTotal, true)}</AMOUNT>` + input.items.map((item) => buildInventoryEntryXml(item, true)).join("") + `</ALLLEDGERENTRIES.LIST>`;
|
|
254
|
+
const taxEntries = (input.taxes ?? []).map((t) => buildLedgerEntryXml(t.ledger, t.amount, true)).join("");
|
|
255
|
+
return buildVoucherEnvelope({
|
|
256
|
+
voucherTypeName: "Purchase",
|
|
257
|
+
date: input.date,
|
|
258
|
+
narration: input.narration,
|
|
259
|
+
voucherNumber: input.voucherNumber,
|
|
260
|
+
reference: input.reference,
|
|
261
|
+
isInvoice: true,
|
|
262
|
+
partyName: input.party,
|
|
263
|
+
body: partyEntry + purchaseEntry + taxEntries
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function buildPaymentXml(input) {
|
|
267
|
+
const body = buildLedgerEntryXml(input.debitLedger, input.amount, true) + buildLedgerEntryXml(input.creditLedger, input.amount, false);
|
|
268
|
+
return buildVoucherEnvelope({
|
|
269
|
+
voucherTypeName: "Payment",
|
|
270
|
+
date: input.date,
|
|
271
|
+
narration: input.narration,
|
|
272
|
+
voucherNumber: input.voucherNumber,
|
|
273
|
+
reference: input.reference,
|
|
274
|
+
isInvoice: false,
|
|
275
|
+
body
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
function buildReceiptXml(input) {
|
|
279
|
+
const body = buildLedgerEntryXml(input.debitLedger, input.amount, true) + buildLedgerEntryXml(input.creditLedger, input.amount, false);
|
|
280
|
+
return buildVoucherEnvelope({
|
|
281
|
+
voucherTypeName: "Receipt",
|
|
282
|
+
date: input.date,
|
|
283
|
+
narration: input.narration,
|
|
284
|
+
voucherNumber: input.voucherNumber,
|
|
285
|
+
reference: input.reference,
|
|
286
|
+
isInvoice: false,
|
|
287
|
+
body
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
function buildJournalXml(input) {
|
|
291
|
+
const body = input.entries.map((e) => buildLedgerEntryXml(e.ledger, e.amount, e.type === "Debit")).join("");
|
|
292
|
+
return buildVoucherEnvelope({
|
|
293
|
+
voucherTypeName: "Journal",
|
|
294
|
+
date: input.date,
|
|
295
|
+
narration: input.narration,
|
|
296
|
+
voucherNumber: input.voucherNumber,
|
|
297
|
+
reference: input.reference,
|
|
298
|
+
isInvoice: false,
|
|
299
|
+
body
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
function buildVoucherEnvelope(opts) {
|
|
303
|
+
return `<TALLYMESSAGE xmlns:UDF="TallyUDF"><VOUCHER VCHTYPE="${escapeXml(opts.voucherTypeName)}" ACTION="Create"` + (opts.isInvoice ? ` ISINVOICE="Yes"` : "") + `><DATE>${formatTallyDate(opts.date)}</DATE><VOUCHERTYPENAME>${escapeXml(opts.voucherTypeName)}</VOUCHERTYPENAME>` + (opts.voucherNumber ? `<VOUCHERNUMBER>${escapeXml(opts.voucherNumber)}</VOUCHERNUMBER>` : "") + (opts.partyName ? `<PARTYLEDGERNAME>${escapeXml(opts.partyName)}</PARTYLEDGERNAME>` : "") + (opts.reference ? `<REFERENCE>${escapeXml(opts.reference)}</REFERENCE>` : "") + (opts.narration ? `<NARRATION>${escapeXml(opts.narration)}</NARRATION>` : "") + opts.body + `</VOUCHER></TALLYMESSAGE>`;
|
|
304
|
+
}
|
|
305
|
+
function buildVoucherXml(input) {
|
|
306
|
+
switch (input.voucherType) {
|
|
307
|
+
case "Sales":
|
|
308
|
+
return buildSalesXml(input);
|
|
309
|
+
case "Purchase":
|
|
310
|
+
return buildPurchaseXml(input);
|
|
311
|
+
case "Payment":
|
|
312
|
+
return buildPaymentXml(input);
|
|
313
|
+
case "Receipt":
|
|
314
|
+
return buildReceiptXml(input);
|
|
315
|
+
case "Journal":
|
|
316
|
+
return buildJournalXml(input);
|
|
317
|
+
default:
|
|
318
|
+
return assertNever(input);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/xml/builders/collection.ts
|
|
323
|
+
function buildGetCompaniesXml() {
|
|
324
|
+
return buildEnvelope({ requestType: "Export Data", id: "List of Companies" });
|
|
325
|
+
}
|
|
326
|
+
function buildGetLedgersXml(company) {
|
|
327
|
+
return buildEnvelope({
|
|
328
|
+
requestType: "Export Data",
|
|
329
|
+
id: "List of Ledgers",
|
|
330
|
+
company,
|
|
331
|
+
staticVariables: { SVEXPORTFORMAT: "$$SysName:XML" }
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function buildGetStockItemsXml(company) {
|
|
335
|
+
return buildEnvelope({
|
|
336
|
+
requestType: "Export Data",
|
|
337
|
+
id: "List of Stock Items",
|
|
338
|
+
company,
|
|
339
|
+
staticVariables: { SVEXPORTFORMAT: "$$SysName:XML" }
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function buildGetOutstandingXml(company) {
|
|
343
|
+
return buildEnvelope({
|
|
344
|
+
requestType: "Export Data",
|
|
345
|
+
id: "Bills Receivable",
|
|
346
|
+
// swap to "Bills Payable" for AP outstanding
|
|
347
|
+
company,
|
|
348
|
+
staticVariables: { SVEXPORTFORMAT: "$$SysName:XML" }
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function buildPingXml() {
|
|
352
|
+
return buildGetCompaniesXml();
|
|
353
|
+
}
|
|
354
|
+
var parser = new fastXmlParser.XMLParser({
|
|
355
|
+
ignoreAttributes: false,
|
|
356
|
+
attributeNamePrefix: "@_",
|
|
357
|
+
// Tally repeats sibling tags (LINEERROR, etc.) without warning when there's
|
|
358
|
+
// more than one — force these into arrays unconditionally so downstream
|
|
359
|
+
// code never has to special-case "string vs array of one".
|
|
360
|
+
isArray: (tagName) => ["LINEERROR", "TALLYMESSAGE"].includes(tagName)
|
|
361
|
+
// Tally emits  as an empty-but-present marker on some master fields;
|
|
362
|
+
// fast-xml-parser decodes numeric entities by default, which turns it into
|
|
363
|
+
// an unprintable control character rather than throwing — we normalize it
|
|
364
|
+
// back to an empty string post-parse instead of fighting the entity
|
|
365
|
+
// decoder.
|
|
366
|
+
});
|
|
367
|
+
function parseImportResponse(rawXml) {
|
|
368
|
+
let parsed;
|
|
369
|
+
try {
|
|
370
|
+
parsed = parser.parse(rawXml);
|
|
371
|
+
} catch (cause) {
|
|
372
|
+
return err(
|
|
373
|
+
tallyError("PARSE_ERROR", "Could not parse Tally's response as XML", {
|
|
374
|
+
responseXml: rawXml,
|
|
375
|
+
cause
|
|
376
|
+
})
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
const body = parsed.ENVELOPE?.BODY;
|
|
380
|
+
const lineErrors = body?.LINEERROR;
|
|
381
|
+
if (lineErrors && lineErrors.length > 0) {
|
|
382
|
+
return err(
|
|
383
|
+
tallyError("TALLY_REJECTED", "Tally rejected the request", {
|
|
384
|
+
tallyMessage: lineErrors.join("; "),
|
|
385
|
+
responseXml: rawXml
|
|
386
|
+
})
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
const result = body?.DATA?.IMPORTRESULT;
|
|
390
|
+
const created = Number(result?.CREATED ?? 0);
|
|
391
|
+
const altered = Number(result?.ALTERED ?? 0);
|
|
392
|
+
const errors = Number(result?.ERRORS ?? 0);
|
|
393
|
+
if (errors > 0) {
|
|
394
|
+
return err(
|
|
395
|
+
tallyError(
|
|
396
|
+
"TALLY_REJECTED",
|
|
397
|
+
`Tally reported ${errors} error(s) during import`,
|
|
398
|
+
{
|
|
399
|
+
responseXml: rawXml
|
|
400
|
+
}
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
if (created === 0 && altered === 0) {
|
|
405
|
+
return err(
|
|
406
|
+
tallyError(
|
|
407
|
+
"PARSE_ERROR",
|
|
408
|
+
"Tally returned no CREATED/ALTERED count and no error \u2014 unexpected response shape",
|
|
409
|
+
{
|
|
410
|
+
responseXml: rawXml
|
|
411
|
+
}
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
}
|
|
415
|
+
return ok({
|
|
416
|
+
voucherNumber: String(result?.LASTVCHID ?? ""),
|
|
417
|
+
guid: String(result?.LASTMID ?? ""),
|
|
418
|
+
alteredOn: /* @__PURE__ */ new Date()
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
var COLLECTION_TAGS = ["LEDGER", "STOCKITEM", "COMPANY", "BILLOUTSTANDING"];
|
|
422
|
+
var parser2 = new fastXmlParser.XMLParser({
|
|
423
|
+
ignoreAttributes: false,
|
|
424
|
+
attributeNamePrefix: "@_",
|
|
425
|
+
isArray: (tagName) => COLLECTION_TAGS.includes(tagName)
|
|
426
|
+
});
|
|
427
|
+
function parseTallyNumber(raw) {
|
|
428
|
+
if (raw == null) return void 0;
|
|
429
|
+
const cleaned = String(raw).replace(/\s*(Cr|Dr)\s*$/i, "").replace(/,/g, "").trim();
|
|
430
|
+
const n = Number(cleaned);
|
|
431
|
+
return Number.isFinite(n) ? n : void 0;
|
|
432
|
+
}
|
|
433
|
+
function safeParse(rawXml, extract) {
|
|
434
|
+
try {
|
|
435
|
+
const parsed = parser2.parse(rawXml);
|
|
436
|
+
return ok(extract(parsed));
|
|
437
|
+
} catch (cause) {
|
|
438
|
+
return err(
|
|
439
|
+
tallyError("PARSE_ERROR", "Could not parse Tally's collection response", {
|
|
440
|
+
responseXml: rawXml,
|
|
441
|
+
cause
|
|
442
|
+
})
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function findCollectionRoot(parsed) {
|
|
447
|
+
return parsed?.ENVELOPE?.BODY?.DATA?.COLLECTION ?? parsed?.ENVELOPE?.BODY?.DATA ?? {};
|
|
448
|
+
}
|
|
449
|
+
function parseLedgerCollection(rawXml) {
|
|
450
|
+
return safeParse(rawXml, (parsed) => {
|
|
451
|
+
const root = findCollectionRoot(parsed);
|
|
452
|
+
const ledgers = root.LEDGER ?? [];
|
|
453
|
+
return ledgers.map((l) => ({
|
|
454
|
+
name: String(l["@_NAME"] ?? l.NAME ?? ""),
|
|
455
|
+
guid: String(l.GUID ?? ""),
|
|
456
|
+
group: String(l.PARENT ?? ""),
|
|
457
|
+
gstin: l.GSTIN ? String(l.GSTIN) : void 0,
|
|
458
|
+
closingBalance: parseTallyNumber(l.CLOSINGBALANCE),
|
|
459
|
+
state: l.LEDSTATENAME ? String(l.LEDSTATENAME) : void 0
|
|
460
|
+
}));
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
function parseStockItemCollection(rawXml) {
|
|
464
|
+
return safeParse(rawXml, (parsed) => {
|
|
465
|
+
const root = findCollectionRoot(parsed);
|
|
466
|
+
const items = root.STOCKITEM ?? [];
|
|
467
|
+
return items.map((s) => ({
|
|
468
|
+
name: String(s["@_NAME"] ?? s.NAME ?? ""),
|
|
469
|
+
guid: String(s.GUID ?? ""),
|
|
470
|
+
unit: String(s.BASEUNITS ?? ""),
|
|
471
|
+
closingQty: parseTallyNumber(s.CLOSINGBALANCE),
|
|
472
|
+
closingValue: parseTallyNumber(s.CLOSINGVALUE),
|
|
473
|
+
hsnCode: s.HSNCODE ? String(s.HSNCODE) : void 0,
|
|
474
|
+
gstRate: parseTallyNumber(s.GSTRATE)
|
|
475
|
+
}));
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
function parseCompanyCollection(rawXml) {
|
|
479
|
+
return safeParse(rawXml, (parsed) => {
|
|
480
|
+
const root = findCollectionRoot(parsed);
|
|
481
|
+
const companies = root.COMPANY ?? [];
|
|
482
|
+
return companies.map((c) => ({
|
|
483
|
+
name: String(c["@_NAME"] ?? c.NAME ?? ""),
|
|
484
|
+
guid: String(c.GUID ?? ""),
|
|
485
|
+
startingFrom: c.STARTINGFROM ? String(c.STARTINGFROM) : void 0,
|
|
486
|
+
endingAt: c.ENDINGAT ? String(c.ENDINGAT) : void 0
|
|
487
|
+
}));
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function parseOutstandingCollection(rawXml) {
|
|
491
|
+
return safeParse(rawXml, (parsed) => {
|
|
492
|
+
const root = findCollectionRoot(parsed);
|
|
493
|
+
const bills = root.BILLOUTSTANDING ?? [];
|
|
494
|
+
return bills.map((b) => ({
|
|
495
|
+
ledgerName: String(b.LEDGERNAME ?? ""),
|
|
496
|
+
voucherNumber: String(b.VOUCHERNUMBER ?? ""),
|
|
497
|
+
voucherDate: new Date(String(b.VOUCHERDATE ?? "")),
|
|
498
|
+
dueDate: b.DUEDATE ? new Date(String(b.DUEDATE)) : void 0,
|
|
499
|
+
pendingAmount: parseTallyNumber(b.PENDINGAMOUNT) ?? 0,
|
|
500
|
+
overdueDays: b.OVERDUEDAYS != null ? Number(b.OVERDUEDAYS) : void 0
|
|
501
|
+
}));
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// src/tally/transport.ts
|
|
506
|
+
var TallyTransport = class {
|
|
507
|
+
constructor(config) {
|
|
508
|
+
this.config = config;
|
|
509
|
+
this.retries = config.retries ?? 1;
|
|
510
|
+
}
|
|
511
|
+
config;
|
|
512
|
+
retries;
|
|
513
|
+
async send(requestXml) {
|
|
514
|
+
let lastError;
|
|
515
|
+
const protocol = this.config.https ? "https" : "http";
|
|
516
|
+
const url = `${protocol}://${this.config.host}:${this.config.port}/`;
|
|
517
|
+
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
518
|
+
try {
|
|
519
|
+
const response = await fetch(url, {
|
|
520
|
+
method: "POST",
|
|
521
|
+
headers: {
|
|
522
|
+
"Content-Type": "text/xml"
|
|
523
|
+
},
|
|
524
|
+
body: requestXml,
|
|
525
|
+
signal: AbortSignal.timeout(this.config.timeoutMs ?? 15e3)
|
|
526
|
+
});
|
|
527
|
+
const responseText = await response.text();
|
|
528
|
+
return ok(responseText);
|
|
529
|
+
} catch (cause) {
|
|
530
|
+
if (cause instanceof Error) {
|
|
531
|
+
if (cause.name === "TimeoutError" || cause.name === "AbortError") {
|
|
532
|
+
lastError = tallyError(
|
|
533
|
+
"TIMEOUT",
|
|
534
|
+
`Request to Tally timed out after ${this.config.timeoutMs ?? 15e3}ms`,
|
|
535
|
+
{
|
|
536
|
+
requestXml,
|
|
537
|
+
cause
|
|
538
|
+
}
|
|
539
|
+
);
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
if (cause instanceof TypeError) {
|
|
543
|
+
lastError = tallyError(
|
|
544
|
+
"NETWORK_ERROR",
|
|
545
|
+
`Could not reach Tally at ${this.config.host}:${this.config.port}`,
|
|
546
|
+
{
|
|
547
|
+
requestXml,
|
|
548
|
+
cause
|
|
549
|
+
}
|
|
550
|
+
);
|
|
551
|
+
continue;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
lastError = tallyError(
|
|
555
|
+
"UNKNOWN",
|
|
556
|
+
"Unexpected error sending request to Tally",
|
|
557
|
+
{
|
|
558
|
+
requestXml,
|
|
559
|
+
cause
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return err(
|
|
566
|
+
lastError ?? tallyError("UNKNOWN", "Request failed with no captured error")
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
// src/tally/client.ts
|
|
572
|
+
function validateVoucherInput(input) {
|
|
573
|
+
const schema = {
|
|
574
|
+
Sales: SalesVoucherInputSchema,
|
|
575
|
+
Purchase: PurchaseVoucherInputSchema,
|
|
576
|
+
Payment: PaymentVoucherInputSchema,
|
|
577
|
+
Receipt: ReceiptVoucherInputSchema,
|
|
578
|
+
Journal: JournalVoucherInputSchema
|
|
579
|
+
}[input.voucherType];
|
|
580
|
+
const parsed = schema.safeParse(input);
|
|
581
|
+
if (!parsed.success) {
|
|
582
|
+
return err(
|
|
583
|
+
tallyError(
|
|
584
|
+
"VALIDATION_ERROR",
|
|
585
|
+
`Invalid ${input.voucherType} voucher input`,
|
|
586
|
+
{
|
|
587
|
+
cause: parsed.error
|
|
588
|
+
}
|
|
589
|
+
)
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
return ok(parsed.data);
|
|
593
|
+
}
|
|
594
|
+
var Tally = class {
|
|
595
|
+
transport;
|
|
596
|
+
company;
|
|
597
|
+
constructor(config) {
|
|
598
|
+
this.transport = new TallyTransport(config);
|
|
599
|
+
this.company = config.company;
|
|
600
|
+
}
|
|
601
|
+
// ---- Connection -------------------------------------------------------
|
|
602
|
+
async ping() {
|
|
603
|
+
const result = await this.transport.send(buildPingXml());
|
|
604
|
+
if (!result.ok) return result;
|
|
605
|
+
if (!result.value.includes("<ENVELOPE>")) {
|
|
606
|
+
return err(
|
|
607
|
+
tallyError(
|
|
608
|
+
"PARSE_ERROR",
|
|
609
|
+
"Response did not look like a Tally ENVELOPE",
|
|
610
|
+
{ responseXml: result.value }
|
|
611
|
+
)
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
return ok(true);
|
|
615
|
+
}
|
|
616
|
+
// ---- Reads --------------------------------------------------------------
|
|
617
|
+
async getCompanies() {
|
|
618
|
+
const res = await this.transport.send(buildGetCompaniesXml());
|
|
619
|
+
if (!res.ok) return res;
|
|
620
|
+
return parseCompanyCollection(res.value);
|
|
621
|
+
}
|
|
622
|
+
async getLedgers() {
|
|
623
|
+
const res = await this.transport.send(buildGetLedgersXml(this.company));
|
|
624
|
+
if (!res.ok) return res;
|
|
625
|
+
return parseLedgerCollection(res.value);
|
|
626
|
+
}
|
|
627
|
+
/** Alias matching the original product sketch's naming. */
|
|
628
|
+
async getCustomers() {
|
|
629
|
+
const res = await this.getLedgers();
|
|
630
|
+
if (!res.ok) return res;
|
|
631
|
+
return ok(res.value.filter((l) => l.group === "Sundry Debtors"));
|
|
632
|
+
}
|
|
633
|
+
async getStockItems() {
|
|
634
|
+
const res = await this.transport.send(buildGetStockItemsXml(this.company));
|
|
635
|
+
if (!res.ok) return res;
|
|
636
|
+
return parseStockItemCollection(res.value);
|
|
637
|
+
}
|
|
638
|
+
async getOutstanding() {
|
|
639
|
+
const res = await this.transport.send(buildGetOutstandingXml(this.company));
|
|
640
|
+
if (!res.ok) return res;
|
|
641
|
+
return parseOutstandingCollection(res.value);
|
|
642
|
+
}
|
|
643
|
+
// ---- Writes -------------------------------------------------------------
|
|
644
|
+
async createLedger(input) {
|
|
645
|
+
const parsed = LedgerInputSchema.safeParse(input);
|
|
646
|
+
if (!parsed.success) {
|
|
647
|
+
return err(
|
|
648
|
+
tallyError("VALIDATION_ERROR", "Invalid ledger input", {
|
|
649
|
+
cause: parsed.error
|
|
650
|
+
})
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
const xml = buildCreateLedgerXml(parsed.data);
|
|
654
|
+
const res = await this.transport.send(xml);
|
|
655
|
+
if (!res.ok) return res;
|
|
656
|
+
return parseImportResponse(res.value);
|
|
657
|
+
}
|
|
658
|
+
async createStockItem(input) {
|
|
659
|
+
const parsed = StockItemInputSchema.safeParse(input);
|
|
660
|
+
if (!parsed.success) {
|
|
661
|
+
return err(
|
|
662
|
+
tallyError("VALIDATION_ERROR", "Invalid stock item input", {
|
|
663
|
+
cause: parsed.error
|
|
664
|
+
})
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
const xml = buildCreateStockItemXml(parsed.data);
|
|
668
|
+
const res = await this.transport.send(xml);
|
|
669
|
+
if (!res.ok) return res;
|
|
670
|
+
return parseImportResponse(res.value);
|
|
671
|
+
}
|
|
672
|
+
async createVoucher(input) {
|
|
673
|
+
const validated = validateVoucherInput(input);
|
|
674
|
+
if (!validated.ok) return validated;
|
|
675
|
+
const xml = buildVoucherXml(validated.value);
|
|
676
|
+
const res = await this.transport.send(xml);
|
|
677
|
+
if (!res.ok) return res;
|
|
678
|
+
return parseImportResponse(res.value);
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* Convenience wrapper matching the original sketch's `createInvoice()`
|
|
682
|
+
* signature — expands into a full SalesVoucherInput (voucherType: "Sales")
|
|
683
|
+
* before going through the same validated path as createVoucher(). Kept
|
|
684
|
+
* separate from createVoucher() because "invoice" maps to a Sales voucher
|
|
685
|
+
* specifically, and spelling that out here means callers coming from
|
|
686
|
+
* other invoicing tools (Stripe, Zoho) don't need to know Tally's
|
|
687
|
+
* voucherType vocabulary at all.
|
|
688
|
+
*/
|
|
689
|
+
async createInvoice(input) {
|
|
690
|
+
return this.createVoucher({
|
|
691
|
+
voucherType: "Sales",
|
|
692
|
+
date: input.date,
|
|
693
|
+
party: input.customer,
|
|
694
|
+
items: input.items,
|
|
695
|
+
salesLedger: input.salesLedger ?? "Sales",
|
|
696
|
+
taxes: input.taxes,
|
|
697
|
+
reference: input.reference,
|
|
698
|
+
narration: input.narration
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
// ---- AI agent integration ------------------------------------------------
|
|
702
|
+
/**
|
|
703
|
+
* Returns JSON-Schema-shaped tool definitions (derived from the same Zod
|
|
704
|
+
* schemas used for validation, so the agent-facing contract can never
|
|
705
|
+
* drift from what the SDK actually accepts) for OpenAI-style function
|
|
706
|
+
* calling, LangGraph, Mastra, or a hand-rolled MCP server. Each `handler`
|
|
707
|
+
* closes over `this`, so a caller can wire these straight into an agent
|
|
708
|
+
* framework's tool registry without writing adapter glue.
|
|
709
|
+
*/
|
|
710
|
+
tools() {
|
|
711
|
+
return [
|
|
712
|
+
{
|
|
713
|
+
name: "getCustomers",
|
|
714
|
+
description: "List all Sundry Debtor ledgers (customers) in the active Tally company.",
|
|
715
|
+
parameters: zod.z.object({}),
|
|
716
|
+
handler: () => this.getCustomers()
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
name: "getOutstanding",
|
|
720
|
+
description: "Get outstanding (unpaid) receivable bills across all customers.",
|
|
721
|
+
parameters: zod.z.object({}),
|
|
722
|
+
handler: () => this.getOutstanding()
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: "createInvoice",
|
|
726
|
+
description: "Create a sales invoice for a customer with one or more line items.",
|
|
727
|
+
parameters: zod.z.object({
|
|
728
|
+
customer: zod.z.string(),
|
|
729
|
+
date: zod.z.coerce.date(),
|
|
730
|
+
items: zod.z.array(
|
|
731
|
+
zod.z.object({
|
|
732
|
+
stockItem: zod.z.string(),
|
|
733
|
+
quantity: zod.z.number(),
|
|
734
|
+
rate: zod.z.number()
|
|
735
|
+
})
|
|
736
|
+
)
|
|
737
|
+
}),
|
|
738
|
+
handler: (args) => this.createInvoice(args)
|
|
739
|
+
},
|
|
740
|
+
{
|
|
741
|
+
name: "createLedger",
|
|
742
|
+
description: "Create a new ledger account (e.g. a new customer or supplier) in Tally.",
|
|
743
|
+
parameters: LedgerInputSchema,
|
|
744
|
+
handler: (args) => this.createLedger(args)
|
|
745
|
+
}
|
|
746
|
+
];
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
|
|
750
|
+
exports.CompanySchema = CompanySchema;
|
|
751
|
+
exports.EMPTY_MARKER = EMPTY_MARKER;
|
|
752
|
+
exports.JournalVoucherInputSchema = JournalVoucherInputSchema;
|
|
753
|
+
exports.LedgerInputSchema = LedgerInputSchema;
|
|
754
|
+
exports.LedgerSchema = LedgerSchema;
|
|
755
|
+
exports.OutstandingEntrySchema = OutstandingEntrySchema;
|
|
756
|
+
exports.PaymentVoucherInputSchema = PaymentVoucherInputSchema;
|
|
757
|
+
exports.PurchaseVoucherInputSchema = PurchaseVoucherInputSchema;
|
|
758
|
+
exports.ReceiptVoucherInputSchema = ReceiptVoucherInputSchema;
|
|
759
|
+
exports.SalesVoucherInputSchema = SalesVoucherInputSchema;
|
|
760
|
+
exports.StockItemInputSchema = StockItemInputSchema;
|
|
761
|
+
exports.StockItemSchema = StockItemSchema;
|
|
762
|
+
exports.Tally = Tally;
|
|
763
|
+
exports.TallyTransport = TallyTransport;
|
|
764
|
+
exports.VoucherInputSchema = VoucherInputSchema;
|
|
765
|
+
exports.assertNever = assertNever;
|
|
766
|
+
exports.buildCreateLedgerXml = buildCreateLedgerXml;
|
|
767
|
+
exports.buildCreateStockItemXml = buildCreateStockItemXml;
|
|
768
|
+
exports.buildEnvelope = buildEnvelope;
|
|
769
|
+
exports.buildGetCompaniesXml = buildGetCompaniesXml;
|
|
770
|
+
exports.buildGetLedgersXml = buildGetLedgersXml;
|
|
771
|
+
exports.buildGetOutstandingXml = buildGetOutstandingXml;
|
|
772
|
+
exports.buildGetStockItemsXml = buildGetStockItemsXml;
|
|
773
|
+
exports.buildPingXml = buildPingXml;
|
|
774
|
+
exports.buildVoucherXml = buildVoucherXml;
|
|
775
|
+
exports.err = err;
|
|
776
|
+
exports.escapeXml = escapeXml;
|
|
777
|
+
exports.formatSignedAmount = formatSignedAmount;
|
|
778
|
+
exports.formatTallyDate = formatTallyDate;
|
|
779
|
+
exports.ok = ok;
|
|
780
|
+
exports.parseCompanyCollection = parseCompanyCollection;
|
|
781
|
+
exports.parseImportResponse = parseImportResponse;
|
|
782
|
+
exports.parseLedgerCollection = parseLedgerCollection;
|
|
783
|
+
exports.parseOutstandingCollection = parseOutstandingCollection;
|
|
784
|
+
exports.parseStockItemCollection = parseStockItemCollection;
|
|
785
|
+
exports.tallyError = tallyError;
|
|
786
|
+
exports.unwrap = unwrap;
|
|
787
|
+
//# sourceMappingURL=index.cjs.map
|
|
788
|
+
//# sourceMappingURL=index.cjs.map
|