@happyvertical/accounting 0.100.2 → 0.101.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.
@@ -1,51 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- //#region src/providers/quickbooks/invoice-request.ts
3
- /** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */
4
- function prepareQuickBooksInvoiceRequest(invoice, identity) {
5
- if (invoice.externalId) throw new Error("QuickBooks request identity is only for invoice creation");
6
- const payload = JSON.stringify(mapInvoiceToQBO(invoice));
7
- const request = {
8
- ...identity,
9
- payloadHash: hash(payload)
10
- };
11
- validateQuickBooksInvoiceRequest(request, identity.realmId, identity.environment, payload);
12
- return Object.freeze(request);
13
- }
14
- function hash(payload) {
15
- return createHash("sha256").update(payload).digest("hex");
16
- }
17
- function validateQuickBooksInvoiceRequest(request, realmId, environment, payload) {
18
- if (!request || typeof request.requestId !== "string" || !/^[A-Za-z0-9._-]{1,50}$/.test(request.requestId)) throw new Error("QuickBooks requestId must contain 1–50 URL-safe letters, digits, dots, underscores or hyphens");
19
- if (!request.realmId || request.realmId !== realmId || !["sandbox", "production"].includes(request.environment) || request.environment !== environment) throw new Error("QuickBooks invoice request realm/environment mismatch");
20
- if (!payload || request.payloadHash !== hash(payload)) throw new Error("QuickBooks invoice request payload mismatch; reconcile the original request");
21
- const parsed = JSON.parse(payload);
22
- if (parsed.Id !== void 0 || parsed.SyncToken !== void 0) throw new Error("QuickBooks request identity is only for invoice creation");
23
- }
24
- function formatLocalDate(date) {
25
- return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
26
- }
27
- function mapInvoiceToQBO(invoice) {
28
- if (invoice.collectionMethod === "charge_automatically") throw new Error("QuickBooks does not support charge_automatically invoice collection");
29
- return {
30
- CustomerRef: { value: invoice.customerExternalId || invoice.customerId },
31
- DocNumber: invoice.invoiceNumber,
32
- TxnDate: formatLocalDate(invoice.issueDate),
33
- DueDate: formatLocalDate(invoice.dueDate),
34
- Line: invoice.lineItems.map((item, idx) => ({
35
- LineNum: idx + 1,
36
- Description: item.description,
37
- Amount: item.amount ?? item.quantity * item.unitPrice,
38
- DetailType: "SalesItemLineDetail",
39
- SalesItemLineDetail: {
40
- Qty: item.quantity,
41
- UnitPrice: item.unitPrice
42
- }
43
- })),
44
- CurrencyRef: invoice.currency ? { value: invoice.currency } : void 0,
45
- CustomerMemo: invoice.memo ? { value: invoice.memo } : void 0
46
- };
47
- }
48
- //#endregion
49
- export { prepareQuickBooksInvoiceRequest as n, validateQuickBooksInvoiceRequest as r, mapInvoiceToQBO as t };
50
-
51
- //# sourceMappingURL=invoice-request-D6XcgNzI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"invoice-request-D6XcgNzI.js","names":[],"sources":["../../src/providers/quickbooks/invoice-request.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport type { InvoiceInput, QuickBooksInvoiceRequest } from '../../types.js';\n\n/** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */\nexport function prepareQuickBooksInvoiceRequest(\n invoice: InvoiceInput,\n identity: Omit<QuickBooksInvoiceRequest, 'payloadHash'>,\n): QuickBooksInvoiceRequest {\n if (invoice.externalId)\n throw new Error('QuickBooks request identity is only for invoice creation');\n const payload = JSON.stringify(mapInvoiceToQBO(invoice));\n const request = { ...identity, payloadHash: hash(payload) };\n validateQuickBooksInvoiceRequest(\n request,\n identity.realmId,\n identity.environment,\n payload,\n );\n return Object.freeze(request);\n}\n\nfunction hash(payload: string): string {\n return createHash('sha256').update(payload).digest('hex');\n}\n\nexport function validateQuickBooksInvoiceRequest(\n request: QuickBooksInvoiceRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n): void {\n // A deliberately conservative URL-safe subset of Intuit's 50-character limit.\n if (\n !request ||\n typeof request.requestId !== 'string' ||\n !/^[A-Za-z0-9._-]{1,50}$/.test(request.requestId)\n ) {\n throw new Error(\n 'QuickBooks requestId must contain 1–50 URL-safe letters, digits, dots, underscores or hyphens',\n );\n }\n if (\n !request.realmId ||\n request.realmId !== realmId ||\n !['sandbox', 'production'].includes(request.environment) ||\n request.environment !== environment\n ) {\n throw new Error('QuickBooks invoice request realm/environment mismatch');\n }\n if (!payload || request.payloadHash !== hash(payload)) {\n throw new Error(\n 'QuickBooks invoice request payload mismatch; reconcile the original request',\n );\n }\n const parsed = JSON.parse(payload);\n if (parsed.Id !== undefined || parsed.SyncToken !== undefined) {\n throw new Error('QuickBooks request identity is only for invoice creation');\n }\n}\n\nfunction formatLocalDate(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n return `${year}-${month}-${day}`;\n}\n\nexport function mapInvoiceToQBO(invoice: InvoiceInput) {\n if (invoice.collectionMethod === 'charge_automatically') {\n // QuickBooks cannot charge a stored payment method for an invoice.\n throw new Error(\n 'QuickBooks does not support charge_automatically invoice collection',\n );\n }\n return {\n CustomerRef: { value: invoice.customerExternalId || invoice.customerId },\n DocNumber: invoice.invoiceNumber,\n TxnDate: formatLocalDate(invoice.issueDate),\n DueDate: formatLocalDate(invoice.dueDate),\n Line: invoice.lineItems.map((item, idx) => ({\n LineNum: idx + 1,\n Description: item.description,\n Amount: item.amount ?? item.quantity * item.unitPrice,\n DetailType: 'SalesItemLineDetail' as const,\n SalesItemLineDetail: {\n Qty: item.quantity,\n UnitPrice: item.unitPrice,\n },\n })),\n CurrencyRef: invoice.currency ? { value: invoice.currency } : undefined,\n CustomerMemo: invoice.memo ? { value: invoice.memo } : undefined,\n };\n}\n"],"mappings":";;;AAIA,SAAgB,gCACd,SACA,UAC0B;CAC1B,IAAI,QAAQ,YACV,MAAM,IAAI,MAAM,0DAA0D;CAC5E,MAAM,UAAU,KAAK,UAAU,gBAAgB,OAAO,CAAC;CACvD,MAAM,UAAU;EAAE,GAAG;EAAU,aAAa,KAAK,OAAO;CAAE;CAC1D,iCACE,SACA,SAAS,SACT,SAAS,aACT,OACF;CACA,OAAO,OAAO,OAAO,OAAO;AAC9B;AAEA,SAAS,KAAK,SAAyB;CACrC,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,OAAO,KAAK;AAC1D;AAEA,SAAgB,iCACd,SACA,SACA,aACA,SACM;CAEN,IACE,CAAC,WACD,OAAO,QAAQ,cAAc,YAC7B,CAAC,yBAAyB,KAAK,QAAQ,SAAS,GAEhD,MAAM,IAAI,MACR,+FACF;CAEF,IACE,CAAC,QAAQ,WACT,QAAQ,YAAY,WACpB,CAAC,CAAC,WAAW,YAAY,CAAC,CAAC,SAAS,QAAQ,WAAW,KACvD,QAAQ,gBAAgB,aAExB,MAAM,IAAI,MAAM,uDAAuD;CAEzE,IAAI,CAAC,WAAW,QAAQ,gBAAgB,KAAK,OAAO,GAClD,MAAM,IAAI,MACR,6EACF;CAEF,MAAM,SAAS,KAAK,MAAM,OAAO;CACjC,IAAI,OAAO,OAAO,KAAA,KAAa,OAAO,cAAc,KAAA,GAClD,MAAM,IAAI,MAAM,0DAA0D;AAE9E;AAEA,SAAS,gBAAgB,MAAoB;CAI3C,OAAO,GAHM,KAAK,YAGR,EAAK,GAFD,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,SAAS,GAAG,GAEpC,EAAM,GADZ,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,GAAG,GACpB;AAC7B;AAEA,SAAgB,gBAAgB,SAAuB;CACrD,IAAI,QAAQ,qBAAqB,wBAE/B,MAAM,IAAI,MACR,qEACF;CAEF,OAAO;EACL,aAAa,EAAE,OAAO,QAAQ,sBAAsB,QAAQ,WAAW;EACvE,WAAW,QAAQ;EACnB,SAAS,gBAAgB,QAAQ,SAAS;EAC1C,SAAS,gBAAgB,QAAQ,OAAO;EACxC,MAAM,QAAQ,UAAU,KAAK,MAAM,SAAS;GAC1C,SAAS,MAAM;GACf,aAAa,KAAK;GAClB,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK;GAC5C,YAAY;GACZ,qBAAqB;IACnB,KAAK,KAAK;IACV,WAAW,KAAK;GAClB;EACF,EAAE;EACF,aAAa,QAAQ,WAAW,EAAE,OAAO,QAAQ,SAAS,IAAI,KAAA;EAC9D,cAAc,QAAQ,OAAO,EAAE,OAAO,QAAQ,KAAK,IAAI,KAAA;CACzD;AACF"}