@happyvertical/accounting 0.105.0 → 0.105.2
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 +13 -0
- package/dist/chunks/{quickbooks-Bh9k87sj.js → quickbooks-Bo_BjMv1.js} +3 -3
- package/dist/chunks/quickbooks-Bo_BjMv1.js.map +1 -0
- package/dist/chunks/{receivable-transfer-DQmMBcRo.js → receivable-transfer-DPxto4TY.js} +11 -4
- package/dist/chunks/{receivable-transfer-DQmMBcRo.js.map → receivable-transfer-DPxto4TY.js.map} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/providers/quickbooks/receivable-operations.d.ts +2 -2
- package/dist/providers/quickbooks/receivable-operations.d.ts.map +1 -1
- package/dist/providers/quickbooks/receivable-transfer.d.ts +12 -3
- package/dist/providers/quickbooks/receivable-transfer.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/quickbooks-Bh9k87sj.js.map +0 -1
package/README.md
CHANGED
|
@@ -585,6 +585,19 @@ types and the realm's home currency before writing. Foreign-currency transfers
|
|
|
585
585
|
are unsupported; no exchange rate is inferred. Account CurrencyRef, when present,
|
|
586
586
|
must agree. Missing transaction currency or financial fields fails closed.
|
|
587
587
|
|
|
588
|
+
For ordinary invoices without retention, use the additive
|
|
589
|
+
`QuickBooksOrdinaryReceivableMapping` with `kind: 'ordinary'`. It retains the same
|
|
590
|
+
explicit accrual/invoice-tax-point policy, scope, review evidence, customer,
|
|
591
|
+
currency and AR/cash references, but forbids `retainedAssetAccountRef` and
|
|
592
|
+
`releaseDueDates`. No unused retention account is queried or invented.
|
|
593
|
+
`QuickBooksReceivableOperationMapping` accepts either mapping; existing retained
|
|
594
|
+
mapping shapes and prepared payload hashes remain unchanged. An ordinary mapping
|
|
595
|
+
supports only noncash application, cash-refund recording and its reversal;
|
|
596
|
+
withhold/release are rejected before provider I/O. `cashAccountRef: null` is valid
|
|
597
|
+
for application; cash-refund recording requires an explicit reviewed bank account.
|
|
598
|
+
Durable reservations, authorization and uncertain-outcome recovery remain the
|
|
599
|
+
host's responsibility for either mapping.
|
|
600
|
+
|
|
588
601
|
`prepareQuickBooksReceivableRequest(input)` returns a persistable descriptor.
|
|
589
602
|
Amounts are positive safe integer **minor units**, exactly representable on the
|
|
590
603
|
currency grid. Source type/ID/customer, effective date, evidence and mapping version
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as QuickBooksWriteError } from "./errors-DIqXkm4s.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as validateQuickBooksReceivableMapping, f as validateQuickBooksCreditMemoRequest, h as isCurrencyMinorUnit, i as reconcileQuickBooksReceivableRecord, l as mapInvoiceToQBO, m as currencyMinorUnitFactor, n as mapQuickBooksReceivableRequest, o as validateQuickBooksReceivableRequest, p as validateQuickBooksInvoiceRequest, s as mapCreditMemoToQBO, t as isOrdinaryReceivableMapping } from "./receivable-transfer-DPxto4TY.js";
|
|
3
3
|
import { createHash, createHmac } from "node:crypto";
|
|
4
4
|
//#region src/providers/quickbooks/receivable-operations.ts
|
|
5
5
|
/** Each operation is separately durable in the host. This class does not pretend QBO supports a saga transaction. */
|
|
@@ -26,7 +26,7 @@ var QuickBooksReceivableTransfers = class {
|
|
|
26
26
|
if (customer.Active !== true || (customer.CurrencyRef?.value ?? (currencies.MultiCurrencyEnabled === false ? mapping.currency : void 0)) !== mapping.currency) throw new Error("Receivable customer must be active and use the verified home currency");
|
|
27
27
|
for (const [ref, type] of [
|
|
28
28
|
[mapping.receivablesAccountRef, "Accounts Receivable"],
|
|
29
|
-
[mapping.retainedAssetAccountRef, "Other Current Asset"],
|
|
29
|
+
...isOrdinaryReceivableMapping(mapping) ? [] : [[mapping.retainedAssetAccountRef, "Other Current Asset"]],
|
|
30
30
|
...mapping.cashAccountRef ? [[mapping.cashAccountRef, "Bank"]] : []
|
|
31
31
|
]) {
|
|
32
32
|
const account = await this.entity("Account", ref);
|
|
@@ -932,4 +932,4 @@ function mapQBOToAddress(qbo) {
|
|
|
932
932
|
//#endregion
|
|
933
933
|
export { QuickBooksProvider };
|
|
934
934
|
|
|
935
|
-
//# sourceMappingURL=quickbooks-
|
|
935
|
+
//# sourceMappingURL=quickbooks-Bo_BjMv1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quickbooks-Bo_BjMv1.js","names":[],"sources":["../../src/providers/quickbooks/receivable-operations.ts","../../src/providers/quickbooks/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { QuickBooksWriteError } from '../../errors.js';\nimport type { QuickBooksProvider } from './index.js';\nimport { currencyMinorUnitFactor, isCurrencyMinorUnit } from './line-amount.js';\nimport {\n isOrdinaryReceivableMapping,\n mapQuickBooksReceivableRequest,\n type QuickBooksReceivableOperationMapping,\n type QuickBooksReceivableReadback,\n type QuickBooksReceivableRequest,\n type QuickBooksReceivableTransferOperations,\n reconcileQuickBooksReceivableRecord,\n validateQuickBooksReceivableMapping,\n validateQuickBooksReceivableRequest,\n} from './receivable-transfer.js';\n\ntype ProviderRecord = Record<string, any>;\n/** Each operation is separately durable in the host. This class does not pretend QBO supports a saga transaction. */\nexport class QuickBooksReceivableTransfers\n implements QuickBooksReceivableTransferOperations\n{\n constructor(private provider: QuickBooksProvider) {}\n private assertScope(mapping: QuickBooksReceivableOperationMapping) {\n validateQuickBooksReceivableMapping(mapping);\n if (\n mapping.realmId !== this.provider.realmId ||\n mapping.environment !== this.provider.environment\n )\n throw new Error(\n 'Receivable mapping belongs to another provider realm or environment',\n );\n }\n private async entity(type: string, id: string): Promise<ProviderRecord> {\n if (!/^[A-Za-z0-9._-]{1,100}$/.test(id))\n throw new Error('Unsupported provider entity reference');\n const result = await this.provider.request<Record<string, ProviderRecord>>(\n 'GET',\n `${type.toLowerCase()}/${encodeURIComponent(id)}`,\n );\n const value = result[type];\n if (!value || value.Id !== id)\n throw new Error(`Provider ${type} identity differs`);\n return value;\n }\n async verifyMapping(mapping: QuickBooksReceivableOperationMapping) {\n this.assertScope(mapping);\n const prefs = await this.provider.request<{ Preferences?: ProviderRecord }>(\n 'GET',\n 'preferences',\n );\n const currencies = prefs.Preferences?.CurrencyPrefs;\n if (\n currencies?.HomeCurrency?.value !== mapping.currency ||\n typeof currencies?.MultiCurrencyEnabled !== 'boolean'\n )\n throw new Error(\n 'Receivable transfers require verified home currency; foreign exchange is unsupported',\n );\n const customer = await this.entity('Customer', mapping.customerRef);\n if (\n customer.Active !== true ||\n (customer.CurrencyRef?.value ??\n (currencies.MultiCurrencyEnabled === false\n ? mapping.currency\n : undefined)) !== mapping.currency\n )\n throw new Error(\n 'Receivable customer must be active and use the verified home currency',\n );\n for (const [ref, type] of [\n [mapping.receivablesAccountRef, 'Accounts Receivable'],\n ...(isOrdinaryReceivableMapping(mapping)\n ? []\n : [[mapping.retainedAssetAccountRef, 'Other Current Asset']]),\n ...(mapping.cashAccountRef ? [[mapping.cashAccountRef, 'Bank']] : []),\n ]) {\n const account = await this.entity('Account', ref);\n if (\n account.Active !== true ||\n account.AccountType !== type ||\n (account.CurrencyRef !== undefined &&\n account.CurrencyRef?.value !== mapping.currency)\n )\n throw new Error(\n 'Receivable account type, activity or currency differs from the reviewed mapping',\n );\n }\n return {\n mappingHash: createHash('sha256')\n .update(JSON.stringify(mapping))\n .digest('hex'),\n homeCurrency: mapping.currency,\n };\n }\n private currency(\n record: ProviderRecord,\n mapping: QuickBooksReceivableOperationMapping,\n ) {\n if (record.CurrencyRef?.value !== mapping.currency)\n throw new Error('Provider transaction currency differs');\n }\n private minor(amount: unknown, currency: string): number {\n if (typeof amount !== 'number' || !isCurrencyMinorUnit(amount, currency))\n throw new Error(\n 'Provider amount is missing or outside the exact currency grid',\n );\n const value = Math.round(amount * currencyMinorUnitFactor(currency)!);\n if (!Number.isSafeInteger(value) || value < 0)\n throw new Error('Provider amount is outside supported safe minor units');\n return value;\n }\n private journalDirection(\n record: ProviderRecord,\n mapping: QuickBooksReceivableOperationMapping,\n ): { kind: 'debit' | 'credit'; amountMinor: number } {\n this.currency(record, mapping);\n if (!Array.isArray(record.Line))\n throw new Error('Provider journal lines are missing');\n const ar = record.Line.filter(\n (line: ProviderRecord) =>\n line.JournalEntryLineDetail?.AccountRef?.value ===\n mapping.receivablesAccountRef,\n );\n if (ar.length !== 1)\n throw new Error(\n 'Provider receivable journal needs exactly one reviewed AR line',\n );\n const detail = ar[0].JournalEntryLineDetail;\n if (\n detail.Entity?.Type !== 'Customer' ||\n detail.Entity?.EntityRef?.value !== mapping.customerRef ||\n !['Debit', 'Credit'].includes(detail.PostingType)\n )\n throw new Error('Provider journal customer or AR direction differs');\n return {\n kind: detail.PostingType === 'Debit' ? 'debit' : 'credit',\n amountMinor: this.minor(ar[0].Amount, mapping.currency),\n };\n }\n private async customerPayments(\n mapping: QuickBooksReceivableOperationMapping,\n ): Promise<ProviderRecord[]> {\n const rows: ProviderRecord[] = [];\n // Complete pagination is mandatory for capacity; no ordinary list default cap may truncate it.\n for (let page = 0; page < 10000; page++) {\n const query = `SELECT * FROM Payment WHERE CustomerRef = '${mapping.customerRef}' STARTPOSITION ${page * 100 + 1} MAXRESULTS 100`;\n const result = await this.provider.request<{\n QueryResponse?: { Payment?: ProviderRecord[] };\n }>('GET', `query?query=${encodeURIComponent(query)}`);\n if (!result.QueryResponse)\n throw new Error('Provider payment query omitted its result');\n const batch = result.QueryResponse.Payment ?? [];\n if (!Array.isArray(batch))\n throw new Error('Provider payment query is malformed');\n rows.push(...batch);\n if (batch.length < 100) return rows;\n }\n throw new Error(\n 'Complete provider payment history is required before receivable application',\n );\n }\n private async available(\n ref: { type: string; id: string },\n mapping: QuickBooksReceivableOperationMapping,\n direction: 'debit' | 'credit',\n ) {\n const record = await this.entity(ref.type, ref.id);\n this.currency(record, mapping);\n if (ref.type !== 'JournalEntry') {\n if (record.CustomerRef?.value !== mapping.customerRef)\n throw new Error('Application transaction belongs to another customer');\n return this.minor(\n ref.type === 'Invoice' ? record.Balance : record.RemainingCredit,\n mapping.currency,\n );\n }\n const journal = this.journalDirection(record, mapping);\n if (journal.kind !== direction)\n throw new Error('Application journal has the wrong receivable direction');\n let used = 0n;\n for (const payment of await this.customerPayments(mapping)) {\n if (payment.CustomerRef?.value !== mapping.customerRef)\n throw new Error('Payment query crossed customer authority');\n for (const line of payment.Line ?? []) {\n const links = line.LinkedTxn ?? [];\n if (\n links.some(\n (link: ProviderRecord) =>\n link.TxnType === 'JournalEntry' && link.TxnId === ref.id,\n )\n ) {\n if (links.length !== 1)\n throw new Error(\n 'Ambiguous multi-transaction payment allocation requires reconciliation',\n );\n this.currency(payment, mapping);\n used += BigInt(this.minor(line.Amount, mapping.currency));\n }\n }\n }\n const available = BigInt(journal.amountMinor) - used;\n if (available < 0n)\n throw new Error(\n 'Provider journal is overapplied and requires reconciliation',\n );\n return Number(available);\n }\n private async preflight(request: QuickBooksReceivableRequest) {\n await this.verifyMapping(request.input.mapping);\n const input = request.input,\n source = await this.entity(input.source.type, input.source.id);\n this.currency(source, input.mapping);\n if (input.source.type === 'JournalEntry')\n this.journalDirection(source, input.mapping);\n else if (source.CustomerRef?.value !== input.mapping.customerRef)\n throw new Error(\n 'Source provider transaction belongs to another customer',\n );\n if (input.kind === 'application') {\n const debit = await this.available(input.debit, input.mapping, 'debit'),\n credit = await this.available(input.credit, input.mapping, 'credit');\n if (input.amountMinor > debit || input.amountMinor > credit)\n throw new Error(\n 'Noncash application exceeds current source debit or credit capacity',\n );\n }\n }\n async execute(\n request: QuickBooksReceivableRequest,\n ): Promise<QuickBooksReceivableReadback> {\n // Reconstruct and retain exact bytes before any asynchronous metadata lookup.\n const retained = structuredClone(request);\n validateQuickBooksReceivableRequest(\n retained,\n this.provider.realmId,\n this.provider.environment,\n );\n const body = mapQuickBooksReceivableRequest(retained.input);\n await this.preflight(retained);\n const response = await this.provider.request<\n Record<string, ProviderRecord>\n >('POST', retained.endpoint, body, retained);\n const type =\n retained.endpoint === 'journalentry' ? 'JournalEntry' : 'Payment';\n // A malformed success is unresolved, never a confirmed operation.\n try {\n return reconcileQuickBooksReceivableRecord(retained, response[type]);\n } catch (cause) {\n const externalId = response?.[type]?.Id;\n throw new QuickBooksWriteError({\n outcome: 'unknown',\n realmId: retained.realmId,\n environment: retained.environment,\n endpoint: retained.endpoint,\n requestId: retained.requestId,\n payloadHash: retained.payloadHash,\n externalId:\n typeof externalId === 'string' && externalId ? externalId : undefined,\n cause,\n });\n }\n }\n async read(\n request: QuickBooksReceivableRequest,\n externalId: string,\n ): Promise<QuickBooksReceivableReadback> {\n const retained = structuredClone(request);\n validateQuickBooksReceivableRequest(\n retained,\n this.provider.realmId,\n this.provider.environment,\n );\n const type =\n retained.endpoint === 'journalentry' ? 'JournalEntry' : 'Payment';\n return reconcileQuickBooksReceivableRecord(\n retained,\n await this.entity(type, externalId),\n );\n }\n}\n","import { QuickBooksReceivableTransfers } from './receivable-operations.js';\nimport {\n type QuickBooksReceivableRequest,\n validateQuickBooksReceivableRequest,\n} from './receivable-transfer.js';\n/**\n * QuickBooks Online Provider\n *\n * Implements the AccountingProvider interface for QuickBooks Online.\n * Uses the Intuit OAuth2 library for authentication and the QBO API for operations.\n */\n\n/// <reference path=\"../../intuit-oauth.d.ts\" />\n\nimport { createHmac } from 'node:crypto';\nimport { QuickBooksWriteError } from '../../errors.js';\nimport type {\n AccountingProvider,\n Address,\n AuditDiscrepancy,\n AuditMatch,\n AuditOperations,\n AuditReport,\n BillInput,\n BillOperations,\n CreditMemoInput,\n CreditMemoOperations,\n CustomerInput,\n CustomerOperations,\n DateRange,\n ExternalBill,\n ExternalCustomer,\n ExternalInvoice,\n ExternalPayment,\n ExternalRecord,\n ExternalVendor,\n FieldDiff,\n InvoiceInput,\n InvoiceOperations,\n ListOptions,\n PaymentInput,\n PaymentOperations,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n QuickBooksOptions,\n SyncResult,\n TokenSet,\n VendorInput,\n VendorOperations,\n WebhookEvent,\n WebhookOperations,\n} from '../../types.js';\nimport {\n mapCreditMemoToQBO,\n mapInvoiceToQBO,\n validateQuickBooksCreditMemoRequest,\n validateQuickBooksInvoiceRequest,\n} from './invoice-request.js';\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Format a Date to YYYY-MM-DD in local timezone (not UTC)\n * This prevents timezone conversion issues where dates shift by a day\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\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Compare two values for equality (handles dates, objects, etc.)\n */\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (typeof a === 'number' && typeof b === 'number') {\n // Allow for floating point precision issues\n return Math.abs(a - b) < 0.01;\n }\n return false;\n}\n\n// =============================================================================\n// QuickBooks Provider\n// =============================================================================\n\n/**\n * QuickBooks Online accounting provider\n */\nexport class QuickBooksProvider implements AccountingProvider {\n readonly type = 'quickbooks' as const;\n readonly receivableTransfers: QuickBooksReceivableTransfers;\n\n private options: QuickBooksOptions;\n private accessToken: string | null = null;\n private tokenExpiresAt: Date | null = null;\n\n readonly customers: CustomerOperations;\n readonly invoices: InvoiceOperations;\n readonly creditMemos: CreditMemoOperations;\n readonly vendors: VendorOperations;\n readonly bills: BillOperations;\n readonly payments: PaymentOperations;\n readonly audit: AuditOperations;\n readonly webhooks: WebhookOperations;\n\n constructor(options: QuickBooksOptions) {\n this.options = {\n timeout: 30000,\n maxRetries: 3,\n ...options,\n };\n\n this.receivableTransfers = new QuickBooksReceivableTransfers(this);\n // Initialize operation handlers\n this.customers = new QuickBooksCustomerOperations(this);\n this.invoices = new QuickBooksInvoiceOperations(this);\n this.creditMemos = new QuickBooksCreditMemoOperations(this);\n this.vendors = new QuickBooksVendorOperations(this);\n this.bills = new QuickBooksBillOperations(this);\n this.payments = new QuickBooksPaymentOperations(this);\n this.audit = new QuickBooksAuditOperations(this);\n this.webhooks = new QuickBooksWebhookOperations(this.options);\n }\n\n /**\n * Get the QBO API base URL\n */\n get baseUrl(): string {\n return this.options.environment === 'production'\n ? 'https://quickbooks.api.intuit.com'\n : 'https://sandbox-quickbooks.api.intuit.com';\n }\n\n /**\n * Get the company/realm ID\n */\n get environment(): 'sandbox' | 'production' {\n return this.options.environment === 'production' ? 'production' : 'sandbox';\n }\n\n get realmId(): string {\n return this.options.realmId;\n }\n\n /**\n * Ensure we have a valid access token, refreshing if needed\n */\n async ensureAccessToken(): Promise<string> {\n // Check if current token is still valid (with 5 min buffer)\n if (this.accessToken && this.tokenExpiresAt) {\n const bufferMs = 5 * 60 * 1000;\n if (new Date().getTime() < this.tokenExpiresAt.getTime() - bufferMs) {\n return this.accessToken;\n }\n }\n\n // Refresh the token\n const tokens = await this.refreshAccessToken();\n this.accessToken = tokens.accessToken;\n this.tokenExpiresAt = tokens.expiresAt;\n\n // Update stored refresh token so subsequent refreshes use the new token\n this.options.refreshToken = tokens.refreshToken;\n\n // Notify callback if provided\n if (this.options.onTokenRefresh) {\n await this.options.onTokenRefresh(tokens);\n }\n\n return this.accessToken;\n }\n\n /**\n * Refresh the OAuth access token\n */\n private async refreshAccessToken(): Promise<TokenSet> {\n // Import intuit-oauth dynamically\n const OAuthClient = (await import('intuit-oauth')).default;\n\n const redirectUri =\n this.options.redirectUri ||\n 'https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl';\n\n const oauthClient = new OAuthClient({\n clientId: this.options.clientId,\n clientSecret: this.options.clientSecret,\n environment:\n this.options.environment === 'production' ? 'production' : 'sandbox',\n redirectUri,\n });\n\n oauthClient.setToken({\n refresh_token: this.options.refreshToken,\n access_token: this.accessToken || '',\n });\n\n const response = await oauthClient.refresh();\n const token = response.getJson();\n\n return {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt: new Date(Date.now() + token.expires_in * 1000),\n tokenType: token.token_type,\n };\n }\n\n /**\n * Make an authenticated request to the QBO API with timeout and retry support\n */\n async request<T>(\n method: 'GET' | 'POST' | 'DELETE',\n endpoint: string,\n body?: unknown,\n createRequest?:\n | QuickBooksInvoiceRequest\n | QuickBooksCreditMemoRequest\n | QuickBooksReceivableRequest,\n ): Promise<T> {\n // Freeze identity and bytes before any asynchronous work.\n const serializedBody =\n body === undefined ? undefined : JSON.stringify(body);\n const realmId = this.realmId;\n const environment =\n this.options.environment === 'production' ? 'production' : 'sandbox';\n if (createRequest) {\n if (\n method !== 'POST' ||\n !['invoice', 'creditmemo', 'journalentry', 'payment'].includes(endpoint)\n ) {\n throw new Error(\n 'QuickBooks request identity is only supported for prepared invoice, credit memo, journal or noncash application creation',\n );\n }\n if (endpoint === 'journalentry' || endpoint === 'payment') {\n if (\n !('endpoint' in createRequest) ||\n createRequest.endpoint !== endpoint\n )\n throw new Error('Receivable endpoint differs from request identity');\n validateQuickBooksReceivableRequest(\n createRequest,\n realmId,\n environment,\n serializedBody,\n );\n } else if (endpoint === 'invoice')\n validateQuickBooksInvoiceRequest(\n createRequest as QuickBooksInvoiceRequest,\n realmId,\n environment,\n serializedBody,\n );\n else\n validateQuickBooksCreditMemoRequest(\n createRequest as QuickBooksCreditMemoRequest,\n realmId,\n environment,\n serializedBody,\n );\n }\n const requestId = createRequest?.requestId;\n const payloadHash = createRequest?.payloadHash;\n const url = new URL(`${this.baseUrl}/v3/company/${realmId}/${endpoint}`);\n if (requestId) url.searchParams.set('requestid', requestId);\n const timeout = this.options.timeout ?? 30000;\n const maxRetries =\n method === 'GET' || requestId ? (this.options.maxRetries ?? 3) : 0;\n const responseEntity = [\n 'Customer',\n 'Vendor',\n 'Bill',\n 'Invoice',\n 'CreditMemo',\n 'Payment',\n 'JournalEntry',\n ].find((entity) => entity.toLowerCase() === endpoint.split(/[/?]/, 1)[0]);\n const accessToken = await this.ensureAccessToken();\n // A persisted identity may have been sent by an earlier worker. Without a\n // durable attempt history, even its first observed 4xx cannot prove that\n // the logical write was never accepted. Fail closed across process retries.\n let uncertain = requestId !== undefined;\n\n for (let attempt = 0; ; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n let status: number | undefined;\n let failure: unknown;\n try {\n const response = await fetch(url.toString(), {\n method,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: serializedBody,\n signal: controller.signal,\n });\n status = response.status;\n if (!response.ok) {\n throw new Error(\n `QBO API error (${status}): ${await response.text()}`,\n );\n }\n const result = await response.json();\n // Every supported write must return a usable remote identity. Validate\n // inside this boundary so malformed successes cannot escape reconciliation.\n if (\n method !== 'GET' &&\n responseEntity &&\n (typeof result?.[responseEntity]?.Id !== 'string' ||\n !result[responseEntity].Id.trim())\n ) {\n throw new Error(`QBO response is missing ${responseEntity}.Id`);\n }\n return result as T;\n } catch (error) {\n failure = error;\n uncertain ||=\n status === undefined ||\n status >= 500 ||\n (status >= 200 && status < 300);\n } finally {\n clearTimeout(timeoutId);\n }\n const retryable =\n status === undefined ||\n status === 429 ||\n status >= 500 ||\n (status >= 200 && status < 300);\n if (!retryable || attempt >= maxRetries) {\n if (method !== 'GET') {\n throw new QuickBooksWriteError({\n realmId,\n environment,\n endpoint,\n requestId,\n status,\n payloadHash,\n outcome: uncertain ? 'unknown' : 'rejected',\n cause: failure,\n });\n }\n throw failure;\n }\n await sleep(2 ** attempt * 1000);\n }\n }\n\n /**\n * Execute a QBO query with pagination support\n */\n async queryAll<T>(\n entity: string,\n whereClause?: string,\n maxResults = 1000,\n ): Promise<T[]> {\n const results: T[] = [];\n let startPosition = 1;\n const pageSize = 100; // QBO max is 1000, but smaller pages are safer\n\n while (results.length < maxResults) {\n let query = `SELECT * FROM ${entity}`;\n if (whereClause) {\n query += ` WHERE ${whereClause}`;\n }\n query += ` MAXRESULTS ${pageSize} STARTPOSITION ${startPosition}`;\n\n const response = await this.request<{\n QueryResponse: Record<string, T[] | undefined>;\n }>('GET', `query?query=${encodeURIComponent(query)}`);\n\n const items = response.QueryResponse[entity] || [];\n results.push(...items);\n\n // If we got fewer than pageSize, we've reached the end\n if (items.length < pageSize) {\n break;\n }\n\n startPosition += pageSize;\n }\n\n return results;\n }\n}\n\n// =============================================================================\n// Customer Operations\n// =============================================================================\n\nclass QuickBooksCustomerOperations implements CustomerOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(customer: CustomerInput): Promise<SyncResult> {\n const qboCustomer = mapCustomerToQBO(customer);\n\n const response = await this.provider.request<{ Customer: QBOCustomer }>(\n 'POST',\n 'customer',\n qboCustomer,\n );\n\n return {\n action: 'created',\n externalId: response.Customer.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalCustomer> {\n const response = await this.provider.request<{ Customer: QBOCustomer }>(\n 'GET',\n `customer/${externalId}`,\n );\n\n return mapQBOToCustomer(response.Customer);\n }\n\n async list(options?: ListOptions): Promise<ExternalCustomer[]> {\n const limit = options?.limit || 1000;\n const customers = await this.provider.queryAll<QBOCustomer>(\n 'Customer',\n undefined,\n limit,\n );\n return customers.map(mapQBOToCustomer);\n }\n\n async sync(customer: CustomerInput): Promise<SyncResult> {\n if (customer.externalId) {\n // Update existing\n const existing = await this.provider.request<{ Customer: QBOCustomer }>(\n 'GET',\n `customer/${customer.externalId}`,\n );\n\n const qboCustomer: QBOCustomerUpdate = {\n ...mapCustomerToQBO(customer),\n Id: customer.externalId,\n SyncToken: existing.Customer.SyncToken,\n };\n\n await this.provider.request('POST', 'customer', qboCustomer);\n\n return {\n action: 'updated',\n externalId: customer.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(customer);\n }\n}\n\n// =============================================================================\n// Invoice Operations\n// =============================================================================\n\nclass QuickBooksInvoiceOperations implements InvoiceOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(invoice: InvoiceInput): Promise<SyncResult> {\n if (invoice.externalId && invoice.quickbooksRequest)\n throw new Error(\n 'QuickBooks invoice request identity cannot be used for updates',\n );\n const qboInvoice = mapInvoiceToQBO(invoice);\n\n const response = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'POST',\n 'invoice',\n qboInvoice,\n invoice.quickbooksRequest,\n );\n\n return {\n action: 'created',\n externalId: response.Invoice.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalInvoice> {\n const response = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${externalId}`,\n );\n\n return mapQBOToInvoice(response.Invoice);\n }\n\n async list(options?: ListOptions): Promise<ExternalInvoice[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const invoices = await this.provider.queryAll<QBOInvoice>(\n 'Invoice',\n whereClause,\n limit,\n );\n return invoices.map(mapQBOToInvoice);\n }\n\n async sync(invoice: InvoiceInput): Promise<SyncResult> {\n if (invoice.externalId) {\n if (invoice.quickbooksRequest)\n throw new Error(\n 'QuickBooks invoice request identity cannot be used for updates',\n );\n const existing = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${invoice.externalId}`,\n );\n\n const qboInvoice: QBOInvoiceUpdate = {\n ...mapInvoiceToQBO(invoice),\n Id: invoice.externalId,\n SyncToken: existing.Invoice.SyncToken,\n };\n\n await this.provider.request('POST', 'invoice', qboInvoice);\n\n return {\n action: 'updated',\n externalId: invoice.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(invoice);\n }\n\n async send(externalId: string): Promise<void> {\n await this.provider.request('POST', `invoice/${externalId}/send`);\n }\n\n async void(externalId: string): Promise<void> {\n const existing = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${externalId}`,\n );\n\n await this.provider.request('POST', 'invoice', {\n Id: externalId,\n SyncToken: existing.Invoice.SyncToken,\n sparse: true,\n // QBO doesn't have a Void field - you delete the invoice instead\n // or create a credit memo. For now, we'll use sparse update to mark private note\n PrivateNote: 'VOIDED',\n });\n }\n}\n\n// =============================================================================\n// Credit memo operations\n// =============================================================================\n\nclass QuickBooksCreditMemoOperations implements CreditMemoOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async pull(externalId: string): Promise<ExternalRecord> {\n if (\n !externalId ||\n externalId.trim() !== externalId ||\n externalId.length > 500\n )\n throw new Error(\n 'QuickBooks credit memo readback requires an exact external ID',\n );\n const response = await this.provider.request<{\n CreditMemo: Record<string, unknown>;\n }>('GET', `creditmemo/${encodeURIComponent(externalId)}`);\n if (!response.CreditMemo || response.CreditMemo.Id !== externalId)\n throw new Error('QuickBooks credit memo readback identity differs');\n return {\n provider: 'quickbooks',\n externalId,\n syncedAt: new Date(),\n raw: response.CreditMemo,\n };\n }\n\n async push(creditMemo: CreditMemoInput): Promise<SyncResult> {\n if (creditMemo.externalId && creditMemo.quickbooksCreditMemoRequest)\n throw new Error(\n 'QuickBooks credit memo request identity cannot be used for updates',\n );\n const mapped = mapCreditMemoToQBO(creditMemo);\n if (\n creditMemo.quickbooksCreditMemoRequest &&\n creditMemo.quickbooksCreditMemoRequest.creditedInvoiceExternalId !==\n creditMemo.creditedInvoiceExternalId\n )\n throw new Error(\n 'QuickBooks credit memo request linkage mismatch; reconcile the original request',\n );\n const response = await this.provider.request<{\n CreditMemo: { Id: string };\n }>('POST', 'creditmemo', mapped, creditMemo.quickbooksCreditMemoRequest);\n return {\n action: 'created',\n externalId: response.CreditMemo.Id,\n syncedAt: new Date(),\n };\n }\n\n async sync(creditMemo: CreditMemoInput): Promise<SyncResult> {\n if (!creditMemo.externalId) return this.push(creditMemo);\n if (creditMemo.quickbooksCreditMemoRequest)\n throw new Error(\n 'QuickBooks credit memo request identity cannot be used for updates',\n );\n // Refuse malformed frozen snapshots before authenticating or contacting QBO.\n const mapped = mapCreditMemoToQBO(creditMemo);\n const existing = await this.provider.request<{\n CreditMemo: { SyncToken: string };\n }>('GET', `creditmemo/${creditMemo.externalId}`);\n await this.provider.request('POST', 'creditmemo', {\n ...mapped,\n Id: creditMemo.externalId,\n SyncToken: existing.CreditMemo.SyncToken,\n });\n return {\n action: 'updated',\n externalId: creditMemo.externalId,\n syncedAt: new Date(),\n };\n }\n}\n\n// =============================================================================\n// Vendor Operations\n// =============================================================================\n\nclass QuickBooksVendorOperations implements VendorOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(vendor: VendorInput): Promise<SyncResult> {\n const qboVendor = mapVendorToQBO(vendor);\n\n const response = await this.provider.request<{ Vendor: QBOVendor }>(\n 'POST',\n 'vendor',\n qboVendor,\n );\n\n return {\n action: 'created',\n externalId: response.Vendor.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalVendor> {\n const response = await this.provider.request<{ Vendor: QBOVendor }>(\n 'GET',\n `vendor/${externalId}`,\n );\n\n return mapQBOToVendor(response.Vendor);\n }\n\n async list(options?: ListOptions): Promise<ExternalVendor[]> {\n const limit = options?.limit || 1000;\n const vendors = await this.provider.queryAll<QBOVendor>(\n 'Vendor',\n undefined,\n limit,\n );\n return vendors.map(mapQBOToVendor);\n }\n\n async sync(vendor: VendorInput): Promise<SyncResult> {\n if (vendor.externalId) {\n const existing = await this.provider.request<{ Vendor: QBOVendor }>(\n 'GET',\n `vendor/${vendor.externalId}`,\n );\n\n const qboVendor: QBOVendorUpdate = {\n ...mapVendorToQBO(vendor),\n Id: vendor.externalId,\n SyncToken: existing.Vendor.SyncToken,\n };\n\n await this.provider.request('POST', 'vendor', qboVendor);\n\n return {\n action: 'updated',\n externalId: vendor.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(vendor);\n }\n}\n\n// =============================================================================\n// Bill Operations\n// =============================================================================\n\nclass QuickBooksBillOperations implements BillOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(bill: BillInput): Promise<SyncResult> {\n const qboBill = mapBillToQBO(bill);\n\n const response = await this.provider.request<{ Bill: QBOBill }>(\n 'POST',\n 'bill',\n qboBill,\n );\n\n return {\n action: 'created',\n externalId: response.Bill.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalBill> {\n const response = await this.provider.request<{ Bill: QBOBill }>(\n 'GET',\n `bill/${externalId}`,\n );\n\n return mapQBOToBill(response.Bill);\n }\n\n async list(options?: ListOptions): Promise<ExternalBill[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const bills = await this.provider.queryAll<QBOBill>(\n 'Bill',\n whereClause,\n limit,\n );\n return bills.map(mapQBOToBill);\n }\n\n async sync(bill: BillInput): Promise<SyncResult> {\n if (bill.externalId) {\n const existing = await this.provider.request<{ Bill: QBOBill }>(\n 'GET',\n `bill/${bill.externalId}`,\n );\n\n const qboBill: QBOBillUpdate = {\n ...mapBillToQBO(bill),\n Id: bill.externalId,\n SyncToken: existing.Bill.SyncToken,\n };\n\n await this.provider.request('POST', 'bill', qboBill);\n\n return {\n action: 'updated',\n externalId: bill.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(bill);\n }\n}\n\n// =============================================================================\n// Payment Operations\n// =============================================================================\n\nclass QuickBooksPaymentOperations implements PaymentOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async pull(externalId: string): Promise<ExternalPayment> {\n const response = await this.provider.request<{ Payment: QBOPayment }>(\n 'GET',\n `payment/${externalId}`,\n );\n\n return mapQBOToPayment(response.Payment);\n }\n\n async list(options?: ListOptions): Promise<ExternalPayment[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const payments = await this.provider.queryAll<QBOPayment>(\n 'Payment',\n whereClause,\n limit,\n );\n return payments.map(mapQBOToPayment);\n }\n}\n\n// =============================================================================\n// Audit Operations\n// =============================================================================\n\nclass QuickBooksAuditOperations implements AuditOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async reconcileCustomers(\n locals: CustomerInput[],\n ): Promise<AuditReport<CustomerInput>> {\n const externals = await this.provider.customers.list({ limit: 10000 });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareCustomer,\n );\n }\n\n async reconcileInvoices(\n locals: InvoiceInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<InvoiceInput>> {\n const externals = await this.provider.invoices.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareInvoice,\n );\n }\n\n async reconcileVendors(\n locals: VendorInput[],\n ): Promise<AuditReport<VendorInput>> {\n const externals = await this.provider.vendors.list({ limit: 10000 });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareVendor,\n );\n }\n\n async reconcileBills(\n locals: BillInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<BillInput>> {\n const externals = await this.provider.bills.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareBill,\n );\n }\n\n async reconcilePayments(\n locals: PaymentInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<PaymentInput>> {\n const externals = await this.provider.payments.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n comparePayment,\n );\n }\n}\n\n/**\n * Generic reconciliation function with field comparison\n */\nfunction reconcileRecords<TLocal, TExternal extends ExternalRecord>(\n locals: TLocal[],\n externals: TExternal[],\n getLocalExternalId: (local: TLocal) => string | undefined,\n getExternalId: (external: TExternal) => string,\n compareFields: (local: TLocal, external: TExternal) => FieldDiff[],\n): AuditReport<TLocal> {\n const externalMap = new Map(externals.map((e) => [getExternalId(e), e]));\n const matchedExternalIds = new Set<string>();\n\n const matched: AuditMatch<TLocal>[] = [];\n const localOnly: TLocal[] = [];\n const discrepancies: AuditDiscrepancy<TLocal>[] = [];\n\n for (const local of locals) {\n const externalId = getLocalExternalId(local);\n if (externalId && externalMap.has(externalId)) {\n const external = externalMap.get(externalId)!;\n matchedExternalIds.add(externalId);\n\n // Compare fields\n const differences = compareFields(local, external);\n\n if (differences.length === 0) {\n matched.push({\n local,\n external,\n status: 'identical',\n });\n } else {\n discrepancies.push({\n local,\n external,\n differences,\n });\n }\n } else {\n localOnly.push(local);\n }\n }\n\n const externalOnly = externals.filter(\n (e) => !matchedExternalIds.has(getExternalId(e)),\n );\n\n return {\n provider: 'quickbooks',\n auditedAt: new Date(),\n matched,\n localOnly,\n externalOnly,\n discrepancies,\n summary: {\n total: locals.length + externalOnly.length,\n matched: matched.length,\n localOnly: localOnly.length,\n externalOnly: externalOnly.length,\n discrepancies: discrepancies.length,\n },\n };\n}\n\n// Field comparison functions\nfunction compareCustomer(\n local: CustomerInput,\n external: ExternalCustomer,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (local.name !== external.name) {\n diffs.push({\n field: 'name',\n localValue: local.name,\n externalValue: external.name,\n });\n }\n if (local.email !== external.email) {\n diffs.push({\n field: 'email',\n localValue: local.email,\n externalValue: external.email,\n });\n }\n\n return diffs;\n}\n\nfunction compareInvoice(\n local: InvoiceInput,\n external: ExternalInvoice,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.totalAmount, external.totalAmount)) {\n diffs.push({\n field: 'totalAmount',\n localValue: local.totalAmount,\n externalValue: external.totalAmount,\n });\n }\n if (local.invoiceNumber !== external.invoiceNumber) {\n diffs.push({\n field: 'invoiceNumber',\n localValue: local.invoiceNumber,\n externalValue: external.invoiceNumber,\n });\n }\n\n return diffs;\n}\n\nfunction compareVendor(\n local: VendorInput,\n external: ExternalVendor,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (local.name !== external.name) {\n diffs.push({\n field: 'name',\n localValue: local.name,\n externalValue: external.name,\n });\n }\n if (local.email !== external.email) {\n diffs.push({\n field: 'email',\n localValue: local.email,\n externalValue: external.email,\n });\n }\n\n return diffs;\n}\n\nfunction compareBill(local: BillInput, external: ExternalBill): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.totalAmount, external.totalAmount)) {\n diffs.push({\n field: 'totalAmount',\n localValue: local.totalAmount,\n externalValue: external.totalAmount,\n });\n }\n\n return diffs;\n}\n\nfunction comparePayment(\n local: PaymentInput,\n external: ExternalPayment,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.amount, external.amount)) {\n diffs.push({\n field: 'amount',\n localValue: local.amount,\n externalValue: external.amount,\n });\n }\n\n return diffs;\n}\n\n// =============================================================================\n// Webhook Operations\n// =============================================================================\n\nclass QuickBooksWebhookOperations implements WebhookOperations {\n constructor(private options: QuickBooksOptions) {}\n\n /**\n * Verify webhook signature using HMAC-SHA256\n * @see https://developer.intuit.com/app/developer/qbo/docs/develop/webhooks/verify-webhooks\n */\n verify(payload: string, signature: string, secret: string): boolean {\n // Use provided secret or fall back to configured webhook verifier token\n const verifierToken = secret || this.options.webhookVerifierToken;\n\n if (!verifierToken) {\n throw new Error(\n 'Webhook verifier token not provided. Pass it as the secret parameter or configure webhookVerifierToken in options.',\n );\n }\n\n // QBO uses HMAC-SHA256 and base64 encodes the signature\n const hmac = createHmac('sha256', verifierToken);\n hmac.update(payload);\n const expectedSignature = hmac.digest('base64');\n\n // Constant-time comparison to prevent timing attacks\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < signature.length; i++) {\n result |= signature.charCodeAt(i) ^ expectedSignature.charCodeAt(i);\n }\n return result === 0;\n }\n\n parse(payload: string): WebhookEvent {\n let data: QBOWebhookPayload;\n try {\n data = JSON.parse(payload) as QBOWebhookPayload;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown JSON parse error';\n throw new Error(`Invalid QuickBooks webhook payload: ${message}`);\n }\n\n // QBO webhook payload structure\n const eventNotifications = data.eventNotifications || [];\n const firstEvent = eventNotifications[0]?.dataChangeEvent?.entities?.[0];\n\n return {\n type: firstEvent?.operation || 'unknown',\n provider: 'quickbooks',\n timestamp: new Date(),\n payload: data,\n resourceType: mapQBOResourceType(firstEvent?.name),\n resourceId: firstEvent?.id,\n };\n }\n}\n\nfunction mapQBOResourceType(\n name?: string,\n): WebhookEvent['resourceType'] | undefined {\n switch (name?.toLowerCase()) {\n case 'customer':\n return 'customer';\n case 'invoice':\n return 'invoice';\n case 'payment':\n return 'payment';\n case 'vendor':\n return 'vendor';\n case 'bill':\n return 'bill';\n default:\n return undefined;\n }\n}\n\n// =============================================================================\n// Mapping Functions\n// =============================================================================\n\nfunction mapCustomerToQBO(customer: CustomerInput): QBOCustomerCreate {\n return {\n DisplayName: customer.name,\n PrimaryEmailAddr: customer.email ? { Address: customer.email } : undefined,\n PrimaryPhone: customer.phone\n ? { FreeFormNumber: customer.phone }\n : undefined,\n BillAddr: mapAddressToQBO(customer.billingAddress),\n ShipAddr: mapAddressToQBO(customer.shippingAddress),\n CurrencyRef: customer.currency ? { value: customer.currency } : undefined,\n };\n}\n\nfunction mapQBOToCustomer(qbo: QBOCustomer): ExternalCustomer {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n name: qbo.DisplayName,\n email: qbo.PrimaryEmailAddr?.Address,\n phone: qbo.PrimaryPhone?.FreeFormNumber,\n billingAddress: mapQBOToAddress(qbo.BillAddr),\n balance: qbo.Balance,\n currency: qbo.CurrencyRef?.value,\n raw: qbo,\n };\n}\n\nfunction mapQBOToInvoice(qbo: QBOInvoice): ExternalInvoice {\n const balance = qbo.Balance ?? 0;\n const totalAmount = qbo.TotalAmt ?? 0;\n\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n invoiceNumber: qbo.DocNumber || '',\n customerExternalId: qbo.CustomerRef?.value || '',\n issueDate: new Date(qbo.TxnDate),\n dueDate: new Date(qbo.DueDate),\n subtotal: totalAmount - (qbo.TxnTaxDetail?.TotalTax ?? 0),\n taxAmount: qbo.TxnTaxDetail?.TotalTax ?? 0,\n totalAmount,\n amountPaid: totalAmount - balance,\n balance,\n status: mapInvoiceStatus(balance, totalAmount, qbo.DueDate),\n currency: qbo.CurrencyRef?.value || 'USD',\n raw: qbo,\n };\n}\n\nfunction mapInvoiceStatus(\n balance: number,\n total: number,\n dueDate: string,\n): ExternalInvoice['status'] {\n if (balance === 0) return 'paid';\n if (balance < total) return 'viewed'; // Partial payment\n if (new Date(dueDate) < new Date()) return 'overdue';\n return 'sent';\n}\n\nfunction mapVendorToQBO(vendor: VendorInput): QBOVendorCreate {\n return {\n DisplayName: vendor.name,\n PrimaryEmailAddr: vendor.email ? { Address: vendor.email } : undefined,\n PrimaryPhone: vendor.phone ? { FreeFormNumber: vendor.phone } : undefined,\n BillAddr: mapAddressToQBO(vendor.address),\n TaxIdentifier: vendor.taxId,\n CurrencyRef: vendor.currency ? { value: vendor.currency } : undefined,\n };\n}\n\nfunction mapQBOToVendor(qbo: QBOVendor): ExternalVendor {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n name: qbo.DisplayName,\n email: qbo.PrimaryEmailAddr?.Address,\n phone: qbo.PrimaryPhone?.FreeFormNumber,\n address: mapQBOToAddress(qbo.BillAddr),\n balance: qbo.Balance,\n currency: qbo.CurrencyRef?.value,\n raw: qbo,\n };\n}\n\nfunction mapBillToQBO(bill: BillInput): QBOBillCreate {\n return {\n VendorRef: { value: bill.vendorExternalId || bill.vendorId },\n DocNumber: bill.billNumber,\n TxnDate: formatLocalDate(bill.billDate),\n DueDate: formatLocalDate(bill.dueDate),\n Line: bill.lineItems.map((item, idx) => ({\n LineNum: idx + 1,\n Description: item.description,\n Amount: item.amount ?? item.quantity * item.unitPrice,\n DetailType: 'AccountBasedExpenseLineDetail' as const,\n AccountBasedExpenseLineDetail: {\n AccountRef: item.accountCode ? { value: item.accountCode } : undefined,\n },\n })),\n CurrencyRef: bill.currency ? { value: bill.currency } : undefined,\n };\n}\n\nfunction mapQBOToBill(qbo: QBOBill): ExternalBill {\n const balance = qbo.Balance ?? 0;\n const totalAmount = qbo.TotalAmt ?? 0;\n\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n billNumber: qbo.DocNumber,\n vendorExternalId: qbo.VendorRef?.value || '',\n billDate: new Date(qbo.TxnDate),\n dueDate: new Date(qbo.DueDate),\n subtotal: totalAmount - (qbo.TxnTaxDetail?.TotalTax ?? 0),\n taxAmount: qbo.TxnTaxDetail?.TotalTax ?? 0,\n totalAmount,\n amountPaid: totalAmount - balance,\n balance,\n status: mapBillStatus(balance, totalAmount, qbo.DueDate),\n currency: qbo.CurrencyRef?.value || 'USD',\n raw: qbo,\n };\n}\n\nfunction mapBillStatus(\n balance: number,\n total: number,\n dueDate: string,\n): ExternalBill['status'] {\n if (balance === 0) return 'paid';\n if (new Date(dueDate) < new Date()) return 'overdue';\n return 'pending';\n}\n\nfunction mapQBOToPayment(qbo: QBOPayment): ExternalPayment {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n amount: qbo.TotalAmt ?? 0,\n currency: qbo.CurrencyRef?.value || 'USD',\n paidAt: new Date(qbo.TxnDate),\n method: qbo.PaymentMethodRef?.name,\n transactionId: qbo.PaymentRefNum,\n invoiceExternalIds: qbo.Line?.filter((l) => l.LinkedTxn).flatMap(\n (l) => l.LinkedTxn?.map((t) => t.TxnId) || [],\n ),\n status: 'completed',\n raw: qbo,\n };\n}\n\nfunction mapAddressToQBO(address?: Address): QBOAddress | undefined {\n if (!address) return undefined;\n return {\n Line1: address.street1,\n Line2: address.street2,\n City: address.city,\n CountrySubDivisionCode: address.state,\n PostalCode: address.postalCode,\n Country: address.country,\n };\n}\n\nfunction mapQBOToAddress(qbo?: QBOAddress): Address | undefined {\n if (!qbo) return undefined;\n return {\n street1: qbo.Line1,\n street2: qbo.Line2,\n city: qbo.City,\n state: qbo.CountrySubDivisionCode,\n postalCode: qbo.PostalCode,\n country: qbo.Country,\n };\n}\n\n// =============================================================================\n// QBO API Types (internal, strongly typed)\n// =============================================================================\n\ninterface QBORef {\n value: string;\n name?: string;\n}\n\ninterface QBOAddress {\n Line1?: string;\n Line2?: string;\n City?: string;\n CountrySubDivisionCode?: string;\n PostalCode?: string;\n Country?: string;\n}\n\ninterface QBOEmail {\n Address: string;\n}\n\ninterface QBOPhone {\n FreeFormNumber: string;\n}\n\n// Customer types\ninterface QBOCustomerBase {\n DisplayName: string;\n PrimaryEmailAddr?: QBOEmail;\n PrimaryPhone?: QBOPhone;\n BillAddr?: QBOAddress;\n ShipAddr?: QBOAddress;\n Balance?: number;\n CurrencyRef?: QBORef;\n}\n\ninterface QBOCustomerCreate extends QBOCustomerBase {}\n\ninterface QBOCustomerUpdate extends QBOCustomerBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOCustomer extends QBOCustomerBase {\n Id: string;\n SyncToken: string;\n}\n\n// Invoice types\ninterface QBOInvoiceLine {\n LineNum: number;\n Description?: string;\n Amount: number;\n DetailType: 'SalesItemLineDetail';\n SalesItemLineDetail?: {\n Qty?: number;\n UnitPrice?: number;\n ItemRef?: QBORef;\n TaxCodeRef?: QBORef;\n TaxInclusiveAmt?: number;\n };\n}\n\ninterface QBOInvoiceBase {\n CustomerRef: QBORef;\n DocNumber?: string;\n TxnDate: string;\n DueDate: string;\n Line: QBOInvoiceLine[];\n TotalAmt?: number;\n Balance?: number;\n TxnTaxDetail?: {\n TotalTax?: number;\n };\n GlobalTaxCalculation?: 'TaxExcluded' | 'TaxInclusive' | 'NotApplicable';\n CurrencyRef?: QBORef;\n CustomerMemo?: { value: string };\n}\n\ninterface QBOInvoiceUpdate extends QBOInvoiceBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOInvoice extends QBOInvoiceBase {\n Id: string;\n SyncToken: string;\n}\n\n// Vendor types\ninterface QBOVendorBase {\n DisplayName: string;\n PrimaryEmailAddr?: QBOEmail;\n PrimaryPhone?: QBOPhone;\n BillAddr?: QBOAddress;\n Balance?: number;\n TaxIdentifier?: string;\n CurrencyRef?: QBORef;\n}\n\ninterface QBOVendorCreate extends QBOVendorBase {}\n\ninterface QBOVendorUpdate extends QBOVendorBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOVendor extends QBOVendorBase {\n Id: string;\n SyncToken: string;\n}\n\n// Bill types\ninterface QBOBillLine {\n LineNum: number;\n Description?: string;\n Amount: number;\n DetailType: 'AccountBasedExpenseLineDetail';\n AccountBasedExpenseLineDetail?: {\n AccountRef?: QBORef;\n };\n}\n\ninterface QBOBillBase {\n VendorRef: QBORef;\n DocNumber?: string;\n TxnDate: string;\n DueDate: string;\n Line: QBOBillLine[];\n TotalAmt?: number;\n Balance?: number;\n TxnTaxDetail?: {\n TotalTax?: number;\n };\n CurrencyRef?: QBORef;\n}\n\ninterface QBOBillCreate extends QBOBillBase {}\n\ninterface QBOBillUpdate extends QBOBillBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOBill extends QBOBillBase {\n Id: string;\n SyncToken: string;\n}\n\n// Payment types\ninterface QBOPaymentLine {\n Amount: number;\n LinkedTxn?: {\n TxnId: string;\n TxnType: string;\n }[];\n}\n\ninterface QBOPayment {\n Id: string;\n SyncToken: string;\n TxnDate: string;\n TotalAmt?: number;\n CustomerRef?: QBORef;\n PaymentMethodRef?: QBORef;\n PaymentRefNum?: string;\n Line?: QBOPaymentLine[];\n CurrencyRef?: QBORef;\n}\n\n// Webhook types\ninterface QBOWebhookPayload {\n eventNotifications?: {\n realmId: string;\n dataChangeEvent?: {\n entities?: {\n name: string;\n id: string;\n operation: string;\n lastUpdated: string;\n }[];\n };\n }[];\n}\n"],"mappings":"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"}
|
|
@@ -480,6 +480,10 @@ function mapCreditMemoToQBO(creditMemo) {
|
|
|
480
480
|
//#endregion
|
|
481
481
|
//#region src/providers/quickbooks/receivable-transfer.ts
|
|
482
482
|
/** Exact, explicit receivable reclassification. No sales, tax or bank-transfer approximation. */
|
|
483
|
+
/** @internal */
|
|
484
|
+
function isOrdinaryReceivableMapping(mapping) {
|
|
485
|
+
return "kind" in mapping && mapping.kind === "ordinary";
|
|
486
|
+
}
|
|
483
487
|
var hash = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
484
488
|
function text(value, label, max = 1e3) {
|
|
485
489
|
if (typeof value !== "string" || !value || value !== value.trim() || value.length > max) throw new Error(`${label} must be explicit trimmed text`);
|
|
@@ -499,15 +503,17 @@ function minor(value, currency) {
|
|
|
499
503
|
return major;
|
|
500
504
|
}
|
|
501
505
|
function validateQuickBooksReceivableMapping(mapping) {
|
|
506
|
+
const ordinary = isOrdinaryReceivableMapping(mapping);
|
|
507
|
+
if ("kind" in mapping && !ordinary || ordinary && ("retainedAssetAccountRef" in mapping || "releaseDueDates" in mapping)) throw new Error("Receivable mapping kind and retention authority conflict");
|
|
502
508
|
id(mapping.realmId, "Realm");
|
|
503
509
|
id(mapping.customerRef, "Customer");
|
|
504
510
|
text(mapping.version, "Mapping version");
|
|
505
511
|
text(mapping.reviewEvidenceRef, "Mapping review evidence");
|
|
506
|
-
if (!["sandbox", "production"].includes(mapping.environment) || mapping.accountingBasis !== "accrual" || mapping.taxTiming !== "invoice-tax-point" || mapping.releaseDueDates !== "host-managed") throw new Error("Receivable transfers support explicit accrual, invoice-tax-point and host-managed release due dates only");
|
|
512
|
+
if (!["sandbox", "production"].includes(mapping.environment) || mapping.accountingBasis !== "accrual" || mapping.taxTiming !== "invoice-tax-point" || !ordinary && mapping.releaseDueDates !== "host-managed") throw new Error("Receivable transfers support explicit accrual, invoice-tax-point and host-managed release due dates only");
|
|
507
513
|
if (!/^[A-Z]{3}$/.test(mapping.currency) || !currencyMinorUnitFactor(mapping.currency)) throw new Error("Unsupported receivable currency");
|
|
508
514
|
const refs = [
|
|
509
515
|
mapping.receivablesAccountRef,
|
|
510
|
-
mapping.retainedAssetAccountRef,
|
|
516
|
+
...ordinary ? [] : [mapping.retainedAssetAccountRef],
|
|
511
517
|
...mapping.cashAccountRef === null ? [] : [mapping.cashAccountRef]
|
|
512
518
|
];
|
|
513
519
|
for (const ref of refs) id(ref, "Posting account");
|
|
@@ -515,6 +521,7 @@ function validateQuickBooksReceivableMapping(mapping) {
|
|
|
515
521
|
}
|
|
516
522
|
function validate(input) {
|
|
517
523
|
validateQuickBooksReceivableMapping(input.mapping);
|
|
524
|
+
if (isOrdinaryReceivableMapping(input.mapping) && (input.kind === "withhold" || input.kind === "release")) throw new Error("Ordinary receivable mapping cannot authorize retention transfers");
|
|
518
525
|
id(input.requestId, "Request");
|
|
519
526
|
if (input.requestId.length > 50) throw new Error("QuickBooks requestId must contain at most 50 characters");
|
|
520
527
|
date(input.effectiveOn);
|
|
@@ -650,6 +657,6 @@ function reconcileQuickBooksReceivableRecord(request, value) {
|
|
|
650
657
|
};
|
|
651
658
|
}
|
|
652
659
|
//#endregion
|
|
653
|
-
export {
|
|
660
|
+
export { validateQuickBooksReceivableMapping as a, mapDocumentTaxReadback as c, prepareQuickBooksInvoiceRequest as d, validateQuickBooksCreditMemoRequest as f, isCurrencyMinorUnit as h, reconcileQuickBooksReceivableRecord as i, mapInvoiceToQBO as l, currencyMinorUnitFactor as m, mapQuickBooksReceivableRequest as n, validateQuickBooksReceivableRequest as o, validateQuickBooksInvoiceRequest as p, prepareQuickBooksReceivableRequest as r, mapCreditMemoToQBO as s, isOrdinaryReceivableMapping as t, prepareQuickBooksCreditMemoRequest as u };
|
|
654
661
|
|
|
655
|
-
//# sourceMappingURL=receivable-transfer-
|
|
662
|
+
//# sourceMappingURL=receivable-transfer-DPxto4TY.js.map
|
package/dist/chunks/{receivable-transfer-DQmMBcRo.js.map → receivable-transfer-DPxto4TY.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receivable-transfer-DQmMBcRo.js","names":[],"sources":["../../src/providers/quickbooks/line-amount.ts","../../src/providers/quickbooks/invoice-request.ts","../../src/providers/quickbooks/receivable-transfer.ts"],"sourcesContent":["/** ISO 4217 List One, published 2026-09-17. Do not use Intl display digits:\n * ICU differs for e.g. IQD, MGA and RSD, and omits fund codes CLF/UYW.\n * https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml\n * N.A., unknown and missing codes cannot authorize currency rounding.\n */\nconst precisionGroups: readonly (readonly [number, string])[] = [\n [0, 'BIF CLP DJF GNF ISK JPY KMF KRW PYG RWF UGX UYI VND VUV XAF XOF XPF'],\n [\n 2,\n 'AED AFN ALL AMD AOA ARS AUD AWG AZN BAM BBD BDT BMD BND BOB BOV BRL BSD BTN BWP BYN BZD CAD CDF CHE CHF CHW CNY COP COU CRC CUP CVE CZK DKK DOP DZD EGP ERN ETB EUR FJD FKP GBP GEL GHS GIP GMD GTQ GYD HKD HNL HTG HUF IDR ILS INR IRR JMD KES KGS KHR KPW KYD KZT LAK LBP LKR LRD LSL MAD MDL MGA MKD MMK MNT MOP MRU MUR MVR MWK MXN MXV MYR MZN NAD NGN NIO NOK NPR NZD PAB PEN PGK PHP PKR PLN QAR RON RSD RUB SAR SBD SCR SDG SEK SGD SHP SLE SOS SRD SSP STN SVC SYP SZL THB TJS TMT TOP TRY TTD TWD TZS UAH USD USN UYU UZS VED VES WST XAD XCD XCG YER ZAR ZMW ZWG',\n ],\n [3, 'BHD IQD JOD KWD LYD OMR TND'],\n [4, 'CLF UYW'],\n];\nconst currencyPrecision = new Map(\n precisionGroups.flatMap(([precision, codes]) =>\n codes.split(' ').map((code) => [code, precision] as const),\n ),\n);\n\n/** ISO minor-unit factor, or undefined when the code is unknown or omitted. */\nexport function currencyMinorUnitFactor(\n currency: string | undefined,\n): number | undefined {\n if (typeof currency !== 'string') return undefined;\n const precision = currencyPrecision.get(currency.toUpperCase());\n return precision === undefined ? undefined : 10 ** precision;\n}\n\n/** True only for a finite amount exactly representable on the ISO minor-unit grid. */\nexport function isCurrencyMinorUnit(\n amount: number,\n currency: string | undefined,\n): boolean {\n if (!Number.isFinite(amount) || typeof currency !== 'string') return false;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return false;\n const value = decimalRatio(Math.abs(amount));\n return (\n (value.numerator * 10n ** BigInt(precision)) % value.denominator === 0n\n );\n}\n\n/** Round a finite major-unit amount half-up to a known ISO currency grid. */\nexport function roundCurrencyAmount(\n amount: number,\n currency: string | undefined,\n): number | undefined {\n if (!Number.isFinite(amount) || typeof currency !== 'string')\n return undefined;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return undefined;\n const sign = amount < 0 ? -1n : 1n;\n const value = decimalRatio(Math.abs(amount));\n const scale = 10n ** BigInt(precision);\n const numerator = value.numerator * scale;\n const rounded =\n numerator / value.denominator +\n ((numerator % value.denominator) * 2n >= value.denominator ? 1n : 0n);\n return Number(sign * rounded) / Number(scale);\n}\n\n/** Exact decimal interpretation of the finite nonnegative public number value. */\nfunction decimalRatio(value: number): {\n numerator: bigint;\n denominator: bigint;\n} {\n const [significand, exponent = '0'] = value.toString().split('e');\n const [whole, fraction = ''] = significand.split('.');\n const coefficient = BigInt(whole + fraction);\n const scale = fraction.length - Number(exponent);\n return scale >= 0\n ? { numerator: coefficient, denominator: 10n ** BigInt(scale) }\n : { numerator: coefficient * 10n ** BigInt(-scale), denominator: 1n };\n}\n\n/** Admit only the exact half-up minor-unit result; never rewrite caller money. */\nexport function matchesCurrencyRoundedLineAmount(\n quantity: number,\n unitPrice: number,\n amount: number,\n currency: string | undefined,\n): boolean {\n if (typeof currency !== 'string') return false;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return false;\n const minorScale = 10n ** BigInt(precision);\n const retained = decimalRatio(amount);\n const retainedMinor = retained.numerator * minorScale;\n // An off-grid caller amount is not permission to round their supplied money.\n if (retainedMinor % retained.denominator !== 0n) return false;\n const qty = decimalRatio(quantity);\n const price = decimalRatio(unitPrice);\n const numerator = qty.numerator * price.numerator * minorScale;\n const denominator = qty.denominator * price.denominator;\n const quotient = numerator / denominator;\n const rounded =\n quotient + ((numerator % denominator) * 2n >= denominator ? 1n : 0n);\n return retainedMinor / retained.denominator === rounded;\n}\n","import { createHash } from 'node:crypto';\nimport type {\n CreditMemoInput,\n InvoiceInput,\n InvoiceLineItemInput,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n} from '../../types.js';\nimport {\n currencyMinorUnitFactor,\n isCurrencyMinorUnit,\n matchesCurrencyRoundedLineAmount,\n roundCurrencyAmount,\n} from './line-amount.js';\n\ntype QuickBooksCreateRequest =\n | QuickBooksInvoiceRequest\n | QuickBooksCreditMemoRequest;\n\ninterface QuickBooksSalesLine {\n LineNum: number;\n Description: string;\n Amount: number;\n DetailType: 'SalesItemLineDetail';\n SalesItemLineDetail: {\n Qty: number;\n UnitPrice: number;\n ItemRef?: { value: string };\n TaxCodeRef?: { value: string };\n TaxInclusiveAmt?: number;\n };\n}\n\ninterface QuickBooksTaxLine {\n Amount: number;\n DetailType: 'TaxLineDetail';\n TaxLineDetail: {\n TaxRateRef: { value: string };\n TaxPercent: number;\n PercentBased: true;\n NetAmountTaxable?: number;\n };\n}\n\ninterface FrozenTaxComponent {\n taxRateRef: string;\n rate: DecimalRate;\n taxMinor: bigint;\n compound: boolean;\n basisMinor: bigint;\n explicitBasis: boolean;\n}\n\ninterface DecimalRate {\n numerator: bigint;\n denominator: bigint;\n value: number;\n}\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 return prepareRequest(mapInvoiceToQBO(invoice), identity, 'invoice');\n}\n\n/** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */\nexport function prepareQuickBooksCreditMemoRequest(\n creditMemo: CreditMemoInput,\n identity: Omit<\n QuickBooksCreditMemoRequest,\n 'payloadHash' | 'creditedInvoiceExternalId'\n >,\n): QuickBooksCreditMemoRequest {\n if (creditMemo.externalId)\n throw new Error(\n 'QuickBooks request identity is only for credit memo creation',\n );\n return prepareRequest(\n mapCreditMemoToQBO(creditMemo),\n {\n ...identity,\n creditedInvoiceExternalId: creditMemo.creditedInvoiceExternalId,\n },\n 'credit memo',\n );\n}\n\nfunction prepareRequest<T extends QuickBooksCreateRequest>(\n mapped: unknown,\n identity: Omit<T, 'payloadHash'>,\n kind: 'invoice' | 'credit memo',\n): T {\n const payload = JSON.stringify(mapped);\n const request = {\n ...identity,\n payloadHash: hashDescriptorPayload(payload, identity, kind),\n } as T;\n validateRequest(\n request,\n identity.realmId,\n identity.environment,\n payload,\n kind,\n );\n return Object.freeze(request);\n}\n\nfunction hash(payload: string): string {\n return createHash('sha256').update(payload).digest('hex');\n}\n\n/** Bind a credit memo's immutable source invoice without sending it to QBO. */\nfunction hashDescriptorPayload(\n payload: string,\n request:\n | QuickBooksCreateRequest\n | Omit<QuickBooksCreateRequest, 'payloadHash'>,\n kind: 'invoice' | 'credit memo',\n): string {\n if (kind === 'invoice') return hash(payload);\n const creditMemoRequest = request as QuickBooksCreditMemoRequest;\n return hash(\n JSON.stringify({\n payload,\n linkage: {\n creditedInvoiceExternalId: creditMemoRequest.creditedInvoiceExternalId,\n },\n }),\n );\n}\n\nexport function validateQuickBooksInvoiceRequest(\n request: QuickBooksInvoiceRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n): void {\n validateRequest(request, realmId, environment, payload, 'invoice');\n}\n\nexport function validateQuickBooksCreditMemoRequest(\n request: QuickBooksCreditMemoRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n): void {\n validateRequest(request, realmId, environment, payload, 'credit memo');\n}\n\nfunction validateRequest(\n request: QuickBooksCreateRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n kind: 'invoice' | 'credit memo',\n): void {\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 ${kind} request realm/environment mismatch`);\n }\n if (\n !payload ||\n request.payloadHash !== hashDescriptorPayload(payload, request, kind)\n ) {\n throw new Error(\n `QuickBooks ${kind} request payload mismatch; reconcile the original request`,\n );\n }\n if (\n kind === 'credit memo' &&\n (!('creditedInvoiceExternalId' in request) ||\n !request.creditedInvoiceExternalId ||\n request.creditedInvoiceExternalId.trim() !==\n request.creditedInvoiceExternalId)\n ) {\n throw new Error(\n 'QuickBooks credit memo request requires a credited invoice external ID',\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 ${kind} 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\nfunction close(a: number, b: number): boolean {\n return (\n Number.isFinite(a) &&\n Number.isFinite(b) &&\n Math.abs(a - b) <=\n Number.EPSILON * Math.max(1, Math.abs(a), Math.abs(b)) * 8\n );\n}\n\nfunction finite(value: number, label: string, allowNegative = false): number {\n if (!Number.isFinite(value) || (!allowNegative && value < 0))\n throw new Error(\n `QuickBooks ${label} must be a finite ${allowNegative ? '' : 'non-negative '}amount`,\n );\n return value;\n}\n\nfunction reference(value: string | undefined, label: string) {\n if (!value || value.trim() !== value || value.length > 255)\n throw new Error(`QuickBooks ${label} must be a non-empty realm reference`);\n return { value };\n}\n\nfunction canonicalRateNumber(value: number): string {\n // Number inputs can carry an adjacent binary representation of the exact\n // frozen decimal (for example 0.1 + 0.2). Prefer the shortest nearby decimal\n // through the calculator's supported precision, without changing a value\n // whose additional digits are materially distinct.\n for (let places = 0; places <= 12; places++) {\n const candidate = Number(value.toFixed(places));\n if (close(value, candidate)) return candidate.toString();\n }\n return value.toString();\n}\n\nfunction decimalRate(\n value: number | string | undefined,\n label: string,\n): DecimalRate {\n const text =\n typeof value === 'string' && /^\\d+(?:\\.\\d+)?$/.test(value)\n ? value\n : typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? canonicalRateNumber(value)\n : undefined;\n if (!text || !/^\\d+(?:\\.\\d+)?$/.test(text))\n throw new Error(\n `QuickBooks ${label} needs a frozen component rate from 0 through 1`,\n );\n const [whole, fraction = ''] = text.split('.');\n const denominator = 10n ** BigInt(fraction.length);\n const numerator = BigInt(`${whole}${fraction}`);\n if (numerator > denominator)\n throw new Error(\n `QuickBooks ${label} needs a frozen component rate from 0 through 1`,\n );\n return { numerator, denominator, value: Number(text) };\n}\n\nfunction ratesEqual(left: DecimalRate, right: DecimalRate): boolean {\n return (\n left.numerator * right.denominator === right.numerator * left.denominator\n );\n}\n\nfunction addRates(left: DecimalRate, right: DecimalRate): DecimalRate {\n const numerator =\n left.numerator * right.denominator + right.numerator * left.denominator;\n const denominator = left.denominator * right.denominator;\n return {\n numerator,\n denominator,\n value: Number(numerator) / Number(denominator),\n };\n}\n\nfunction taxPercent(rate: DecimalRate): number {\n return Number(rate.numerator * 100n) / Number(rate.denominator);\n}\n\nfunction currencyMinor(\n amount: number,\n currency: string | undefined,\n label: string,\n): bigint {\n const factor = currencyMinorUnitFactor(currency);\n const rounded = roundCurrencyAmount(amount, currency);\n if (\n factor === undefined ||\n rounded === undefined ||\n (!isCurrencyMinorUnit(amount, currency) && !close(amount, rounded))\n )\n throw new Error(\n `QuickBooks ${label} must fit the explicitly supplied currency's ISO 4217 minor-unit grid`,\n );\n // Match frozenCurrencyAmount: only a value already admitted as ordinary\n // binary noise is normalized before exact minor-unit aggregation. A genuine\n // off-grid value still refuses before any request is mapped.\n return BigInt(\n Math.round(\n (isCurrencyMinorUnit(amount, currency) ? amount : rounded) * factor,\n ),\n );\n}\n\nfunction currencyMajor(minor: bigint, currency: string | undefined): number {\n const factor = currencyMinorUnitFactor(currency);\n if (factor === undefined)\n throw new Error('QuickBooks needs a known currency');\n return Number(minor) / factor;\n}\n\nfunction taxMinorMatchesAllocation(\n taxMinor: bigint,\n numerator: bigint,\n denominator: bigint,\n): boolean {\n const floor = numerator / denominator;\n const remainder = numerator % denominator;\n return taxMinor === floor || (remainder !== 0n && taxMinor === floor + 1n);\n}\n\n/** Exact per-component factors relative to net; component order is significant. */\nfunction orderedFactors(components: readonly FrozenTaxComponent[]): {\n factors: DecimalRate[];\n total: DecimalRate;\n} {\n let total: DecimalRate = { numerator: 0n, denominator: 1n, value: 0 };\n const factors = components.map((component) => {\n const basis = component.compound\n ? addRates({ numerator: 1n, denominator: 1n, value: 1 }, total)\n : { numerator: 1n, denominator: 1n, value: 1 };\n const numerator = component.rate.numerator * basis.numerator;\n const denominator = component.rate.denominator * basis.denominator;\n const factor = {\n numerator,\n denominator,\n value: Number(numerator) / Number(denominator),\n };\n total = addRates(total, factor);\n return factor;\n });\n return { factors, total };\n}\n\nfunction validateFrozenComponentRates(\n components: readonly FrozenTaxComponent[],\n taxableAmount: number,\n currency: string | undefined,\n inclusive: boolean,\n label: string,\n): void {\n const taxableMinor = currencyMinor(\n taxableAmount,\n currency,\n `${label} taxable amount`,\n );\n const { factors, total } = orderedFactors(components);\n for (const [index, component] of components.entries()) {\n const factor = factors[index];\n const numerator = inclusive\n ? taxableMinor * factor.numerator * total.denominator\n : component.basisMinor * component.rate.numerator;\n const denominator = inclusive\n ? factor.denominator * (total.denominator + total.numerator)\n : component.rate.denominator;\n if (!taxMinorMatchesAllocation(component.taxMinor, numerator, denominator))\n throw new Error(\n `QuickBooks ${label} tax component rate is inconsistent with its frozen tax amount`,\n );\n }\n}\n\nfunction frozenCurrencyAmount(\n value: number,\n label: string,\n currency: string | undefined,\n allowNegative = false,\n): number {\n finite(value, label, allowNegative);\n const rounded = roundCurrencyAmount(value, currency);\n // Stored decimal money can reach JavaScript as an adjacent binary value\n // (for example 0.1 * 3). Accept that representation only when the known\n // currency round-trip differs by ordinary floating-point noise; this never\n // authorizes a real off-grid amount such as CAD 0.005 or JPY 100.5.\n if (\n !isCurrencyMinorUnit(value, currency) &&\n (rounded === undefined || !close(value, rounded))\n )\n throw new Error(\n `QuickBooks ${label} must fit the explicitly supplied currency's ISO 4217 minor-unit grid`,\n );\n return value;\n}\n\nfunction hasFrozenSnapshots(\n input: Pick<InvoiceInput, 'quickbooksMapping' | 'lineItems'>,\n): boolean {\n return (\n input.quickbooksMapping?.globalTaxCalculation === 'TaxInclusive' ||\n input.lineItems.some(\n (item) =>\n item.taxAmount !== undefined ||\n item.taxComponents !== undefined ||\n item.taxInclusiveAmount !== undefined ||\n (item.discount !== undefined && item.discount !== 0),\n )\n );\n}\n\n/** Limit accumulated binary error when a valid document has many decimal lines. */\nfunction compensatedSum(values: readonly number[]): number {\n let sum = 0;\n let compensation = 0;\n for (const value of values) {\n const adjusted = value - compensation;\n const next = sum + adjusted;\n compensation = next - sum - adjusted;\n sum = next;\n }\n return sum;\n}\n\nfunction mapDocumentLines(\n input: Pick<\n InvoiceInput,\n | 'lineItems'\n | 'subtotal'\n | 'taxAmount'\n | 'totalAmount'\n | 'currency'\n | 'quickbooksMapping'\n >,\n includeImplicitTaxBasis = false,\n): { lines: QuickBooksSalesLine[]; taxLines: QuickBooksTaxLine[] } {\n const mode = input.quickbooksMapping?.globalTaxCalculation;\n if (mode && !['TaxExcluded', 'TaxInclusive', 'NotApplicable'].includes(mode))\n throw new Error(\n 'QuickBooks globalTaxCalculation must be TaxExcluded, TaxInclusive or NotApplicable',\n );\n const frozen = hasFrozenSnapshots(input);\n const validateAmount = (value: number, label: string) =>\n frozen\n ? frozenCurrencyAmount(value, label, input.currency)\n : finite(value, label);\n validateAmount(input.subtotal, 'subtotal');\n validateAmount(input.taxAmount, 'tax amount');\n validateAmount(input.totalAmount, 'total amount');\n if (input.lineItems.length === 0)\n throw new Error('QuickBooks invoices require at least one sales line');\n const hasLineMapping = input.lineItems.some((item) => item.quickbooksMapping);\n if ((input.taxAmount > 0 || hasLineMapping) && !input.quickbooksMapping)\n throw new Error(\n 'QuickBooks mapped or nonzero-tax invoices require explicit globalTaxCalculation',\n );\n if (\n input.quickbooksMapping &&\n input.lineItems.some((item) => !item.quickbooksMapping)\n )\n throw new Error(\n 'QuickBooks mapped invoices require itemRef and taxCodeRef on every line',\n );\n if (input.taxAmount > 0 && mode === 'NotApplicable')\n throw new Error(\n 'QuickBooks nonzero tax cannot use NotApplicable global tax calculation',\n );\n\n const mapped: QuickBooksSalesLine[] = [];\n const taxLines = new Map<\n string,\n {\n rate: DecimalRate;\n amountMinor: bigint;\n basisMinor: bigint;\n explicitBasis: boolean;\n }\n >();\n const snapshotLineTaxes: number[] = [];\n let hasAnyLineTax = false;\n let hasCompleteLineTax = true;\n const lineTaxSnapshots: Array<{\n taxAmount: number | undefined;\n taxComponents: readonly FrozenTaxComponent[];\n }> = [];\n for (const [index, item] of input.lineItems.entries()) {\n const line = mapLine(item, index, input.currency, mode, frozen);\n mapped.push(...line.lines);\n lineTaxSnapshots.push({\n taxAmount: line.taxAmount,\n taxComponents: line.taxComponents,\n });\n if (line.taxAmount === undefined) hasCompleteLineTax = false;\n else {\n hasAnyLineTax = true;\n snapshotLineTaxes.push(line.taxAmount);\n }\n for (const component of line.taxComponents) {\n const existing = taxLines.get(component.taxRateRef);\n if (existing) {\n if (!ratesEqual(existing.rate, component.rate))\n throw new Error(\n `QuickBooks tax rate ${component.taxRateRef} has inconsistent frozen rates`,\n );\n existing.amountMinor += component.taxMinor;\n existing.basisMinor += component.basisMinor;\n existing.explicitBasis ||= component.explicitBasis;\n if (\n existing.explicitBasis &&\n !Number.isSafeInteger(Number(existing.basisMinor))\n )\n throw new Error(\n 'QuickBooks aggregate taxable basis exceeds safe minor units',\n );\n } else {\n taxLines.set(component.taxRateRef, {\n rate: component.rate,\n amountMinor: component.taxMinor,\n basisMinor: component.basisMinor,\n explicitBasis: component.explicitBasis,\n });\n }\n }\n }\n const mappedSubtotal = compensatedSum(mapped.map((line) => line.Amount));\n if (!close(mappedSubtotal, input.subtotal))\n throw new Error('QuickBooks line amounts must equal the invoice subtotal');\n if (!close(input.subtotal + input.taxAmount, input.totalAmount))\n throw new Error(\n 'QuickBooks subtotal plus tax must equal the invoice total',\n );\n if (taxLines.size > 0) {\n if (\n lineTaxSnapshots.some(\n (line) =>\n line.taxAmount === undefined ||\n (line.taxAmount > 0 && line.taxComponents.length === 0),\n )\n )\n throw new Error(\n 'QuickBooks component tax detail requires components on every taxed line',\n );\n const totalTaxMinor = currencyMinor(\n input.taxAmount,\n input.currency,\n 'tax amount',\n );\n const detailTaxMinor = [...taxLines.values()].reduce(\n (sum, line) => sum + line.amountMinor,\n 0n,\n );\n if (detailTaxMinor !== totalTaxMinor)\n throw new Error(\n 'QuickBooks component tax detail must equal the invoice tax amount',\n );\n }\n if (hasAnyLineTax && !hasCompleteLineTax)\n throw new Error(\n 'QuickBooks stored line tax must be supplied on every line when any line supplies it',\n );\n if (\n hasAnyLineTax &&\n !close(compensatedSum(snapshotLineTaxes), input.taxAmount)\n )\n throw new Error(\n 'QuickBooks stored line tax must equal the invoice tax amount',\n );\n return {\n lines: mapped,\n taxLines: [...taxLines.entries()].map(([taxRateRef, detail]) => ({\n Amount: currencyMajor(detail.amountMinor, input.currency),\n DetailType: 'TaxLineDetail',\n TaxLineDetail: {\n TaxRateRef: { value: taxRateRef },\n TaxPercent: taxPercent(detail.rate),\n PercentBased: true,\n ...(detail.explicitBasis || includeImplicitTaxBasis\n ? {\n NetAmountTaxable: currencyMajor(\n detail.basisMinor,\n input.currency,\n ),\n }\n : {}),\n },\n })),\n };\n}\n\n/** Internal readback projection reuses the mapper's validated aggregate tax bases. */\nexport function mapDocumentTaxReadback(input: InvoiceInput | CreditMemoInput) {\n return mapDocumentLines(input, true).taxLines;\n}\n\nfunction mapLine(\n item: InvoiceLineItemInput,\n index: number,\n currency: string | undefined,\n mode: 'TaxExcluded' | 'TaxInclusive' | 'NotApplicable' | undefined,\n enforceCurrencyGrid: boolean,\n): {\n lines: QuickBooksSalesLine[];\n taxAmount?: number;\n taxComponents: FrozenTaxComponent[];\n} {\n const label = `line ${index + 1}`;\n if (item.taxRate !== undefined && item.taxRate !== 0)\n throw new Error(\n 'QuickBooks numeric taxRate is not supported; use a realm taxCodeRef',\n );\n if (item.taxCode !== undefined)\n throw new Error(\n 'QuickBooks generic taxCode is not a realm tax reference; use quickbooksMapping.taxCodeRef',\n );\n finite(item.quantity, `${label} quantity`);\n if (item.quantity <= 0)\n throw new Error(`QuickBooks ${label} quantity must be greater than zero`);\n finite(item.unitPrice, `${label} unit price`);\n const baseDocumentAmount = item.quantity * item.unitPrice;\n finite(baseDocumentAmount, `${label} pre-discount amount`);\n const validateAmount = (\n value: number,\n amountLabel: string,\n allowNegative = false,\n ) =>\n enforceCurrencyGrid\n ? frozenCurrencyAmount(value, amountLabel, currency, allowNegative)\n : finite(value, amountLabel, allowNegative);\n const discount = validateAmount(item.discount ?? 0, `${label} discount`);\n if (discount > baseDocumentAmount && !close(discount, baseDocumentAmount))\n throw new Error(\n `QuickBooks ${label} discount cannot exceed quantity times unit price`,\n );\n const netAmount = validateAmount(\n item.amount ?? baseDocumentAmount - discount,\n `${label} amount`,\n );\n const taxAmount =\n item.taxAmount === undefined\n ? undefined\n : validateAmount(item.taxAmount, `${label} tax amount`);\n const taxComponents: FrozenTaxComponent[] = [];\n const componentIds = new Set<string>();\n const componentRateRefs = new Set<string>();\n if (item.taxComponents !== undefined) {\n if (taxAmount === undefined)\n throw new Error(\n `QuickBooks ${label} tax components require a line tax amount`,\n );\n const componentTax = item.taxComponents.reduce(\n (sum, component, componentIndex) => {\n if (\n !component ||\n typeof component !== 'object' ||\n Object.keys(component).some(\n (key) =>\n ![\n 'taxCode',\n 'rate',\n 'quickbooksTaxRateRef',\n 'taxAmount',\n 'compound',\n 'taxableAmount',\n ].includes(key),\n )\n )\n throw new Error(\n `QuickBooks ${label} tax component has unsupported fields`,\n );\n if (\n component.compound !== undefined &&\n typeof component.compound !== 'boolean'\n )\n throw new Error(`QuickBooks ${label} compound must be boolean`);\n if (component.compound && component.taxableAmount === undefined)\n throw new Error(\n `QuickBooks ${label} compound tax requires its frozen taxableAmount`,\n );\n if (\n !component.taxCode ||\n component.taxCode.trim() !== component.taxCode\n )\n throw new Error(\n `QuickBooks ${label} tax component ${componentIndex + 1} needs a tax code`,\n );\n const rate = decimalRate(\n component.rate,\n `${label} tax component ${componentIndex + 1}`,\n );\n const taxRateRef = reference(\n component.quickbooksTaxRateRef,\n `${label} tax component ${componentIndex + 1} quickbooksTaxRateRef`,\n ).value;\n const componentAmount = validateAmount(\n component.taxAmount,\n `${label} tax component ${componentIndex + 1}`,\n );\n if (\n componentIds.has(component.taxCode) ||\n componentRateRefs.has(taxRateRef)\n )\n throw new Error(\n `QuickBooks ${label} repeats a tax component or rate reference`,\n );\n componentIds.add(component.taxCode);\n componentRateRefs.add(taxRateRef);\n const expectedBasis =\n currencyMinor(netAmount, currency, `${label} net amount`) +\n (component.compound\n ? taxComponents.reduce((sum, prior) => sum + prior.taxMinor, 0n)\n : 0n);\n const basisMinor =\n component.taxableAmount === undefined\n ? expectedBasis\n : currencyMinor(\n validateAmount(\n component.taxableAmount,\n `${label} taxable basis`,\n ),\n currency,\n `${label} taxable basis`,\n );\n if (!Number.isSafeInteger(Number(basisMinor)))\n throw new Error(\n `QuickBooks ${label} taxable basis exceeds safe minor units`,\n );\n if (basisMinor !== expectedBasis)\n throw new Error(\n `QuickBooks ${label} frozen taxable basis does not match its ordered components`,\n );\n taxComponents.push({\n taxRateRef,\n rate,\n compound: component.compound ?? false,\n basisMinor,\n explicitBasis: component.taxableAmount !== undefined,\n taxMinor: currencyMinor(\n componentAmount,\n currency,\n `${label} tax component ${componentIndex + 1}`,\n ),\n });\n return sum + componentAmount;\n },\n 0,\n );\n if (!close(componentTax, taxAmount))\n throw new Error(\n `QuickBooks ${label} tax components must equal the line tax amount`,\n );\n }\n\n const inclusive = mode === 'TaxInclusive';\n const grossAmount = item.taxInclusiveAmount;\n if (!inclusive && grossAmount !== undefined)\n throw new Error(\n `QuickBooks ${label} tax-inclusive amount requires TaxInclusive global tax calculation`,\n );\n if (inclusive) {\n if (\n grossAmount === undefined ||\n taxAmount === undefined ||\n (taxAmount > 0 && !item.taxComponents?.length)\n )\n throw new Error(\n `QuickBooks ${label} TaxInclusive snapshots require gross amount, line tax and tax components for nonzero tax`,\n );\n validateAmount(grossAmount, `${label} tax-inclusive amount`);\n if (!close(netAmount + taxAmount, grossAmount))\n throw new Error(\n `QuickBooks ${label} net amount plus tax must equal gross amount`,\n );\n if (!close(baseDocumentAmount - discount, grossAmount))\n throw new Error(\n `QuickBooks ${label} gross amount must equal quantity times gross unit price less gross discount`,\n );\n } else if (\n !close(netAmount, baseDocumentAmount - discount) &&\n !matchesCurrencyRoundedLineAmount(\n item.quantity,\n item.unitPrice,\n netAmount + discount,\n currency,\n )\n ) {\n throw new Error(\n `QuickBooks ${label} amount must equal quantity times unit price less discount`,\n );\n }\n const mappedComponents = item.quickbooksMapping?.taxComponents;\n if (\n taxComponents.some((component) => component.compound) &&\n mappedComponents === undefined\n )\n throw new Error(\n `QuickBooks ${label} compound tax requires caller-verified ordered tax-code mapping`,\n );\n if (mappedComponents !== undefined) {\n if (\n !Array.isArray(mappedComponents) ||\n mappedComponents.length !== taxComponents.length\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping must match every frozen component`,\n );\n const refs = new Set<string>();\n for (const [position, mapped] of mappedComponents.entries()) {\n if (\n !mapped ||\n typeof mapped !== 'object' ||\n Object.keys(mapped).some(\n (key) => !['taxRateRef', 'compound'].includes(key),\n ) ||\n typeof mapped.compound !== 'boolean'\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping has unknown order metadata`,\n );\n const ref = reference(\n mapped.taxRateRef,\n `${label} mapped tax rate`,\n ).value;\n const component = taxComponents[position];\n if (\n refs.has(ref) ||\n ref !== component.taxRateRef ||\n mapped.compound !== component.compound\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping does not match frozen components`,\n );\n refs.add(ref);\n }\n }\n if (taxComponents.length > 0)\n validateFrozenComponentRates(\n taxComponents,\n inclusive ? (grossAmount as number) : netAmount,\n currency,\n inclusive,\n label,\n );\n\n const itemRef = item.quickbooksMapping\n ? reference(item.quickbooksMapping.itemRef, `${label} itemRef`)\n : undefined;\n const taxCodeRef = item.quickbooksMapping\n ? reference(item.quickbooksMapping.taxCodeRef, `${label} taxCodeRef`)\n : undefined;\n const line = (\n amount: number,\n quantity: number,\n unitPrice: number,\n description: string,\n taxInclusiveAmount?: number,\n ) => ({\n LineNum: index + 1,\n Description: description,\n Amount: amount,\n DetailType: 'SalesItemLineDetail' as const,\n SalesItemLineDetail: {\n Qty: quantity,\n UnitPrice: unitPrice,\n ItemRef: itemRef,\n TaxCodeRef: taxCodeRef,\n ...(taxInclusiveAmount === undefined\n ? {}\n : { TaxInclusiveAmt: taxInclusiveAmount }),\n },\n });\n\n if (discount === 0 && !inclusive) {\n return {\n lines: [line(netAmount, item.quantity, item.unitPrice, item.description)],\n taxAmount,\n taxComponents,\n };\n }\n if (\n discount === 0 ||\n isCurrencyMinorUnit(netAmount / item.quantity, currency)\n ) {\n return {\n lines: [\n line(\n netAmount,\n item.quantity,\n netAmount / item.quantity,\n item.description,\n inclusive ? grossAmount : undefined,\n ),\n ],\n taxAmount,\n taxComponents,\n };\n }\n\n let preDiscountAmount = netAmount + discount;\n let negativeAmount = -discount;\n const preDiscountGross = inclusive ? baseDocumentAmount : undefined;\n if (inclusive) {\n const components = item.taxComponents;\n const exemptSnapshot = taxAmount === 0 && !components?.length;\n if (!components?.length && !exemptSnapshot)\n throw new Error(\n `QuickBooks ${label} needs frozen component rates for an inclusive negative discount line`,\n );\n const rate = exemptSnapshot\n ? 0\n : (components ?? []).reduce(\n (sum, component, componentIndex) =>\n sum +\n decimalRate(\n component.rate,\n `${label} tax component ${componentIndex + 1}`,\n ).value,\n 0,\n );\n let discountNet = roundCurrencyAmount(discount / (1 + rate), currency);\n if (taxComponents.some((component) => component.compound)) {\n const { total } = orderedFactors(taxComponents);\n const numerator =\n currencyMinor(discount, currency, `${label} discount`) *\n total.denominator;\n const denominator = total.denominator + total.numerator;\n discountNet = currencyMajor(\n (2n * numerator + denominator) / (2n * denominator),\n currency,\n );\n }\n if (discountNet === undefined)\n throw new Error(\n `QuickBooks ${label} needs a recognized currency to map an inclusive fractional-unit discount`,\n );\n preDiscountAmount = netAmount + discountNet;\n negativeAmount = -discountNet;\n }\n if (enforceCurrencyGrid) {\n frozenCurrencyAmount(\n preDiscountAmount,\n `${label} generated pre-discount amount`,\n currency,\n );\n frozenCurrencyAmount(\n negativeAmount,\n `${label} generated discount amount`,\n currency,\n true,\n );\n }\n let negativeGross: number | undefined;\n if (inclusive) {\n if (grossAmount === undefined || preDiscountGross === undefined)\n throw new Error(\n `QuickBooks ${label} needs frozen gross amounts for an inclusive negative discount line`,\n );\n const unroundedNegativeGross = grossAmount - preDiscountGross;\n negativeGross =\n roundCurrencyAmount(unroundedNegativeGross, currency) ??\n unroundedNegativeGross;\n }\n if (enforceCurrencyGrid && negativeGross !== undefined) {\n frozenCurrencyAmount(\n negativeGross,\n `${label} generated gross discount amount`,\n currency,\n true,\n );\n }\n return {\n lines: [\n line(\n preDiscountAmount,\n item.quantity,\n preDiscountAmount / item.quantity,\n item.description,\n preDiscountGross,\n ),\n line(\n negativeAmount,\n 1,\n negativeAmount,\n `Discount on line ${index + 1}`,\n negativeGross,\n ),\n ],\n taxAmount,\n taxComponents,\n };\n}\n\nfunction basePayload(\n input: Pick<\n InvoiceInput,\n | 'customerId'\n | 'customerExternalId'\n | 'issueDate'\n | 'subtotal'\n | 'taxAmount'\n | 'totalAmount'\n | 'currency'\n | 'memo'\n | 'lineItems'\n | 'quickbooksMapping'\n >,\n number: string,\n dueDate?: Date,\n) {\n const { lines, taxLines } = mapDocumentLines(input);\n return {\n CustomerRef: { value: input.customerExternalId || input.customerId },\n DocNumber: number,\n TxnDate: formatLocalDate(input.issueDate),\n ...(dueDate ? { DueDate: formatLocalDate(dueDate) } : {}),\n Line: lines,\n GlobalTaxCalculation: input.quickbooksMapping?.globalTaxCalculation,\n TxnTaxDetail: input.quickbooksMapping\n ? {\n TotalTax: input.taxAmount,\n ...(taxLines.length > 0 ? { TaxLine: taxLines } : {}),\n }\n : undefined,\n CurrencyRef: input.currency ? { value: input.currency } : undefined,\n CustomerMemo: input.memo ? { value: input.memo } : undefined,\n };\n}\n\nexport function mapInvoiceToQBO(invoice: InvoiceInput) {\n if (invoice.collectionMethod === 'charge_automatically')\n throw new Error(\n 'QuickBooks does not support charge_automatically invoice collection',\n );\n if (invoice.automaticTax)\n throw new Error(\n 'QuickBooks does not support automaticTax invoice calculation',\n );\n return basePayload(\n invoice,\n invoice.invoiceNumber,\n invoice.dueDate,\n ) as ReturnType<typeof basePayload> & { DueDate: string };\n}\n\nexport function mapCreditMemoToQBO(creditMemo: CreditMemoInput) {\n if (\n !creditMemo.creditedInvoiceExternalId ||\n creditMemo.creditedInvoiceExternalId.trim() !==\n creditMemo.creditedInvoiceExternalId\n )\n throw new Error(\n 'QuickBooks credit memos require a credited invoice external ID',\n );\n return basePayload(creditMemo, creditMemo.creditMemoNumber);\n}\n","/** Exact, explicit receivable reclassification. No sales, tax or bank-transfer approximation. */\nimport { createHash } from 'node:crypto';\nimport { currencyMinorUnitFactor, isCurrencyMinorUnit } from './line-amount.js';\n\nexport interface QuickBooksReceivableMapping {\n realmId: string;\n environment: 'sandbox' | 'production';\n version: string;\n reviewEvidenceRef: string;\n accountingBasis: 'accrual';\n taxTiming: 'invoice-tax-point';\n releaseDueDates: 'host-managed';\n currency: string;\n customerRef: string;\n receivablesAccountRef: string;\n retainedAssetAccountRef: string;\n cashAccountRef: string | null;\n}\nexport interface QuickBooksReceivableSource {\n type: 'Invoice' | 'CreditMemo' | 'JournalEntry';\n id: string;\n customerRef: string;\n /** Immutable host snapshot/agreement/release reference, never a guessed provider field. */\n evidenceRef: string;\n}\ninterface TransferEvidence {\n mapping: QuickBooksReceivableMapping;\n source: QuickBooksReceivableSource;\n requestId: string;\n effectiveOn: string;\n evidenceRef: string;\n}\nexport interface QuickBooksReceivableTransferInput extends TransferEvidence {\n kind: 'withhold' | 'release' | 'cash-refund' | 'reverse-cash-refund';\n amountMinor: number;\n}\nexport interface QuickBooksNonCashApplicationInput extends TransferEvidence {\n kind: 'application';\n amountMinor: number;\n debit: { type: 'Invoice' | 'JournalEntry'; id: string };\n credit: { type: 'CreditMemo' | 'JournalEntry'; id: string };\n}\nexport type QuickBooksReceivableInput =\n | QuickBooksReceivableTransferInput\n | QuickBooksNonCashApplicationInput;\nexport interface QuickBooksReceivableRequest {\n version: 1;\n endpoint: 'journalentry' | 'payment';\n realmId: string;\n environment: 'sandbox' | 'production';\n requestId: string;\n payloadHash: string;\n input: QuickBooksReceivableInput;\n}\nexport interface QuickBooksReceivableReadback {\n externalId: string;\n syncToken: string;\n kind: QuickBooksReceivableInput['kind'];\n customerRef: string;\n currency: string;\n effectiveOn: string;\n amountMinor: number;\n /** Noncash application amount is never counted as a customer cash receipt. */\n nonCashAppliedMinor: number;\n /** A cash journal is a record, not evidence of provider bank settlement. */\n recordedCashChangeMinor: number;\n providerProcessedCashMinor: 0;\n bankSettlementVerified: false;\n source: QuickBooksReceivableSource;\n payloadHash: string;\n}\nexport interface QuickBooksReceivableTransferOperations {\n verifyMapping(\n mapping: QuickBooksReceivableMapping,\n ): Promise<{ mappingHash: string; homeCurrency: string }>;\n execute(\n request: QuickBooksReceivableRequest,\n ): Promise<QuickBooksReceivableReadback>;\n /** Reconcile a known remote ID against the complete prepared contract, not just its total. */\n read(\n request: QuickBooksReceivableRequest,\n externalId: string,\n ): Promise<QuickBooksReceivableReadback>;\n}\n\nconst hash = (value: unknown) =>\n createHash('sha256').update(JSON.stringify(value)).digest('hex');\nfunction text(\n value: unknown,\n label: string,\n max = 1000,\n): asserts value is string {\n if (\n typeof value !== 'string' ||\n !value ||\n value !== value.trim() ||\n value.length > max\n )\n throw new Error(`${label} must be explicit trimmed text`);\n}\nfunction id(value: unknown, label: string): asserts value is string {\n text(value, label, 100);\n if (!/^[A-Za-z0-9._-]+$/.test(value))\n throw new Error(`${label} is not a supported provider reference`);\n}\nfunction date(value: string) {\n if (\n !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) ||\n !Number.isFinite(Date.parse(value)) ||\n new Date(value).toISOString().slice(0, 10) !== value\n )\n throw new Error('Receivable effective date is invalid');\n}\nfunction minor(value: number, currency: string): number {\n const factor = currencyMinorUnitFactor(currency);\n if (!factor || !Number.isSafeInteger(value) || value <= 0)\n throw new Error(\n 'Receivable amount must be positive safe integer currency minor units',\n );\n const major = value / factor;\n if (\n !isCurrencyMinorUnit(major, currency) ||\n Math.round(major * factor) !== value\n )\n throw new Error(\n 'Receivable amount cannot be represented exactly by the provider',\n );\n return major;\n}\nexport function validateQuickBooksReceivableMapping(\n mapping: QuickBooksReceivableMapping,\n) {\n id(mapping.realmId, 'Realm');\n id(mapping.customerRef, 'Customer');\n text(mapping.version, 'Mapping version');\n text(mapping.reviewEvidenceRef, 'Mapping review evidence');\n if (\n !['sandbox', 'production'].includes(mapping.environment) ||\n mapping.accountingBasis !== 'accrual' ||\n mapping.taxTiming !== 'invoice-tax-point' ||\n mapping.releaseDueDates !== 'host-managed'\n )\n throw new Error(\n 'Receivable transfers support explicit accrual, invoice-tax-point and host-managed release due dates only',\n );\n if (\n !/^[A-Z]{3}$/.test(mapping.currency) ||\n !currencyMinorUnitFactor(mapping.currency)\n )\n throw new Error('Unsupported receivable currency');\n const refs = [\n mapping.receivablesAccountRef,\n mapping.retainedAssetAccountRef,\n ...(mapping.cashAccountRef === null ? [] : [mapping.cashAccountRef]),\n ];\n for (const ref of refs) id(ref, 'Posting account');\n if (new Set(refs).size !== refs.length)\n throw new Error('Receivable posting accounts must be distinct');\n}\nfunction validate(input: QuickBooksReceivableInput) {\n validateQuickBooksReceivableMapping(input.mapping);\n id(input.requestId, 'Request');\n if (input.requestId.length > 50)\n throw new Error('QuickBooks requestId must contain at most 50 characters');\n date(input.effectiveOn);\n text(input.evidenceRef, 'Operation evidence', 1000);\n if (!['Invoice', 'CreditMemo', 'JournalEntry'].includes(input.source.type))\n throw new Error('Unsupported source transaction type');\n id(input.source.id, 'Source transaction');\n id(input.source.customerRef, 'Source customer');\n text(input.source.evidenceRef, 'Source evidence');\n if (input.source.customerRef !== input.mapping.customerRef)\n throw new Error('Source customer differs from receivable mapping');\n minor(input.amountMinor, input.mapping.currency);\n if (input.kind === 'application') {\n if (\n !['Invoice', 'JournalEntry'].includes(input.debit.type) ||\n !['CreditMemo', 'JournalEntry'].includes(input.credit.type)\n )\n throw new Error('Unsupported noncash application transaction types');\n id(input.debit.id, 'Debit transaction');\n id(input.credit.id, 'Credit transaction');\n if (\n input.debit.type === input.credit.type &&\n input.debit.id === input.credit.id\n )\n throw new Error('Cannot apply a journal to itself');\n } else if (\n !['withhold', 'release', 'cash-refund', 'reverse-cash-refund'].includes(\n input.kind,\n )\n )\n throw new Error('Unsupported receivable transfer direction');\n else if (input.kind.includes('cash-refund') && !input.mapping.cashAccountRef)\n throw new Error('Cash refund recording requires an explicit cash account');\n}\nexport function mapQuickBooksReceivableRequest(\n input: QuickBooksReceivableInput,\n): Record<string, unknown> {\n validate(input);\n const amount = minor(input.amountMinor, input.mapping.currency);\n const source = `${input.source.type}:${input.source.id}; customer:${input.source.customerRef}; evidence:${input.source.evidenceRef}`;\n const note = `${input.kind}; ${source}; operation:${input.evidenceRef}; mapping:${input.mapping.version}; request:${input.requestId}`;\n if (note.length > 4000)\n throw new Error('Receivable provenance exceeds the provider note limit');\n const base = {\n TxnDate: input.effectiveOn,\n CurrencyRef: { value: input.mapping.currency },\n PrivateNote: note,\n };\n if (input.kind === 'application')\n return {\n ...base,\n CustomerRef: { value: input.mapping.customerRef },\n TotalAmt: 0,\n ProcessPayment: false,\n Line: [input.debit, input.credit].map((ref) => ({\n Amount: amount,\n LinkedTxn: [{ TxnType: ref.type, TxnId: ref.id }],\n })),\n };\n const arDebit = input.kind === 'release' || input.kind === 'cash-refund';\n const counterpart = input.kind.includes('cash-refund')\n ? input.mapping.cashAccountRef\n : input.mapping.retainedAssetAccountRef;\n return {\n ...base,\n Line: [\n { account: input.mapping.receivablesAccountRef, debit: arDebit },\n { account: counterpart, debit: !arDebit },\n ].map((line, index) => ({\n LineNum: index + 1,\n Description: source,\n Amount: amount,\n DetailType: 'JournalEntryLineDetail',\n JournalEntryLineDetail: {\n PostingType: line.debit ? 'Debit' : 'Credit',\n AccountRef: { value: line.account },\n Entity: {\n Type: 'Customer',\n EntityRef: { value: input.mapping.customerRef },\n },\n },\n })),\n };\n}\n/** Pure preparation. Persist before sending; the hash does not prove a remote write occurred once. */\nexport function prepareQuickBooksReceivableRequest(\n input: QuickBooksReceivableInput,\n): QuickBooksReceivableRequest {\n const frozenInput = structuredClone(input),\n body = mapQuickBooksReceivableRequest(frozenInput);\n return Object.freeze({\n version: 1,\n endpoint: input.kind === 'application' ? 'payment' : 'journalentry',\n realmId: input.mapping.realmId,\n environment: input.mapping.environment,\n requestId: input.requestId,\n payloadHash: hash({ input: frozenInput, body }),\n input: frozenInput,\n });\n}\nexport function validateQuickBooksReceivableRequest(\n request: QuickBooksReceivableRequest,\n realmId: string,\n environment: string,\n serializedBody?: string,\n) {\n const expected = prepareQuickBooksReceivableRequest(request.input);\n if (\n request.version !== 1 ||\n request.realmId !== realmId ||\n request.environment !== environment ||\n request.endpoint !== expected.endpoint ||\n request.requestId !== expected.requestId ||\n request.payloadHash !== expected.payloadHash ||\n request.realmId !== expected.realmId ||\n request.environment !== expected.environment ||\n (serializedBody !== undefined &&\n serializedBody !==\n JSON.stringify(mapQuickBooksReceivableRequest(request.input)))\n )\n throw new Error(\n 'Receivable request scope, provenance or frozen payload changed',\n );\n}\n\n/** Exact readback validation; provider-added IDs/names are allowed, omitted financial facts are not. */\nexport function reconcileQuickBooksReceivableRecord(\n request: QuickBooksReceivableRequest,\n value: unknown,\n): QuickBooksReceivableReadback {\n validateQuickBooksReceivableRequest(\n request,\n request.realmId,\n request.environment,\n );\n const raw = value as Record<string, any>,\n expected = mapQuickBooksReceivableRequest(request.input),\n input = request.input;\n if (!raw || typeof raw !== 'object')\n throw new Error('Receivable provider record is missing');\n id(raw.Id, 'Provider record');\n text(raw.SyncToken, 'Provider sync token', 100);\n if (\n raw.TxnDate !== expected.TxnDate ||\n raw.CurrencyRef?.value !== input.mapping.currency ||\n raw.PrivateNote !== expected.PrivateNote ||\n !Array.isArray(raw.Line) ||\n raw.Line.length !== 2\n )\n throw new Error(\n 'Receivable provider identity, currency, date or evidence differs',\n );\n if (\n (raw.ExchangeRate !== undefined && raw.ExchangeRate !== 1) ||\n (raw.TxnTaxDetail !== undefined && raw.TxnTaxDetail?.TotalTax !== 0)\n )\n throw new Error(\n 'Receivable readback contains unsupported exchange or tax effects',\n );\n const expectedLines = expected.Line as Record<string, any>[];\n for (let i = 0; i < 2; i++) {\n const line = raw.Line[i],\n wanted = expectedLines[i];\n if (line.Amount !== wanted.Amount)\n throw new Error('Receivable provider line amount differs');\n if (input.kind === 'application') {\n if (\n !Array.isArray(line.LinkedTxn) ||\n line.LinkedTxn.length !== 1 ||\n line.LinkedTxn[0].TxnType !== wanted.LinkedTxn[0].TxnType ||\n line.LinkedTxn[0].TxnId !== wanted.LinkedTxn[0].TxnId\n )\n throw new Error('Receivable application linkage differs');\n } else {\n const details = line.JournalEntryLineDetail,\n required = wanted.JournalEntryLineDetail;\n if (\n line.DetailType !== 'JournalEntryLineDetail' ||\n line.Description !== wanted.Description ||\n details?.PostingType !== required.PostingType ||\n details?.AccountRef?.value !== required.AccountRef.value ||\n details?.Entity?.Type !== 'Customer' ||\n details?.Entity?.EntityRef?.value !== input.mapping.customerRef ||\n details?.TaxAmount !== undefined ||\n details?.TaxCodeRef !== undefined\n )\n throw new Error('Receivable journal posting authority differs');\n }\n }\n if (\n input.kind === 'application' &&\n (raw.TotalAmt !== 0 ||\n raw.UnappliedAmt !== 0 ||\n raw.CustomerRef?.value !== input.mapping.customerRef ||\n raw.ProcessPayment === true)\n )\n throw new Error(\n 'Noncash application must have zero cash and no unapplied balance',\n );\n return {\n externalId: raw.Id,\n syncToken: raw.SyncToken,\n kind: input.kind,\n customerRef: input.mapping.customerRef,\n currency: input.mapping.currency,\n effectiveOn: input.effectiveOn,\n amountMinor: input.amountMinor,\n nonCashAppliedMinor: input.kind === 'application' ? input.amountMinor : 0,\n recordedCashChangeMinor:\n input.kind === 'cash-refund'\n ? -input.amountMinor\n : input.kind === 'reverse-cash-refund'\n ? input.amountMinor\n : 0,\n providerProcessedCashMinor: 0,\n bankSettlementVerified: false,\n source: structuredClone(input.source),\n payloadHash: request.payloadHash,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"receivable-transfer-DPxto4TY.js","names":[],"sources":["../../src/providers/quickbooks/line-amount.ts","../../src/providers/quickbooks/invoice-request.ts","../../src/providers/quickbooks/receivable-transfer.ts"],"sourcesContent":["/** ISO 4217 List One, published 2026-09-17. Do not use Intl display digits:\n * ICU differs for e.g. IQD, MGA and RSD, and omits fund codes CLF/UYW.\n * https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/lists/list-one.xml\n * N.A., unknown and missing codes cannot authorize currency rounding.\n */\nconst precisionGroups: readonly (readonly [number, string])[] = [\n [0, 'BIF CLP DJF GNF ISK JPY KMF KRW PYG RWF UGX UYI VND VUV XAF XOF XPF'],\n [\n 2,\n 'AED AFN ALL AMD AOA ARS AUD AWG AZN BAM BBD BDT BMD BND BOB BOV BRL BSD BTN BWP BYN BZD CAD CDF CHE CHF CHW CNY COP COU CRC CUP CVE CZK DKK DOP DZD EGP ERN ETB EUR FJD FKP GBP GEL GHS GIP GMD GTQ GYD HKD HNL HTG HUF IDR ILS INR IRR JMD KES KGS KHR KPW KYD KZT LAK LBP LKR LRD LSL MAD MDL MGA MKD MMK MNT MOP MRU MUR MVR MWK MXN MXV MYR MZN NAD NGN NIO NOK NPR NZD PAB PEN PGK PHP PKR PLN QAR RON RSD RUB SAR SBD SCR SDG SEK SGD SHP SLE SOS SRD SSP STN SVC SYP SZL THB TJS TMT TOP TRY TTD TWD TZS UAH USD USN UYU UZS VED VES WST XAD XCD XCG YER ZAR ZMW ZWG',\n ],\n [3, 'BHD IQD JOD KWD LYD OMR TND'],\n [4, 'CLF UYW'],\n];\nconst currencyPrecision = new Map(\n precisionGroups.flatMap(([precision, codes]) =>\n codes.split(' ').map((code) => [code, precision] as const),\n ),\n);\n\n/** ISO minor-unit factor, or undefined when the code is unknown or omitted. */\nexport function currencyMinorUnitFactor(\n currency: string | undefined,\n): number | undefined {\n if (typeof currency !== 'string') return undefined;\n const precision = currencyPrecision.get(currency.toUpperCase());\n return precision === undefined ? undefined : 10 ** precision;\n}\n\n/** True only for a finite amount exactly representable on the ISO minor-unit grid. */\nexport function isCurrencyMinorUnit(\n amount: number,\n currency: string | undefined,\n): boolean {\n if (!Number.isFinite(amount) || typeof currency !== 'string') return false;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return false;\n const value = decimalRatio(Math.abs(amount));\n return (\n (value.numerator * 10n ** BigInt(precision)) % value.denominator === 0n\n );\n}\n\n/** Round a finite major-unit amount half-up to a known ISO currency grid. */\nexport function roundCurrencyAmount(\n amount: number,\n currency: string | undefined,\n): number | undefined {\n if (!Number.isFinite(amount) || typeof currency !== 'string')\n return undefined;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return undefined;\n const sign = amount < 0 ? -1n : 1n;\n const value = decimalRatio(Math.abs(amount));\n const scale = 10n ** BigInt(precision);\n const numerator = value.numerator * scale;\n const rounded =\n numerator / value.denominator +\n ((numerator % value.denominator) * 2n >= value.denominator ? 1n : 0n);\n return Number(sign * rounded) / Number(scale);\n}\n\n/** Exact decimal interpretation of the finite nonnegative public number value. */\nfunction decimalRatio(value: number): {\n numerator: bigint;\n denominator: bigint;\n} {\n const [significand, exponent = '0'] = value.toString().split('e');\n const [whole, fraction = ''] = significand.split('.');\n const coefficient = BigInt(whole + fraction);\n const scale = fraction.length - Number(exponent);\n return scale >= 0\n ? { numerator: coefficient, denominator: 10n ** BigInt(scale) }\n : { numerator: coefficient * 10n ** BigInt(-scale), denominator: 1n };\n}\n\n/** Admit only the exact half-up minor-unit result; never rewrite caller money. */\nexport function matchesCurrencyRoundedLineAmount(\n quantity: number,\n unitPrice: number,\n amount: number,\n currency: string | undefined,\n): boolean {\n if (typeof currency !== 'string') return false;\n const precision = currencyPrecision.get(currency.toUpperCase());\n if (precision === undefined) return false;\n const minorScale = 10n ** BigInt(precision);\n const retained = decimalRatio(amount);\n const retainedMinor = retained.numerator * minorScale;\n // An off-grid caller amount is not permission to round their supplied money.\n if (retainedMinor % retained.denominator !== 0n) return false;\n const qty = decimalRatio(quantity);\n const price = decimalRatio(unitPrice);\n const numerator = qty.numerator * price.numerator * minorScale;\n const denominator = qty.denominator * price.denominator;\n const quotient = numerator / denominator;\n const rounded =\n quotient + ((numerator % denominator) * 2n >= denominator ? 1n : 0n);\n return retainedMinor / retained.denominator === rounded;\n}\n","import { createHash } from 'node:crypto';\nimport type {\n CreditMemoInput,\n InvoiceInput,\n InvoiceLineItemInput,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n} from '../../types.js';\nimport {\n currencyMinorUnitFactor,\n isCurrencyMinorUnit,\n matchesCurrencyRoundedLineAmount,\n roundCurrencyAmount,\n} from './line-amount.js';\n\ntype QuickBooksCreateRequest =\n | QuickBooksInvoiceRequest\n | QuickBooksCreditMemoRequest;\n\ninterface QuickBooksSalesLine {\n LineNum: number;\n Description: string;\n Amount: number;\n DetailType: 'SalesItemLineDetail';\n SalesItemLineDetail: {\n Qty: number;\n UnitPrice: number;\n ItemRef?: { value: string };\n TaxCodeRef?: { value: string };\n TaxInclusiveAmt?: number;\n };\n}\n\ninterface QuickBooksTaxLine {\n Amount: number;\n DetailType: 'TaxLineDetail';\n TaxLineDetail: {\n TaxRateRef: { value: string };\n TaxPercent: number;\n PercentBased: true;\n NetAmountTaxable?: number;\n };\n}\n\ninterface FrozenTaxComponent {\n taxRateRef: string;\n rate: DecimalRate;\n taxMinor: bigint;\n compound: boolean;\n basisMinor: bigint;\n explicitBasis: boolean;\n}\n\ninterface DecimalRate {\n numerator: bigint;\n denominator: bigint;\n value: number;\n}\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 return prepareRequest(mapInvoiceToQBO(invoice), identity, 'invoice');\n}\n\n/** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */\nexport function prepareQuickBooksCreditMemoRequest(\n creditMemo: CreditMemoInput,\n identity: Omit<\n QuickBooksCreditMemoRequest,\n 'payloadHash' | 'creditedInvoiceExternalId'\n >,\n): QuickBooksCreditMemoRequest {\n if (creditMemo.externalId)\n throw new Error(\n 'QuickBooks request identity is only for credit memo creation',\n );\n return prepareRequest(\n mapCreditMemoToQBO(creditMemo),\n {\n ...identity,\n creditedInvoiceExternalId: creditMemo.creditedInvoiceExternalId,\n },\n 'credit memo',\n );\n}\n\nfunction prepareRequest<T extends QuickBooksCreateRequest>(\n mapped: unknown,\n identity: Omit<T, 'payloadHash'>,\n kind: 'invoice' | 'credit memo',\n): T {\n const payload = JSON.stringify(mapped);\n const request = {\n ...identity,\n payloadHash: hashDescriptorPayload(payload, identity, kind),\n } as T;\n validateRequest(\n request,\n identity.realmId,\n identity.environment,\n payload,\n kind,\n );\n return Object.freeze(request);\n}\n\nfunction hash(payload: string): string {\n return createHash('sha256').update(payload).digest('hex');\n}\n\n/** Bind a credit memo's immutable source invoice without sending it to QBO. */\nfunction hashDescriptorPayload(\n payload: string,\n request:\n | QuickBooksCreateRequest\n | Omit<QuickBooksCreateRequest, 'payloadHash'>,\n kind: 'invoice' | 'credit memo',\n): string {\n if (kind === 'invoice') return hash(payload);\n const creditMemoRequest = request as QuickBooksCreditMemoRequest;\n return hash(\n JSON.stringify({\n payload,\n linkage: {\n creditedInvoiceExternalId: creditMemoRequest.creditedInvoiceExternalId,\n },\n }),\n );\n}\n\nexport function validateQuickBooksInvoiceRequest(\n request: QuickBooksInvoiceRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n): void {\n validateRequest(request, realmId, environment, payload, 'invoice');\n}\n\nexport function validateQuickBooksCreditMemoRequest(\n request: QuickBooksCreditMemoRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n): void {\n validateRequest(request, realmId, environment, payload, 'credit memo');\n}\n\nfunction validateRequest(\n request: QuickBooksCreateRequest,\n realmId: string,\n environment: 'sandbox' | 'production',\n payload: string | undefined,\n kind: 'invoice' | 'credit memo',\n): void {\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 ${kind} request realm/environment mismatch`);\n }\n if (\n !payload ||\n request.payloadHash !== hashDescriptorPayload(payload, request, kind)\n ) {\n throw new Error(\n `QuickBooks ${kind} request payload mismatch; reconcile the original request`,\n );\n }\n if (\n kind === 'credit memo' &&\n (!('creditedInvoiceExternalId' in request) ||\n !request.creditedInvoiceExternalId ||\n request.creditedInvoiceExternalId.trim() !==\n request.creditedInvoiceExternalId)\n ) {\n throw new Error(\n 'QuickBooks credit memo request requires a credited invoice external ID',\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 ${kind} 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\nfunction close(a: number, b: number): boolean {\n return (\n Number.isFinite(a) &&\n Number.isFinite(b) &&\n Math.abs(a - b) <=\n Number.EPSILON * Math.max(1, Math.abs(a), Math.abs(b)) * 8\n );\n}\n\nfunction finite(value: number, label: string, allowNegative = false): number {\n if (!Number.isFinite(value) || (!allowNegative && value < 0))\n throw new Error(\n `QuickBooks ${label} must be a finite ${allowNegative ? '' : 'non-negative '}amount`,\n );\n return value;\n}\n\nfunction reference(value: string | undefined, label: string) {\n if (!value || value.trim() !== value || value.length > 255)\n throw new Error(`QuickBooks ${label} must be a non-empty realm reference`);\n return { value };\n}\n\nfunction canonicalRateNumber(value: number): string {\n // Number inputs can carry an adjacent binary representation of the exact\n // frozen decimal (for example 0.1 + 0.2). Prefer the shortest nearby decimal\n // through the calculator's supported precision, without changing a value\n // whose additional digits are materially distinct.\n for (let places = 0; places <= 12; places++) {\n const candidate = Number(value.toFixed(places));\n if (close(value, candidate)) return candidate.toString();\n }\n return value.toString();\n}\n\nfunction decimalRate(\n value: number | string | undefined,\n label: string,\n): DecimalRate {\n const text =\n typeof value === 'string' && /^\\d+(?:\\.\\d+)?$/.test(value)\n ? value\n : typeof value === 'number' && Number.isFinite(value) && value >= 0\n ? canonicalRateNumber(value)\n : undefined;\n if (!text || !/^\\d+(?:\\.\\d+)?$/.test(text))\n throw new Error(\n `QuickBooks ${label} needs a frozen component rate from 0 through 1`,\n );\n const [whole, fraction = ''] = text.split('.');\n const denominator = 10n ** BigInt(fraction.length);\n const numerator = BigInt(`${whole}${fraction}`);\n if (numerator > denominator)\n throw new Error(\n `QuickBooks ${label} needs a frozen component rate from 0 through 1`,\n );\n return { numerator, denominator, value: Number(text) };\n}\n\nfunction ratesEqual(left: DecimalRate, right: DecimalRate): boolean {\n return (\n left.numerator * right.denominator === right.numerator * left.denominator\n );\n}\n\nfunction addRates(left: DecimalRate, right: DecimalRate): DecimalRate {\n const numerator =\n left.numerator * right.denominator + right.numerator * left.denominator;\n const denominator = left.denominator * right.denominator;\n return {\n numerator,\n denominator,\n value: Number(numerator) / Number(denominator),\n };\n}\n\nfunction taxPercent(rate: DecimalRate): number {\n return Number(rate.numerator * 100n) / Number(rate.denominator);\n}\n\nfunction currencyMinor(\n amount: number,\n currency: string | undefined,\n label: string,\n): bigint {\n const factor = currencyMinorUnitFactor(currency);\n const rounded = roundCurrencyAmount(amount, currency);\n if (\n factor === undefined ||\n rounded === undefined ||\n (!isCurrencyMinorUnit(amount, currency) && !close(amount, rounded))\n )\n throw new Error(\n `QuickBooks ${label} must fit the explicitly supplied currency's ISO 4217 minor-unit grid`,\n );\n // Match frozenCurrencyAmount: only a value already admitted as ordinary\n // binary noise is normalized before exact minor-unit aggregation. A genuine\n // off-grid value still refuses before any request is mapped.\n return BigInt(\n Math.round(\n (isCurrencyMinorUnit(amount, currency) ? amount : rounded) * factor,\n ),\n );\n}\n\nfunction currencyMajor(minor: bigint, currency: string | undefined): number {\n const factor = currencyMinorUnitFactor(currency);\n if (factor === undefined)\n throw new Error('QuickBooks needs a known currency');\n return Number(minor) / factor;\n}\n\nfunction taxMinorMatchesAllocation(\n taxMinor: bigint,\n numerator: bigint,\n denominator: bigint,\n): boolean {\n const floor = numerator / denominator;\n const remainder = numerator % denominator;\n return taxMinor === floor || (remainder !== 0n && taxMinor === floor + 1n);\n}\n\n/** Exact per-component factors relative to net; component order is significant. */\nfunction orderedFactors(components: readonly FrozenTaxComponent[]): {\n factors: DecimalRate[];\n total: DecimalRate;\n} {\n let total: DecimalRate = { numerator: 0n, denominator: 1n, value: 0 };\n const factors = components.map((component) => {\n const basis = component.compound\n ? addRates({ numerator: 1n, denominator: 1n, value: 1 }, total)\n : { numerator: 1n, denominator: 1n, value: 1 };\n const numerator = component.rate.numerator * basis.numerator;\n const denominator = component.rate.denominator * basis.denominator;\n const factor = {\n numerator,\n denominator,\n value: Number(numerator) / Number(denominator),\n };\n total = addRates(total, factor);\n return factor;\n });\n return { factors, total };\n}\n\nfunction validateFrozenComponentRates(\n components: readonly FrozenTaxComponent[],\n taxableAmount: number,\n currency: string | undefined,\n inclusive: boolean,\n label: string,\n): void {\n const taxableMinor = currencyMinor(\n taxableAmount,\n currency,\n `${label} taxable amount`,\n );\n const { factors, total } = orderedFactors(components);\n for (const [index, component] of components.entries()) {\n const factor = factors[index];\n const numerator = inclusive\n ? taxableMinor * factor.numerator * total.denominator\n : component.basisMinor * component.rate.numerator;\n const denominator = inclusive\n ? factor.denominator * (total.denominator + total.numerator)\n : component.rate.denominator;\n if (!taxMinorMatchesAllocation(component.taxMinor, numerator, denominator))\n throw new Error(\n `QuickBooks ${label} tax component rate is inconsistent with its frozen tax amount`,\n );\n }\n}\n\nfunction frozenCurrencyAmount(\n value: number,\n label: string,\n currency: string | undefined,\n allowNegative = false,\n): number {\n finite(value, label, allowNegative);\n const rounded = roundCurrencyAmount(value, currency);\n // Stored decimal money can reach JavaScript as an adjacent binary value\n // (for example 0.1 * 3). Accept that representation only when the known\n // currency round-trip differs by ordinary floating-point noise; this never\n // authorizes a real off-grid amount such as CAD 0.005 or JPY 100.5.\n if (\n !isCurrencyMinorUnit(value, currency) &&\n (rounded === undefined || !close(value, rounded))\n )\n throw new Error(\n `QuickBooks ${label} must fit the explicitly supplied currency's ISO 4217 minor-unit grid`,\n );\n return value;\n}\n\nfunction hasFrozenSnapshots(\n input: Pick<InvoiceInput, 'quickbooksMapping' | 'lineItems'>,\n): boolean {\n return (\n input.quickbooksMapping?.globalTaxCalculation === 'TaxInclusive' ||\n input.lineItems.some(\n (item) =>\n item.taxAmount !== undefined ||\n item.taxComponents !== undefined ||\n item.taxInclusiveAmount !== undefined ||\n (item.discount !== undefined && item.discount !== 0),\n )\n );\n}\n\n/** Limit accumulated binary error when a valid document has many decimal lines. */\nfunction compensatedSum(values: readonly number[]): number {\n let sum = 0;\n let compensation = 0;\n for (const value of values) {\n const adjusted = value - compensation;\n const next = sum + adjusted;\n compensation = next - sum - adjusted;\n sum = next;\n }\n return sum;\n}\n\nfunction mapDocumentLines(\n input: Pick<\n InvoiceInput,\n | 'lineItems'\n | 'subtotal'\n | 'taxAmount'\n | 'totalAmount'\n | 'currency'\n | 'quickbooksMapping'\n >,\n includeImplicitTaxBasis = false,\n): { lines: QuickBooksSalesLine[]; taxLines: QuickBooksTaxLine[] } {\n const mode = input.quickbooksMapping?.globalTaxCalculation;\n if (mode && !['TaxExcluded', 'TaxInclusive', 'NotApplicable'].includes(mode))\n throw new Error(\n 'QuickBooks globalTaxCalculation must be TaxExcluded, TaxInclusive or NotApplicable',\n );\n const frozen = hasFrozenSnapshots(input);\n const validateAmount = (value: number, label: string) =>\n frozen\n ? frozenCurrencyAmount(value, label, input.currency)\n : finite(value, label);\n validateAmount(input.subtotal, 'subtotal');\n validateAmount(input.taxAmount, 'tax amount');\n validateAmount(input.totalAmount, 'total amount');\n if (input.lineItems.length === 0)\n throw new Error('QuickBooks invoices require at least one sales line');\n const hasLineMapping = input.lineItems.some((item) => item.quickbooksMapping);\n if ((input.taxAmount > 0 || hasLineMapping) && !input.quickbooksMapping)\n throw new Error(\n 'QuickBooks mapped or nonzero-tax invoices require explicit globalTaxCalculation',\n );\n if (\n input.quickbooksMapping &&\n input.lineItems.some((item) => !item.quickbooksMapping)\n )\n throw new Error(\n 'QuickBooks mapped invoices require itemRef and taxCodeRef on every line',\n );\n if (input.taxAmount > 0 && mode === 'NotApplicable')\n throw new Error(\n 'QuickBooks nonzero tax cannot use NotApplicable global tax calculation',\n );\n\n const mapped: QuickBooksSalesLine[] = [];\n const taxLines = new Map<\n string,\n {\n rate: DecimalRate;\n amountMinor: bigint;\n basisMinor: bigint;\n explicitBasis: boolean;\n }\n >();\n const snapshotLineTaxes: number[] = [];\n let hasAnyLineTax = false;\n let hasCompleteLineTax = true;\n const lineTaxSnapshots: Array<{\n taxAmount: number | undefined;\n taxComponents: readonly FrozenTaxComponent[];\n }> = [];\n for (const [index, item] of input.lineItems.entries()) {\n const line = mapLine(item, index, input.currency, mode, frozen);\n mapped.push(...line.lines);\n lineTaxSnapshots.push({\n taxAmount: line.taxAmount,\n taxComponents: line.taxComponents,\n });\n if (line.taxAmount === undefined) hasCompleteLineTax = false;\n else {\n hasAnyLineTax = true;\n snapshotLineTaxes.push(line.taxAmount);\n }\n for (const component of line.taxComponents) {\n const existing = taxLines.get(component.taxRateRef);\n if (existing) {\n if (!ratesEqual(existing.rate, component.rate))\n throw new Error(\n `QuickBooks tax rate ${component.taxRateRef} has inconsistent frozen rates`,\n );\n existing.amountMinor += component.taxMinor;\n existing.basisMinor += component.basisMinor;\n existing.explicitBasis ||= component.explicitBasis;\n if (\n existing.explicitBasis &&\n !Number.isSafeInteger(Number(existing.basisMinor))\n )\n throw new Error(\n 'QuickBooks aggregate taxable basis exceeds safe minor units',\n );\n } else {\n taxLines.set(component.taxRateRef, {\n rate: component.rate,\n amountMinor: component.taxMinor,\n basisMinor: component.basisMinor,\n explicitBasis: component.explicitBasis,\n });\n }\n }\n }\n const mappedSubtotal = compensatedSum(mapped.map((line) => line.Amount));\n if (!close(mappedSubtotal, input.subtotal))\n throw new Error('QuickBooks line amounts must equal the invoice subtotal');\n if (!close(input.subtotal + input.taxAmount, input.totalAmount))\n throw new Error(\n 'QuickBooks subtotal plus tax must equal the invoice total',\n );\n if (taxLines.size > 0) {\n if (\n lineTaxSnapshots.some(\n (line) =>\n line.taxAmount === undefined ||\n (line.taxAmount > 0 && line.taxComponents.length === 0),\n )\n )\n throw new Error(\n 'QuickBooks component tax detail requires components on every taxed line',\n );\n const totalTaxMinor = currencyMinor(\n input.taxAmount,\n input.currency,\n 'tax amount',\n );\n const detailTaxMinor = [...taxLines.values()].reduce(\n (sum, line) => sum + line.amountMinor,\n 0n,\n );\n if (detailTaxMinor !== totalTaxMinor)\n throw new Error(\n 'QuickBooks component tax detail must equal the invoice tax amount',\n );\n }\n if (hasAnyLineTax && !hasCompleteLineTax)\n throw new Error(\n 'QuickBooks stored line tax must be supplied on every line when any line supplies it',\n );\n if (\n hasAnyLineTax &&\n !close(compensatedSum(snapshotLineTaxes), input.taxAmount)\n )\n throw new Error(\n 'QuickBooks stored line tax must equal the invoice tax amount',\n );\n return {\n lines: mapped,\n taxLines: [...taxLines.entries()].map(([taxRateRef, detail]) => ({\n Amount: currencyMajor(detail.amountMinor, input.currency),\n DetailType: 'TaxLineDetail',\n TaxLineDetail: {\n TaxRateRef: { value: taxRateRef },\n TaxPercent: taxPercent(detail.rate),\n PercentBased: true,\n ...(detail.explicitBasis || includeImplicitTaxBasis\n ? {\n NetAmountTaxable: currencyMajor(\n detail.basisMinor,\n input.currency,\n ),\n }\n : {}),\n },\n })),\n };\n}\n\n/** Internal readback projection reuses the mapper's validated aggregate tax bases. */\nexport function mapDocumentTaxReadback(input: InvoiceInput | CreditMemoInput) {\n return mapDocumentLines(input, true).taxLines;\n}\n\nfunction mapLine(\n item: InvoiceLineItemInput,\n index: number,\n currency: string | undefined,\n mode: 'TaxExcluded' | 'TaxInclusive' | 'NotApplicable' | undefined,\n enforceCurrencyGrid: boolean,\n): {\n lines: QuickBooksSalesLine[];\n taxAmount?: number;\n taxComponents: FrozenTaxComponent[];\n} {\n const label = `line ${index + 1}`;\n if (item.taxRate !== undefined && item.taxRate !== 0)\n throw new Error(\n 'QuickBooks numeric taxRate is not supported; use a realm taxCodeRef',\n );\n if (item.taxCode !== undefined)\n throw new Error(\n 'QuickBooks generic taxCode is not a realm tax reference; use quickbooksMapping.taxCodeRef',\n );\n finite(item.quantity, `${label} quantity`);\n if (item.quantity <= 0)\n throw new Error(`QuickBooks ${label} quantity must be greater than zero`);\n finite(item.unitPrice, `${label} unit price`);\n const baseDocumentAmount = item.quantity * item.unitPrice;\n finite(baseDocumentAmount, `${label} pre-discount amount`);\n const validateAmount = (\n value: number,\n amountLabel: string,\n allowNegative = false,\n ) =>\n enforceCurrencyGrid\n ? frozenCurrencyAmount(value, amountLabel, currency, allowNegative)\n : finite(value, amountLabel, allowNegative);\n const discount = validateAmount(item.discount ?? 0, `${label} discount`);\n if (discount > baseDocumentAmount && !close(discount, baseDocumentAmount))\n throw new Error(\n `QuickBooks ${label} discount cannot exceed quantity times unit price`,\n );\n const netAmount = validateAmount(\n item.amount ?? baseDocumentAmount - discount,\n `${label} amount`,\n );\n const taxAmount =\n item.taxAmount === undefined\n ? undefined\n : validateAmount(item.taxAmount, `${label} tax amount`);\n const taxComponents: FrozenTaxComponent[] = [];\n const componentIds = new Set<string>();\n const componentRateRefs = new Set<string>();\n if (item.taxComponents !== undefined) {\n if (taxAmount === undefined)\n throw new Error(\n `QuickBooks ${label} tax components require a line tax amount`,\n );\n const componentTax = item.taxComponents.reduce(\n (sum, component, componentIndex) => {\n if (\n !component ||\n typeof component !== 'object' ||\n Object.keys(component).some(\n (key) =>\n ![\n 'taxCode',\n 'rate',\n 'quickbooksTaxRateRef',\n 'taxAmount',\n 'compound',\n 'taxableAmount',\n ].includes(key),\n )\n )\n throw new Error(\n `QuickBooks ${label} tax component has unsupported fields`,\n );\n if (\n component.compound !== undefined &&\n typeof component.compound !== 'boolean'\n )\n throw new Error(`QuickBooks ${label} compound must be boolean`);\n if (component.compound && component.taxableAmount === undefined)\n throw new Error(\n `QuickBooks ${label} compound tax requires its frozen taxableAmount`,\n );\n if (\n !component.taxCode ||\n component.taxCode.trim() !== component.taxCode\n )\n throw new Error(\n `QuickBooks ${label} tax component ${componentIndex + 1} needs a tax code`,\n );\n const rate = decimalRate(\n component.rate,\n `${label} tax component ${componentIndex + 1}`,\n );\n const taxRateRef = reference(\n component.quickbooksTaxRateRef,\n `${label} tax component ${componentIndex + 1} quickbooksTaxRateRef`,\n ).value;\n const componentAmount = validateAmount(\n component.taxAmount,\n `${label} tax component ${componentIndex + 1}`,\n );\n if (\n componentIds.has(component.taxCode) ||\n componentRateRefs.has(taxRateRef)\n )\n throw new Error(\n `QuickBooks ${label} repeats a tax component or rate reference`,\n );\n componentIds.add(component.taxCode);\n componentRateRefs.add(taxRateRef);\n const expectedBasis =\n currencyMinor(netAmount, currency, `${label} net amount`) +\n (component.compound\n ? taxComponents.reduce((sum, prior) => sum + prior.taxMinor, 0n)\n : 0n);\n const basisMinor =\n component.taxableAmount === undefined\n ? expectedBasis\n : currencyMinor(\n validateAmount(\n component.taxableAmount,\n `${label} taxable basis`,\n ),\n currency,\n `${label} taxable basis`,\n );\n if (!Number.isSafeInteger(Number(basisMinor)))\n throw new Error(\n `QuickBooks ${label} taxable basis exceeds safe minor units`,\n );\n if (basisMinor !== expectedBasis)\n throw new Error(\n `QuickBooks ${label} frozen taxable basis does not match its ordered components`,\n );\n taxComponents.push({\n taxRateRef,\n rate,\n compound: component.compound ?? false,\n basisMinor,\n explicitBasis: component.taxableAmount !== undefined,\n taxMinor: currencyMinor(\n componentAmount,\n currency,\n `${label} tax component ${componentIndex + 1}`,\n ),\n });\n return sum + componentAmount;\n },\n 0,\n );\n if (!close(componentTax, taxAmount))\n throw new Error(\n `QuickBooks ${label} tax components must equal the line tax amount`,\n );\n }\n\n const inclusive = mode === 'TaxInclusive';\n const grossAmount = item.taxInclusiveAmount;\n if (!inclusive && grossAmount !== undefined)\n throw new Error(\n `QuickBooks ${label} tax-inclusive amount requires TaxInclusive global tax calculation`,\n );\n if (inclusive) {\n if (\n grossAmount === undefined ||\n taxAmount === undefined ||\n (taxAmount > 0 && !item.taxComponents?.length)\n )\n throw new Error(\n `QuickBooks ${label} TaxInclusive snapshots require gross amount, line tax and tax components for nonzero tax`,\n );\n validateAmount(grossAmount, `${label} tax-inclusive amount`);\n if (!close(netAmount + taxAmount, grossAmount))\n throw new Error(\n `QuickBooks ${label} net amount plus tax must equal gross amount`,\n );\n if (!close(baseDocumentAmount - discount, grossAmount))\n throw new Error(\n `QuickBooks ${label} gross amount must equal quantity times gross unit price less gross discount`,\n );\n } else if (\n !close(netAmount, baseDocumentAmount - discount) &&\n !matchesCurrencyRoundedLineAmount(\n item.quantity,\n item.unitPrice,\n netAmount + discount,\n currency,\n )\n ) {\n throw new Error(\n `QuickBooks ${label} amount must equal quantity times unit price less discount`,\n );\n }\n const mappedComponents = item.quickbooksMapping?.taxComponents;\n if (\n taxComponents.some((component) => component.compound) &&\n mappedComponents === undefined\n )\n throw new Error(\n `QuickBooks ${label} compound tax requires caller-verified ordered tax-code mapping`,\n );\n if (mappedComponents !== undefined) {\n if (\n !Array.isArray(mappedComponents) ||\n mappedComponents.length !== taxComponents.length\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping must match every frozen component`,\n );\n const refs = new Set<string>();\n for (const [position, mapped] of mappedComponents.entries()) {\n if (\n !mapped ||\n typeof mapped !== 'object' ||\n Object.keys(mapped).some(\n (key) => !['taxRateRef', 'compound'].includes(key),\n ) ||\n typeof mapped.compound !== 'boolean'\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping has unknown order metadata`,\n );\n const ref = reference(\n mapped.taxRateRef,\n `${label} mapped tax rate`,\n ).value;\n const component = taxComponents[position];\n if (\n refs.has(ref) ||\n ref !== component.taxRateRef ||\n mapped.compound !== component.compound\n )\n throw new Error(\n `QuickBooks ${label} ordered tax-code mapping does not match frozen components`,\n );\n refs.add(ref);\n }\n }\n if (taxComponents.length > 0)\n validateFrozenComponentRates(\n taxComponents,\n inclusive ? (grossAmount as number) : netAmount,\n currency,\n inclusive,\n label,\n );\n\n const itemRef = item.quickbooksMapping\n ? reference(item.quickbooksMapping.itemRef, `${label} itemRef`)\n : undefined;\n const taxCodeRef = item.quickbooksMapping\n ? reference(item.quickbooksMapping.taxCodeRef, `${label} taxCodeRef`)\n : undefined;\n const line = (\n amount: number,\n quantity: number,\n unitPrice: number,\n description: string,\n taxInclusiveAmount?: number,\n ) => ({\n LineNum: index + 1,\n Description: description,\n Amount: amount,\n DetailType: 'SalesItemLineDetail' as const,\n SalesItemLineDetail: {\n Qty: quantity,\n UnitPrice: unitPrice,\n ItemRef: itemRef,\n TaxCodeRef: taxCodeRef,\n ...(taxInclusiveAmount === undefined\n ? {}\n : { TaxInclusiveAmt: taxInclusiveAmount }),\n },\n });\n\n if (discount === 0 && !inclusive) {\n return {\n lines: [line(netAmount, item.quantity, item.unitPrice, item.description)],\n taxAmount,\n taxComponents,\n };\n }\n if (\n discount === 0 ||\n isCurrencyMinorUnit(netAmount / item.quantity, currency)\n ) {\n return {\n lines: [\n line(\n netAmount,\n item.quantity,\n netAmount / item.quantity,\n item.description,\n inclusive ? grossAmount : undefined,\n ),\n ],\n taxAmount,\n taxComponents,\n };\n }\n\n let preDiscountAmount = netAmount + discount;\n let negativeAmount = -discount;\n const preDiscountGross = inclusive ? baseDocumentAmount : undefined;\n if (inclusive) {\n const components = item.taxComponents;\n const exemptSnapshot = taxAmount === 0 && !components?.length;\n if (!components?.length && !exemptSnapshot)\n throw new Error(\n `QuickBooks ${label} needs frozen component rates for an inclusive negative discount line`,\n );\n const rate = exemptSnapshot\n ? 0\n : (components ?? []).reduce(\n (sum, component, componentIndex) =>\n sum +\n decimalRate(\n component.rate,\n `${label} tax component ${componentIndex + 1}`,\n ).value,\n 0,\n );\n let discountNet = roundCurrencyAmount(discount / (1 + rate), currency);\n if (taxComponents.some((component) => component.compound)) {\n const { total } = orderedFactors(taxComponents);\n const numerator =\n currencyMinor(discount, currency, `${label} discount`) *\n total.denominator;\n const denominator = total.denominator + total.numerator;\n discountNet = currencyMajor(\n (2n * numerator + denominator) / (2n * denominator),\n currency,\n );\n }\n if (discountNet === undefined)\n throw new Error(\n `QuickBooks ${label} needs a recognized currency to map an inclusive fractional-unit discount`,\n );\n preDiscountAmount = netAmount + discountNet;\n negativeAmount = -discountNet;\n }\n if (enforceCurrencyGrid) {\n frozenCurrencyAmount(\n preDiscountAmount,\n `${label} generated pre-discount amount`,\n currency,\n );\n frozenCurrencyAmount(\n negativeAmount,\n `${label} generated discount amount`,\n currency,\n true,\n );\n }\n let negativeGross: number | undefined;\n if (inclusive) {\n if (grossAmount === undefined || preDiscountGross === undefined)\n throw new Error(\n `QuickBooks ${label} needs frozen gross amounts for an inclusive negative discount line`,\n );\n const unroundedNegativeGross = grossAmount - preDiscountGross;\n negativeGross =\n roundCurrencyAmount(unroundedNegativeGross, currency) ??\n unroundedNegativeGross;\n }\n if (enforceCurrencyGrid && negativeGross !== undefined) {\n frozenCurrencyAmount(\n negativeGross,\n `${label} generated gross discount amount`,\n currency,\n true,\n );\n }\n return {\n lines: [\n line(\n preDiscountAmount,\n item.quantity,\n preDiscountAmount / item.quantity,\n item.description,\n preDiscountGross,\n ),\n line(\n negativeAmount,\n 1,\n negativeAmount,\n `Discount on line ${index + 1}`,\n negativeGross,\n ),\n ],\n taxAmount,\n taxComponents,\n };\n}\n\nfunction basePayload(\n input: Pick<\n InvoiceInput,\n | 'customerId'\n | 'customerExternalId'\n | 'issueDate'\n | 'subtotal'\n | 'taxAmount'\n | 'totalAmount'\n | 'currency'\n | 'memo'\n | 'lineItems'\n | 'quickbooksMapping'\n >,\n number: string,\n dueDate?: Date,\n) {\n const { lines, taxLines } = mapDocumentLines(input);\n return {\n CustomerRef: { value: input.customerExternalId || input.customerId },\n DocNumber: number,\n TxnDate: formatLocalDate(input.issueDate),\n ...(dueDate ? { DueDate: formatLocalDate(dueDate) } : {}),\n Line: lines,\n GlobalTaxCalculation: input.quickbooksMapping?.globalTaxCalculation,\n TxnTaxDetail: input.quickbooksMapping\n ? {\n TotalTax: input.taxAmount,\n ...(taxLines.length > 0 ? { TaxLine: taxLines } : {}),\n }\n : undefined,\n CurrencyRef: input.currency ? { value: input.currency } : undefined,\n CustomerMemo: input.memo ? { value: input.memo } : undefined,\n };\n}\n\nexport function mapInvoiceToQBO(invoice: InvoiceInput) {\n if (invoice.collectionMethod === 'charge_automatically')\n throw new Error(\n 'QuickBooks does not support charge_automatically invoice collection',\n );\n if (invoice.automaticTax)\n throw new Error(\n 'QuickBooks does not support automaticTax invoice calculation',\n );\n return basePayload(\n invoice,\n invoice.invoiceNumber,\n invoice.dueDate,\n ) as ReturnType<typeof basePayload> & { DueDate: string };\n}\n\nexport function mapCreditMemoToQBO(creditMemo: CreditMemoInput) {\n if (\n !creditMemo.creditedInvoiceExternalId ||\n creditMemo.creditedInvoiceExternalId.trim() !==\n creditMemo.creditedInvoiceExternalId\n )\n throw new Error(\n 'QuickBooks credit memos require a credited invoice external ID',\n );\n return basePayload(creditMemo, creditMemo.creditMemoNumber);\n}\n","/** Exact, explicit receivable reclassification. No sales, tax or bank-transfer approximation. */\nimport { createHash } from 'node:crypto';\nimport { currencyMinorUnitFactor, isCurrencyMinorUnit } from './line-amount.js';\n\nexport interface QuickBooksReceivableMapping {\n realmId: string;\n environment: 'sandbox' | 'production';\n version: string;\n reviewEvidenceRef: string;\n accountingBasis: 'accrual';\n taxTiming: 'invoice-tax-point';\n releaseDueDates: 'host-managed';\n currency: string;\n customerRef: string;\n receivablesAccountRef: string;\n retainedAssetAccountRef: string;\n cashAccountRef: string | null;\n}\n/** Ordinary AR/cash authority; cannot authorize retention reclassification. */\nexport interface QuickBooksOrdinaryReceivableMapping\n extends Omit<\n QuickBooksReceivableMapping,\n 'retainedAssetAccountRef' | 'releaseDueDates'\n > {\n kind: 'ordinary';\n retainedAssetAccountRef?: never;\n releaseDueDates?: never;\n}\nexport type QuickBooksReceivableOperationMapping =\n | QuickBooksReceivableMapping\n | QuickBooksOrdinaryReceivableMapping;\n\n/** @internal */\nexport function isOrdinaryReceivableMapping(\n mapping: QuickBooksReceivableOperationMapping,\n): mapping is QuickBooksOrdinaryReceivableMapping {\n return 'kind' in mapping && mapping.kind === 'ordinary';\n}\nexport interface QuickBooksReceivableSource {\n type: 'Invoice' | 'CreditMemo' | 'JournalEntry';\n id: string;\n customerRef: string;\n /** Immutable host snapshot/agreement/release reference, never a guessed provider field. */\n evidenceRef: string;\n}\ninterface TransferEvidence {\n mapping: QuickBooksReceivableOperationMapping;\n source: QuickBooksReceivableSource;\n requestId: string;\n effectiveOn: string;\n evidenceRef: string;\n}\nexport interface QuickBooksReceivableTransferInput extends TransferEvidence {\n kind: 'withhold' | 'release' | 'cash-refund' | 'reverse-cash-refund';\n amountMinor: number;\n}\nexport interface QuickBooksNonCashApplicationInput extends TransferEvidence {\n kind: 'application';\n amountMinor: number;\n debit: { type: 'Invoice' | 'JournalEntry'; id: string };\n credit: { type: 'CreditMemo' | 'JournalEntry'; id: string };\n}\nexport type QuickBooksReceivableInput =\n | QuickBooksReceivableTransferInput\n | QuickBooksNonCashApplicationInput;\nexport interface QuickBooksReceivableRequest {\n version: 1;\n endpoint: 'journalentry' | 'payment';\n realmId: string;\n environment: 'sandbox' | 'production';\n requestId: string;\n payloadHash: string;\n input: QuickBooksReceivableInput;\n}\nexport interface QuickBooksReceivableReadback {\n externalId: string;\n syncToken: string;\n kind: QuickBooksReceivableInput['kind'];\n customerRef: string;\n currency: string;\n effectiveOn: string;\n amountMinor: number;\n /** Noncash application amount is never counted as a customer cash receipt. */\n nonCashAppliedMinor: number;\n /** A cash journal is a record, not evidence of provider bank settlement. */\n recordedCashChangeMinor: number;\n providerProcessedCashMinor: 0;\n bankSettlementVerified: false;\n source: QuickBooksReceivableSource;\n payloadHash: string;\n}\nexport interface QuickBooksReceivableTransferOperations {\n verifyMapping(\n mapping: QuickBooksReceivableOperationMapping,\n ): Promise<{ mappingHash: string; homeCurrency: string }>;\n execute(\n request: QuickBooksReceivableRequest,\n ): Promise<QuickBooksReceivableReadback>;\n /** Reconcile a known remote ID against the complete prepared contract, not just its total. */\n read(\n request: QuickBooksReceivableRequest,\n externalId: string,\n ): Promise<QuickBooksReceivableReadback>;\n}\n\nconst hash = (value: unknown) =>\n createHash('sha256').update(JSON.stringify(value)).digest('hex');\nfunction text(\n value: unknown,\n label: string,\n max = 1000,\n): asserts value is string {\n if (\n typeof value !== 'string' ||\n !value ||\n value !== value.trim() ||\n value.length > max\n )\n throw new Error(`${label} must be explicit trimmed text`);\n}\nfunction id(value: unknown, label: string): asserts value is string {\n text(value, label, 100);\n if (!/^[A-Za-z0-9._-]+$/.test(value))\n throw new Error(`${label} is not a supported provider reference`);\n}\nfunction date(value: string) {\n if (\n !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) ||\n !Number.isFinite(Date.parse(value)) ||\n new Date(value).toISOString().slice(0, 10) !== value\n )\n throw new Error('Receivable effective date is invalid');\n}\nfunction minor(value: number, currency: string): number {\n const factor = currencyMinorUnitFactor(currency);\n if (!factor || !Number.isSafeInteger(value) || value <= 0)\n throw new Error(\n 'Receivable amount must be positive safe integer currency minor units',\n );\n const major = value / factor;\n if (\n !isCurrencyMinorUnit(major, currency) ||\n Math.round(major * factor) !== value\n )\n throw new Error(\n 'Receivable amount cannot be represented exactly by the provider',\n );\n return major;\n}\nexport function validateQuickBooksReceivableMapping(\n mapping: QuickBooksReceivableOperationMapping,\n) {\n const ordinary = isOrdinaryReceivableMapping(mapping);\n if (\n ('kind' in mapping && !ordinary) ||\n (ordinary &&\n ('retainedAssetAccountRef' in mapping || 'releaseDueDates' in mapping))\n )\n throw new Error('Receivable mapping kind and retention authority conflict');\n id(mapping.realmId, 'Realm');\n id(mapping.customerRef, 'Customer');\n text(mapping.version, 'Mapping version');\n text(mapping.reviewEvidenceRef, 'Mapping review evidence');\n if (\n !['sandbox', 'production'].includes(mapping.environment) ||\n mapping.accountingBasis !== 'accrual' ||\n mapping.taxTiming !== 'invoice-tax-point' ||\n (!ordinary && mapping.releaseDueDates !== 'host-managed')\n )\n throw new Error(\n 'Receivable transfers support explicit accrual, invoice-tax-point and host-managed release due dates only',\n );\n if (\n !/^[A-Z]{3}$/.test(mapping.currency) ||\n !currencyMinorUnitFactor(mapping.currency)\n )\n throw new Error('Unsupported receivable currency');\n const refs = [\n mapping.receivablesAccountRef,\n ...(ordinary ? [] : [mapping.retainedAssetAccountRef]),\n ...(mapping.cashAccountRef === null ? [] : [mapping.cashAccountRef]),\n ];\n for (const ref of refs) id(ref, 'Posting account');\n if (new Set(refs).size !== refs.length)\n throw new Error('Receivable posting accounts must be distinct');\n}\nfunction validate(input: QuickBooksReceivableInput) {\n validateQuickBooksReceivableMapping(input.mapping);\n if (\n isOrdinaryReceivableMapping(input.mapping) &&\n (input.kind === 'withhold' || input.kind === 'release')\n )\n throw new Error(\n 'Ordinary receivable mapping cannot authorize retention transfers',\n );\n id(input.requestId, 'Request');\n if (input.requestId.length > 50)\n throw new Error('QuickBooks requestId must contain at most 50 characters');\n date(input.effectiveOn);\n text(input.evidenceRef, 'Operation evidence', 1000);\n if (!['Invoice', 'CreditMemo', 'JournalEntry'].includes(input.source.type))\n throw new Error('Unsupported source transaction type');\n id(input.source.id, 'Source transaction');\n id(input.source.customerRef, 'Source customer');\n text(input.source.evidenceRef, 'Source evidence');\n if (input.source.customerRef !== input.mapping.customerRef)\n throw new Error('Source customer differs from receivable mapping');\n minor(input.amountMinor, input.mapping.currency);\n if (input.kind === 'application') {\n if (\n !['Invoice', 'JournalEntry'].includes(input.debit.type) ||\n !['CreditMemo', 'JournalEntry'].includes(input.credit.type)\n )\n throw new Error('Unsupported noncash application transaction types');\n id(input.debit.id, 'Debit transaction');\n id(input.credit.id, 'Credit transaction');\n if (\n input.debit.type === input.credit.type &&\n input.debit.id === input.credit.id\n )\n throw new Error('Cannot apply a journal to itself');\n } else if (\n !['withhold', 'release', 'cash-refund', 'reverse-cash-refund'].includes(\n input.kind,\n )\n )\n throw new Error('Unsupported receivable transfer direction');\n else if (input.kind.includes('cash-refund') && !input.mapping.cashAccountRef)\n throw new Error('Cash refund recording requires an explicit cash account');\n}\nexport function mapQuickBooksReceivableRequest(\n input: QuickBooksReceivableInput,\n): Record<string, unknown> {\n validate(input);\n const amount = minor(input.amountMinor, input.mapping.currency);\n const source = `${input.source.type}:${input.source.id}; customer:${input.source.customerRef}; evidence:${input.source.evidenceRef}`;\n const note = `${input.kind}; ${source}; operation:${input.evidenceRef}; mapping:${input.mapping.version}; request:${input.requestId}`;\n if (note.length > 4000)\n throw new Error('Receivable provenance exceeds the provider note limit');\n const base = {\n TxnDate: input.effectiveOn,\n CurrencyRef: { value: input.mapping.currency },\n PrivateNote: note,\n };\n if (input.kind === 'application')\n return {\n ...base,\n CustomerRef: { value: input.mapping.customerRef },\n TotalAmt: 0,\n ProcessPayment: false,\n Line: [input.debit, input.credit].map((ref) => ({\n Amount: amount,\n LinkedTxn: [{ TxnType: ref.type, TxnId: ref.id }],\n })),\n };\n const arDebit = input.kind === 'release' || input.kind === 'cash-refund';\n const counterpart = input.kind.includes('cash-refund')\n ? input.mapping.cashAccountRef\n : input.mapping.retainedAssetAccountRef;\n return {\n ...base,\n Line: [\n { account: input.mapping.receivablesAccountRef, debit: arDebit },\n { account: counterpart, debit: !arDebit },\n ].map((line, index) => ({\n LineNum: index + 1,\n Description: source,\n Amount: amount,\n DetailType: 'JournalEntryLineDetail',\n JournalEntryLineDetail: {\n PostingType: line.debit ? 'Debit' : 'Credit',\n AccountRef: { value: line.account },\n Entity: {\n Type: 'Customer',\n EntityRef: { value: input.mapping.customerRef },\n },\n },\n })),\n };\n}\n/** Pure preparation. Persist before sending; the hash does not prove a remote write occurred once. */\nexport function prepareQuickBooksReceivableRequest(\n input: QuickBooksReceivableInput,\n): QuickBooksReceivableRequest {\n const frozenInput = structuredClone(input),\n body = mapQuickBooksReceivableRequest(frozenInput);\n return Object.freeze({\n version: 1,\n endpoint: input.kind === 'application' ? 'payment' : 'journalentry',\n realmId: input.mapping.realmId,\n environment: input.mapping.environment,\n requestId: input.requestId,\n payloadHash: hash({ input: frozenInput, body }),\n input: frozenInput,\n });\n}\nexport function validateQuickBooksReceivableRequest(\n request: QuickBooksReceivableRequest,\n realmId: string,\n environment: string,\n serializedBody?: string,\n) {\n const expected = prepareQuickBooksReceivableRequest(request.input);\n if (\n request.version !== 1 ||\n request.realmId !== realmId ||\n request.environment !== environment ||\n request.endpoint !== expected.endpoint ||\n request.requestId !== expected.requestId ||\n request.payloadHash !== expected.payloadHash ||\n request.realmId !== expected.realmId ||\n request.environment !== expected.environment ||\n (serializedBody !== undefined &&\n serializedBody !==\n JSON.stringify(mapQuickBooksReceivableRequest(request.input)))\n )\n throw new Error(\n 'Receivable request scope, provenance or frozen payload changed',\n );\n}\n\n/** Exact readback validation; provider-added IDs/names are allowed, omitted financial facts are not. */\nexport function reconcileQuickBooksReceivableRecord(\n request: QuickBooksReceivableRequest,\n value: unknown,\n): QuickBooksReceivableReadback {\n validateQuickBooksReceivableRequest(\n request,\n request.realmId,\n request.environment,\n );\n const raw = value as Record<string, any>,\n expected = mapQuickBooksReceivableRequest(request.input),\n input = request.input;\n if (!raw || typeof raw !== 'object')\n throw new Error('Receivable provider record is missing');\n id(raw.Id, 'Provider record');\n text(raw.SyncToken, 'Provider sync token', 100);\n if (\n raw.TxnDate !== expected.TxnDate ||\n raw.CurrencyRef?.value !== input.mapping.currency ||\n raw.PrivateNote !== expected.PrivateNote ||\n !Array.isArray(raw.Line) ||\n raw.Line.length !== 2\n )\n throw new Error(\n 'Receivable provider identity, currency, date or evidence differs',\n );\n if (\n (raw.ExchangeRate !== undefined && raw.ExchangeRate !== 1) ||\n (raw.TxnTaxDetail !== undefined && raw.TxnTaxDetail?.TotalTax !== 0)\n )\n throw new Error(\n 'Receivable readback contains unsupported exchange or tax effects',\n );\n const expectedLines = expected.Line as Record<string, any>[];\n for (let i = 0; i < 2; i++) {\n const line = raw.Line[i],\n wanted = expectedLines[i];\n if (line.Amount !== wanted.Amount)\n throw new Error('Receivable provider line amount differs');\n if (input.kind === 'application') {\n if (\n !Array.isArray(line.LinkedTxn) ||\n line.LinkedTxn.length !== 1 ||\n line.LinkedTxn[0].TxnType !== wanted.LinkedTxn[0].TxnType ||\n line.LinkedTxn[0].TxnId !== wanted.LinkedTxn[0].TxnId\n )\n throw new Error('Receivable application linkage differs');\n } else {\n const details = line.JournalEntryLineDetail,\n required = wanted.JournalEntryLineDetail;\n if (\n line.DetailType !== 'JournalEntryLineDetail' ||\n line.Description !== wanted.Description ||\n details?.PostingType !== required.PostingType ||\n details?.AccountRef?.value !== required.AccountRef.value ||\n details?.Entity?.Type !== 'Customer' ||\n details?.Entity?.EntityRef?.value !== input.mapping.customerRef ||\n details?.TaxAmount !== undefined ||\n details?.TaxCodeRef !== undefined\n )\n throw new Error('Receivable journal posting authority differs');\n }\n }\n if (\n input.kind === 'application' &&\n (raw.TotalAmt !== 0 ||\n raw.UnappliedAmt !== 0 ||\n raw.CustomerRef?.value !== input.mapping.customerRef ||\n raw.ProcessPayment === true)\n )\n throw new Error(\n 'Noncash application must have zero cash and no unapplied balance',\n );\n return {\n externalId: raw.Id,\n syncToken: raw.SyncToken,\n kind: input.kind,\n customerRef: input.mapping.customerRef,\n currency: input.mapping.currency,\n effectiveOn: input.effectiveOn,\n amountMinor: input.amountMinor,\n nonCashAppliedMinor: input.kind === 'application' ? input.amountMinor : 0,\n recordedCashChangeMinor:\n input.kind === 'cash-refund'\n ? -input.amountMinor\n : input.kind === 'reverse-cash-refund'\n ? input.amountMinor\n : 0,\n providerProcessedCashMinor: 0,\n bankSettlementVerified: false,\n source: structuredClone(input.source),\n payloadHash: request.payloadHash,\n };\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,6 @@ export declare function getAccountingProvider(userOptions: Partial<AccountingOpt
|
|
|
91
91
|
}): Promise<AccountingProvider>;
|
|
92
92
|
/** @internal */
|
|
93
93
|
export declare const PACKAGE_VERSION_INITIALIZED = true;
|
|
94
|
-
export type { QuickBooksNonCashApplicationInput, QuickBooksReceivableInput, QuickBooksReceivableMapping, QuickBooksReceivableReadback, QuickBooksReceivableRequest, QuickBooksReceivableSource, QuickBooksReceivableTransferInput, QuickBooksReceivableTransferOperations, } from './providers/quickbooks/receivable-transfer.js';
|
|
94
|
+
export type { QuickBooksNonCashApplicationInput, QuickBooksOrdinaryReceivableMapping, QuickBooksReceivableInput, QuickBooksReceivableMapping, QuickBooksReceivableOperationMapping, QuickBooksReceivableReadback, QuickBooksReceivableRequest, QuickBooksReceivableSource, QuickBooksReceivableTransferInput, QuickBooksReceivableTransferOperations, } from './providers/quickbooks/receivable-transfer.js';
|
|
95
95
|
export { prepareQuickBooksReceivableRequest, reconcileQuickBooksReceivableRecord, } from './providers/quickbooks/receivable-transfer.js';
|
|
96
96
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAE9E,cAAc,YAAY,CAAC;AAmB3B;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,GACzB,OAAO,IAAI,iBAAiB,CAE9B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,iBAAiB,GACzB,OAAO,IAAI,aAAa,CAE1B;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,aAAa,CAAC,GACzD,oBAAoB,CAMtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;CAAE,GAC5E,OAAO,CAAC,kBAAkB,CAAC,CAmC7B;AAED,gBAAgB;AAChB,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD,YAAY,EACV,iCAAiC,EACjC,yBAAyB,EACzB,2BAA2B,EAC3B,4BAA4B,EAC5B,2BAA2B,EAC3B,0BAA0B,EAC1B,iCAAiC,EACjC,sCAAsC,GACvC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EACL,kCAAkC,EAClC,mCAAmC,GACpC,MAAM,+CAA+C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACd,MAAM,YAAY,CAAC;AAEpB,YAAY,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,kCAAkC,EACvC,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,6CAA6C,CAAC;AACrD,OAAO,EACL,kCAAkC,EAClC,+BAA+B,GAChC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAE9E,cAAc,YAAY,CAAC;AAmB3B;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,iBAAiB,GACzB,OAAO,IAAI,iBAAiB,CAE9B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,iBAAiB,GACzB,OAAO,IAAI,aAAa,CAE1B;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,aAAa,CAAC,GACzD,oBAAoB,CAMtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;CAAE,GAC5E,OAAO,CAAC,kBAAkB,CAAC,CAmC7B;AAED,gBAAgB;AAChB,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAEhD,YAAY,EACV,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,2BAA2B,EAC3B,oCAAoC,EACpC,4BAA4B,EAC5B,2BAA2B,EAC3B,0BAA0B,EAC1B,iCAAiC,EACjC,sCAAsC,GACvC,MAAM,+CAA+C,CAAC;AACvD,OAAO,EACL,kCAAkC,EAClC,mCAAmC,GACpC,MAAM,+CAA+C,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as QuickBooksWriteError, r as StripeApiError, t as QuickBooksOAuthError } from "./chunks/errors-DIqXkm4s.js";
|
|
2
|
-
import { c as
|
|
2
|
+
import { c as mapDocumentTaxReadback, d as prepareQuickBooksInvoiceRequest, i as reconcileQuickBooksReceivableRecord, l as mapInvoiceToQBO, r as prepareQuickBooksReceivableRequest, s as mapCreditMemoToQBO, u as prepareQuickBooksCreditMemoRequest } from "./chunks/receivable-transfer-DPxto4TY.js";
|
|
3
3
|
import { loadEnvConfig } from "@happyvertical/utils";
|
|
4
4
|
import { createHash, timingSafeEqual } from "node:crypto";
|
|
5
5
|
//#region src/providers/quickbooks/document-readback.ts
|
|
@@ -300,7 +300,7 @@ async function getAccountingProvider(userOptions) {
|
|
|
300
300
|
switch (options.type) {
|
|
301
301
|
case "quickbooks": {
|
|
302
302
|
if (!isQuickBooksOptions(options)) throw new Error("Invalid QuickBooks options");
|
|
303
|
-
const { QuickBooksProvider } = await import("./chunks/quickbooks-
|
|
303
|
+
const { QuickBooksProvider } = await import("./chunks/quickbooks-Bo_BjMv1.js");
|
|
304
304
|
return new QuickBooksProvider(options);
|
|
305
305
|
}
|
|
306
306
|
case "stripe": {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/providers/quickbooks/document-readback.ts","../src/providers/quickbooks/oauth.ts","../src/index.ts"],"sourcesContent":["import type {\n CreditMemoInput,\n InvoiceInput,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n} from '../../types.js';\nimport {\n mapCreditMemoToQBO,\n mapDocumentTaxReadback,\n mapInvoiceToQBO,\n prepareQuickBooksCreditMemoRequest,\n prepareQuickBooksInvoiceRequest,\n} from './invoice-request.js';\n\n/** The host obtains this record through its authorized realm-bound provider. */\nexport interface QuickBooksDocumentReadback {\n readonly realmId: string;\n readonly environment: 'sandbox' | 'production';\n readonly externalId: string;\n readonly record: unknown;\n}\nexport interface VerifiedQuickBooksDocumentReadback {\n readonly externalId: string;\n readonly syncToken: string;\n readonly payloadHash: string;\n}\nfunction reject(): never {\n // Never put private provider payloads or credentials into a thrown error.\n throw new Error('QuickBooks readback differs from the frozen document');\n}\nfunction object(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) reject();\n return value as Record<string, unknown>;\n}\nfunction matches(expected: unknown, actual: unknown): boolean {\n if (Array.isArray(expected))\n return (\n Array.isArray(actual) &&\n expected.length === actual.length &&\n expected.every((item, index) => matches(item, actual[index]))\n );\n if (expected !== null && typeof expected === 'object') {\n if (!actual || typeof actual !== 'object' || Array.isArray(actual))\n return false;\n const record = actual as Record<string, unknown>;\n return Object.entries(expected).every(\n ([key, value]) => value === undefined || matches(value, record[key]),\n );\n }\n return expected === actual;\n}\nfunction verify(\n input: InvoiceInput | CreditMemoInput,\n request: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest,\n prepared: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest,\n payload: Record<string, unknown>,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n if (\n !observed.externalId ||\n observed.externalId.trim() !== observed.externalId ||\n request.realmId !== observed.realmId ||\n request.environment !== observed.environment ||\n request.requestId !== prepared.requestId ||\n request.payloadHash !== prepared.payloadHash ||\n !input.currency ||\n !input.quickbooksMapping\n )\n reject();\n const raw = object(observed.record);\n if (\n raw.Id !== observed.externalId ||\n typeof raw.SyncToken !== 'string' ||\n !/^\\d+$/.test(raw.SyncToken) ||\n raw.TotalAmt !== input.totalAmount ||\n raw.status === 'Deleted' ||\n raw.TxnStatus === 'Voided' ||\n (raw.Deposit !== undefined && raw.Deposit !== 0) ||\n (raw.ExchangeRate !== undefined && raw.ExchangeRate !== 1)\n )\n reject();\n if (!Array.isArray(raw.Line)) reject();\n const lines: unknown[] = [];\n let subtotals = 0;\n for (const item of raw.Line) {\n const line = object(item);\n if (line.DetailType === 'SalesItemLineDetail') lines.push(line);\n else if (\n line.DetailType === 'SubTotalLineDetail' &&\n ++subtotals === 1 &&\n line.Amount === input.subtotal\n )\n continue;\n else reject();\n }\n const expectedTax = object(payload.TxnTaxDetail);\n const actualTax = object(raw.TxnTaxDetail);\n // A header total alone cannot prove which nonzero tax components were posted.\n if (input.taxAmount !== 0 && !Array.isArray(expectedTax.TaxLine)) reject();\n if (\n expectedTax.TaxLine === undefined &&\n actualTax.TaxLine !== undefined &&\n (!Array.isArray(actualTax.TaxLine) || actualTax.TaxLine.length !== 0)\n )\n reject();\n // Provider-added taxable bases are economics, not display metadata. Compare\n // them with the owning mapper's aggregate basis without changing create bytes.\n if (Array.isArray(actualTax.TaxLine)) {\n const bases = mapDocumentTaxReadback(input);\n for (const [index, line] of actualTax.TaxLine.entries()) {\n const detail = object(object(line).TaxLineDetail);\n if (\n detail.NetAmountTaxable !== undefined &&\n detail.NetAmountTaxable !== bases[index]?.TaxLineDetail.NetAmountTaxable\n )\n reject();\n }\n }\n if (!matches(payload, { ...raw, Line: lines })) reject();\n return {\n externalId: observed.externalId,\n syncToken: raw.SyncToken,\n payloadHash: prepared.payloadHash,\n };\n}\n\n/** Verify a fetched invoice; never guesses absence or makes a provider call. */\nexport function verifyQuickBooksInvoiceReadback(\n invoice: InvoiceInput,\n request: QuickBooksInvoiceRequest,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n const {\n externalId: _externalId,\n quickbooksRequest: _request,\n ...original\n } = invoice;\n const prepared = prepareQuickBooksInvoiceRequest(original, request);\n return verify(\n original,\n request,\n prepared,\n mapInvoiceToQBO(original),\n observed,\n );\n}\n\n/** Verify the credit document only; application to the original invoice remains separate. */\nexport function verifyQuickBooksCreditMemoReadback(\n credit: CreditMemoInput,\n request: QuickBooksCreditMemoRequest,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n if (request.creditedInvoiceExternalId !== credit.creditedInvoiceExternalId)\n reject();\n const {\n externalId: _externalId,\n quickbooksCreditMemoRequest: _request,\n ...original\n } = credit;\n const prepared = prepareQuickBooksCreditMemoRequest(original, request);\n return verify(\n original,\n request,\n prepared,\n mapCreditMemoToQBO(original),\n observed,\n );\n}\n","import { createHash, timingSafeEqual } from 'node:crypto';\nimport { QuickBooksOAuthError } from '../../errors.js';\nimport type {\n QuickBooksOAuthClient,\n QuickBooksOAuthConnection,\n QuickBooksOAuthOptions,\n TokenSet,\n} from '../../types.js';\n\nconst ACCOUNTING_SCOPE = 'com.intuit.quickbooks.accounting';\n\n/** Create a public QuickBooks connection helper backed by Intuit's OAuth client. */\nexport async function createQuickBooksOAuthClient(\n options: QuickBooksOAuthOptions,\n): Promise<QuickBooksOAuthClient> {\n const redirect = validateOptions(options);\n const OAuthClient = (await import('intuit-oauth')).default;\n let client: InstanceType<typeof OAuthClient>;\n try {\n client = new OAuthClient({\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n environment: options.environment,\n redirectUri: options.redirectUri,\n });\n } catch {\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n }\n\n return {\n authorizationUrl({ state }) {\n validateOpaque(state, 'INVALID_STATE');\n try {\n return client.authorizeUri({ scope: [ACCOUNTING_SCOPE], state });\n } catch {\n throw new QuickBooksOAuthError('AUTHORIZATION_FAILED');\n }\n },\n\n async exchangeCallback({ callbackUrl, expectedState }) {\n validateOpaque(expectedState, 'INVALID_STATE');\n const callback = validateCallback(callbackUrl, redirect);\n const state = single(callback.searchParams, 'state', 'INVALID_STATE');\n validateOpaque(state, 'INVALID_STATE');\n if (!sameOpaqueValue(state, expectedState))\n throw new QuickBooksOAuthError('INVALID_STATE');\n const code = single(callback.searchParams, 'code', 'INVALID_CALLBACK');\n if (code.length > 4096)\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n const realmId = single(\n callback.searchParams,\n 'realmId',\n 'INVALID_CALLBACK',\n );\n if (realmId.length > 255)\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n for (const name of callback.searchParams.keys())\n if (!['code', 'realmId', 'state'].includes(name))\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n\n // Rebuild from the configured redirect and the three validated values.\n // intuit-oauth treats a callback `redirectUri` query as an override.\n const exchangeUrl = new URL(redirect);\n exchangeUrl.searchParams.set('code', code);\n exchangeUrl.searchParams.set('realmId', realmId);\n exchangeUrl.searchParams.set('state', state);\n\n try {\n const response = await client.createToken(exchangeUrl.toString());\n const token = response.getJson();\n const tokens = mapTokens(token);\n const grantedScopes = scopes(token.scope);\n return {\n realmId,\n tokens,\n ...(grantedScopes ? { grantedScopes } : {}),\n } satisfies QuickBooksOAuthConnection;\n } catch (error) {\n if (error instanceof QuickBooksOAuthError) throw error;\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n }\n },\n\n async revoke({ refreshToken }) {\n validateOpaque(refreshToken, 'INVALID_TOKEN');\n try {\n await client.revoke({ refresh_token: refreshToken });\n } catch {\n throw new QuickBooksOAuthError('REVOCATION_FAILED');\n }\n },\n };\n}\n\nfunction validateOptions(options: QuickBooksOAuthOptions): URL {\n if (\n !options ||\n !['sandbox', 'production'].includes(options.environment) ||\n !nonempty(options.clientId) ||\n !nonempty(options.clientSecret) ||\n !nonempty(options.redirectUri)\n )\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n\n try {\n const redirect = new URL(options.redirectUri);\n if (\n !['http:', 'https:'].includes(redirect.protocol) ||\n redirect.username ||\n redirect.password ||\n redirect.search ||\n redirect.hash\n )\n throw new Error('invalid redirect');\n return redirect;\n } catch {\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n }\n}\n\nfunction validateCallback(callbackUrl: string, redirect: URL): URL {\n try {\n const callback = new URL(callbackUrl);\n if (\n callback.protocol !== redirect.protocol ||\n callback.origin !== redirect.origin ||\n callback.pathname !== redirect.pathname ||\n callback.username ||\n callback.password ||\n callback.hash ||\n callback.searchParams.has('error')\n )\n throw new Error('invalid callback');\n return callback;\n } catch {\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n }\n}\n\nfunction single(\n params: URLSearchParams,\n name: string,\n code: 'INVALID_STATE' | 'INVALID_CALLBACK',\n): string {\n const values = params.getAll(name);\n if (values.length !== 1 || !nonempty(values[0]))\n throw new QuickBooksOAuthError(code);\n return values[0];\n}\n\nfunction validateOpaque(\n value: string,\n code: 'INVALID_STATE' | 'INVALID_TOKEN',\n): void {\n if (!nonempty(value) || value.length > 4096)\n throw new QuickBooksOAuthError(code);\n}\n\nfunction sameOpaqueValue(actual: string, expected: string): boolean {\n const digest = (value: string) => createHash('sha256').update(value).digest();\n return timingSafeEqual(digest(actual), digest(expected));\n}\n\nfunction mapTokens(token: {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n token_type?: unknown;\n}): TokenSet {\n if (\n !nonempty(token?.access_token) ||\n !nonempty(token.refresh_token) ||\n typeof token.expires_in !== 'number' ||\n !Number.isFinite(token.expires_in) ||\n token.expires_in <= 0 ||\n (token.token_type !== undefined && !nonempty(token.token_type))\n )\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n const expiresAt = new Date(Date.now() + token.expires_in * 1000);\n if (!Number.isFinite(expiresAt.getTime()))\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n return {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt,\n ...(token.token_type ? { tokenType: token.token_type } : {}),\n };\n}\n\nfunction scopes(value: unknown): string[] | undefined {\n const values = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? value.split(/\\s+/)\n : [];\n const normalized = [\n ...new Set(values.filter((item): item is string => nonempty(item))),\n ];\n return normalized.length ? normalized : undefined;\n}\n\nfunction nonempty(value: unknown): value is string {\n return (\n typeof value === 'string' && value.length > 0 && value.trim() === value\n );\n}\n","/**\n * @happyvertical/accounting - Multi-provider accounting integration\n *\n * This package provides a unified interface for syncing and auditing\n * accounting data (AR/AP) with external providers like QuickBooks Online,\n * Stripe, PayPal, and Coinbase Commerce.\n *\n * Key components:\n * - getAccountingProvider() - Factory function for creating provider instances\n * - AccountingProvider - Unified interface for all providers\n * - Audit operations for reconciling local vs external data\n *\n * @example\n * ```typescript\n * import { getAccountingProvider } from '@happyvertical/accounting';\n *\n * const provider = await getAccountingProvider({\n * type: 'quickbooks',\n * clientId: 'xxx',\n * clientSecret: 'xxx',\n * realmId: 'xxx',\n * refreshToken: 'xxx'\n * });\n *\n * // Sync a customer\n * const result = await provider.customers.sync(customer);\n *\n * // Audit invoices\n * const report = await provider.audit.reconcileInvoices(localInvoices);\n * ```\n */\n\nimport { loadEnvConfig } from '@happyvertical/utils';\nimport type {\n AccountingOptions,\n AccountingProvider,\n CreditMemoOperations,\n QuickBooksOptions,\n StripeOptions,\n} from './types.js';\n\nexport type { QuickBooksOAuthErrorCode } from './errors.js';\nexport {\n QuickBooksOAuthError,\n QuickBooksWriteError,\n StripeApiError,\n} from './errors.js';\nexport {\n type QuickBooksDocumentReadback,\n type VerifiedQuickBooksDocumentReadback,\n verifyQuickBooksCreditMemoReadback,\n verifyQuickBooksInvoiceReadback,\n} from './providers/quickbooks/document-readback.js';\nexport {\n prepareQuickBooksCreditMemoRequest,\n prepareQuickBooksInvoiceRequest,\n} from './providers/quickbooks/invoice-request.js';\nexport { createQuickBooksOAuthClient } from './providers/quickbooks/oauth.js';\n// Re-export all types\nexport * from './types.js';\n\n/**\n * Schema for environment variable type conversion\n */\nconst accountingOptionsSchema: Record<string, 'string' | 'number' | 'boolean'> =\n {\n type: 'string',\n clientId: 'string',\n clientSecret: 'string',\n realmId: 'string',\n refreshToken: 'string',\n environment: 'string',\n secretKey: 'string',\n apiKey: 'string',\n timeout: 'number',\n maxRetries: 'number',\n };\n\n/**\n * Type guard for QuickBooks options\n */\nexport function isQuickBooksOptions(\n options: AccountingOptions,\n): options is QuickBooksOptions {\n return options.type === 'quickbooks';\n}\n\n/**\n * Type guard for Stripe options\n */\nexport function isStripeOptions(\n options: AccountingOptions,\n): options is StripeOptions {\n return options.type === 'stripe';\n}\n\n/**\n * Return the provider's credit-memo capability or fail explicitly before a\n * caller attempts a write against a provider that does not implement it.\n */\nexport function requireCreditMemoOperations(\n provider: Pick<AccountingProvider, 'type' | 'creditMemos'>,\n): CreditMemoOperations {\n if (!provider.creditMemos)\n throw new Error(\n `Accounting provider '${provider.type}' does not support credit memos`,\n );\n return provider.creditMemos;\n}\n\n/**\n * Create an accounting provider instance\n *\n * Factory function that creates a provider-specific implementation\n * of the AccountingProvider interface. Uses dynamic imports to\n * load only the provider code you need.\n *\n * @param userOptions - Provider configuration options\n * @returns AccountingProvider instance\n *\n * @example\n * ```typescript\n * // QuickBooks Online\n * const qbo = await getAccountingProvider({\n * type: 'quickbooks',\n * clientId: process.env.QBO_CLIENT_ID!,\n * clientSecret: process.env.QBO_CLIENT_SECRET!,\n * realmId: process.env.QBO_REALM_ID!,\n * refreshToken: process.env.QBO_REFRESH_TOKEN!,\n * environment: 'sandbox',\n * onTokenRefresh: async (tokens) => {\n * // Persist refreshed tokens\n * await saveTokens(tokens);\n * }\n * });\n *\n * // Stripe\n * const stripe = await getAccountingProvider({\n * type: 'stripe',\n * secretKey: process.env.STRIPE_SECRET_KEY!\n * });\n *\n * // Use env vars for configuration\n * const provider = await getAccountingProvider({ type: 'quickbooks' });\n * // Reads HAVE_ACCOUNTING_CLIENT_ID, HAVE_ACCOUNTING_REALM_ID, etc.\n * ```\n */\nexport async function getAccountingProvider(\n userOptions: Partial<AccountingOptions> & { type: AccountingOptions['type'] },\n): Promise<AccountingProvider> {\n // Load config from env vars, user options take precedence\n const options = loadEnvConfig<AccountingOptions>(userOptions, {\n packageName: 'accounting',\n schema: accountingOptionsSchema,\n });\n\n switch (options.type) {\n case 'quickbooks': {\n if (!isQuickBooksOptions(options)) {\n throw new Error('Invalid QuickBooks options');\n }\n const { QuickBooksProvider } = await import(\n './providers/quickbooks/index.js'\n );\n return new QuickBooksProvider(options);\n }\n\n case 'stripe': {\n if (!isStripeOptions(options)) {\n throw new Error('Invalid Stripe options');\n }\n const { StripeProvider } = await import('./providers/stripe/index.js');\n return new StripeProvider(options);\n }\n\n case 'paypal':\n throw new Error('PayPal provider not yet implemented');\n\n case 'coinbase':\n throw new Error('Coinbase provider not yet implemented');\n\n default:\n throw new Error(`Unknown provider type: ${(options as any).type}`);\n }\n}\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n\nexport type {\n QuickBooksNonCashApplicationInput,\n QuickBooksReceivableInput,\n QuickBooksReceivableMapping,\n QuickBooksReceivableReadback,\n QuickBooksReceivableRequest,\n QuickBooksReceivableSource,\n QuickBooksReceivableTransferInput,\n QuickBooksReceivableTransferOperations,\n} from './providers/quickbooks/receivable-transfer.js';\nexport {\n prepareQuickBooksReceivableRequest,\n reconcileQuickBooksReceivableRecord,\n} from './providers/quickbooks/receivable-transfer.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/providers/quickbooks/document-readback.ts","../src/providers/quickbooks/oauth.ts","../src/index.ts"],"sourcesContent":["import type {\n CreditMemoInput,\n InvoiceInput,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n} from '../../types.js';\nimport {\n mapCreditMemoToQBO,\n mapDocumentTaxReadback,\n mapInvoiceToQBO,\n prepareQuickBooksCreditMemoRequest,\n prepareQuickBooksInvoiceRequest,\n} from './invoice-request.js';\n\n/** The host obtains this record through its authorized realm-bound provider. */\nexport interface QuickBooksDocumentReadback {\n readonly realmId: string;\n readonly environment: 'sandbox' | 'production';\n readonly externalId: string;\n readonly record: unknown;\n}\nexport interface VerifiedQuickBooksDocumentReadback {\n readonly externalId: string;\n readonly syncToken: string;\n readonly payloadHash: string;\n}\nfunction reject(): never {\n // Never put private provider payloads or credentials into a thrown error.\n throw new Error('QuickBooks readback differs from the frozen document');\n}\nfunction object(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) reject();\n return value as Record<string, unknown>;\n}\nfunction matches(expected: unknown, actual: unknown): boolean {\n if (Array.isArray(expected))\n return (\n Array.isArray(actual) &&\n expected.length === actual.length &&\n expected.every((item, index) => matches(item, actual[index]))\n );\n if (expected !== null && typeof expected === 'object') {\n if (!actual || typeof actual !== 'object' || Array.isArray(actual))\n return false;\n const record = actual as Record<string, unknown>;\n return Object.entries(expected).every(\n ([key, value]) => value === undefined || matches(value, record[key]),\n );\n }\n return expected === actual;\n}\nfunction verify(\n input: InvoiceInput | CreditMemoInput,\n request: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest,\n prepared: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest,\n payload: Record<string, unknown>,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n if (\n !observed.externalId ||\n observed.externalId.trim() !== observed.externalId ||\n request.realmId !== observed.realmId ||\n request.environment !== observed.environment ||\n request.requestId !== prepared.requestId ||\n request.payloadHash !== prepared.payloadHash ||\n !input.currency ||\n !input.quickbooksMapping\n )\n reject();\n const raw = object(observed.record);\n if (\n raw.Id !== observed.externalId ||\n typeof raw.SyncToken !== 'string' ||\n !/^\\d+$/.test(raw.SyncToken) ||\n raw.TotalAmt !== input.totalAmount ||\n raw.status === 'Deleted' ||\n raw.TxnStatus === 'Voided' ||\n (raw.Deposit !== undefined && raw.Deposit !== 0) ||\n (raw.ExchangeRate !== undefined && raw.ExchangeRate !== 1)\n )\n reject();\n if (!Array.isArray(raw.Line)) reject();\n const lines: unknown[] = [];\n let subtotals = 0;\n for (const item of raw.Line) {\n const line = object(item);\n if (line.DetailType === 'SalesItemLineDetail') lines.push(line);\n else if (\n line.DetailType === 'SubTotalLineDetail' &&\n ++subtotals === 1 &&\n line.Amount === input.subtotal\n )\n continue;\n else reject();\n }\n const expectedTax = object(payload.TxnTaxDetail);\n const actualTax = object(raw.TxnTaxDetail);\n // A header total alone cannot prove which nonzero tax components were posted.\n if (input.taxAmount !== 0 && !Array.isArray(expectedTax.TaxLine)) reject();\n if (\n expectedTax.TaxLine === undefined &&\n actualTax.TaxLine !== undefined &&\n (!Array.isArray(actualTax.TaxLine) || actualTax.TaxLine.length !== 0)\n )\n reject();\n // Provider-added taxable bases are economics, not display metadata. Compare\n // them with the owning mapper's aggregate basis without changing create bytes.\n if (Array.isArray(actualTax.TaxLine)) {\n const bases = mapDocumentTaxReadback(input);\n for (const [index, line] of actualTax.TaxLine.entries()) {\n const detail = object(object(line).TaxLineDetail);\n if (\n detail.NetAmountTaxable !== undefined &&\n detail.NetAmountTaxable !== bases[index]?.TaxLineDetail.NetAmountTaxable\n )\n reject();\n }\n }\n if (!matches(payload, { ...raw, Line: lines })) reject();\n return {\n externalId: observed.externalId,\n syncToken: raw.SyncToken,\n payloadHash: prepared.payloadHash,\n };\n}\n\n/** Verify a fetched invoice; never guesses absence or makes a provider call. */\nexport function verifyQuickBooksInvoiceReadback(\n invoice: InvoiceInput,\n request: QuickBooksInvoiceRequest,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n const {\n externalId: _externalId,\n quickbooksRequest: _request,\n ...original\n } = invoice;\n const prepared = prepareQuickBooksInvoiceRequest(original, request);\n return verify(\n original,\n request,\n prepared,\n mapInvoiceToQBO(original),\n observed,\n );\n}\n\n/** Verify the credit document only; application to the original invoice remains separate. */\nexport function verifyQuickBooksCreditMemoReadback(\n credit: CreditMemoInput,\n request: QuickBooksCreditMemoRequest,\n observed: QuickBooksDocumentReadback,\n): VerifiedQuickBooksDocumentReadback {\n if (request.creditedInvoiceExternalId !== credit.creditedInvoiceExternalId)\n reject();\n const {\n externalId: _externalId,\n quickbooksCreditMemoRequest: _request,\n ...original\n } = credit;\n const prepared = prepareQuickBooksCreditMemoRequest(original, request);\n return verify(\n original,\n request,\n prepared,\n mapCreditMemoToQBO(original),\n observed,\n );\n}\n","import { createHash, timingSafeEqual } from 'node:crypto';\nimport { QuickBooksOAuthError } from '../../errors.js';\nimport type {\n QuickBooksOAuthClient,\n QuickBooksOAuthConnection,\n QuickBooksOAuthOptions,\n TokenSet,\n} from '../../types.js';\n\nconst ACCOUNTING_SCOPE = 'com.intuit.quickbooks.accounting';\n\n/** Create a public QuickBooks connection helper backed by Intuit's OAuth client. */\nexport async function createQuickBooksOAuthClient(\n options: QuickBooksOAuthOptions,\n): Promise<QuickBooksOAuthClient> {\n const redirect = validateOptions(options);\n const OAuthClient = (await import('intuit-oauth')).default;\n let client: InstanceType<typeof OAuthClient>;\n try {\n client = new OAuthClient({\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n environment: options.environment,\n redirectUri: options.redirectUri,\n });\n } catch {\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n }\n\n return {\n authorizationUrl({ state }) {\n validateOpaque(state, 'INVALID_STATE');\n try {\n return client.authorizeUri({ scope: [ACCOUNTING_SCOPE], state });\n } catch {\n throw new QuickBooksOAuthError('AUTHORIZATION_FAILED');\n }\n },\n\n async exchangeCallback({ callbackUrl, expectedState }) {\n validateOpaque(expectedState, 'INVALID_STATE');\n const callback = validateCallback(callbackUrl, redirect);\n const state = single(callback.searchParams, 'state', 'INVALID_STATE');\n validateOpaque(state, 'INVALID_STATE');\n if (!sameOpaqueValue(state, expectedState))\n throw new QuickBooksOAuthError('INVALID_STATE');\n const code = single(callback.searchParams, 'code', 'INVALID_CALLBACK');\n if (code.length > 4096)\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n const realmId = single(\n callback.searchParams,\n 'realmId',\n 'INVALID_CALLBACK',\n );\n if (realmId.length > 255)\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n for (const name of callback.searchParams.keys())\n if (!['code', 'realmId', 'state'].includes(name))\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n\n // Rebuild from the configured redirect and the three validated values.\n // intuit-oauth treats a callback `redirectUri` query as an override.\n const exchangeUrl = new URL(redirect);\n exchangeUrl.searchParams.set('code', code);\n exchangeUrl.searchParams.set('realmId', realmId);\n exchangeUrl.searchParams.set('state', state);\n\n try {\n const response = await client.createToken(exchangeUrl.toString());\n const token = response.getJson();\n const tokens = mapTokens(token);\n const grantedScopes = scopes(token.scope);\n return {\n realmId,\n tokens,\n ...(grantedScopes ? { grantedScopes } : {}),\n } satisfies QuickBooksOAuthConnection;\n } catch (error) {\n if (error instanceof QuickBooksOAuthError) throw error;\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n }\n },\n\n async revoke({ refreshToken }) {\n validateOpaque(refreshToken, 'INVALID_TOKEN');\n try {\n await client.revoke({ refresh_token: refreshToken });\n } catch {\n throw new QuickBooksOAuthError('REVOCATION_FAILED');\n }\n },\n };\n}\n\nfunction validateOptions(options: QuickBooksOAuthOptions): URL {\n if (\n !options ||\n !['sandbox', 'production'].includes(options.environment) ||\n !nonempty(options.clientId) ||\n !nonempty(options.clientSecret) ||\n !nonempty(options.redirectUri)\n )\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n\n try {\n const redirect = new URL(options.redirectUri);\n if (\n !['http:', 'https:'].includes(redirect.protocol) ||\n redirect.username ||\n redirect.password ||\n redirect.search ||\n redirect.hash\n )\n throw new Error('invalid redirect');\n return redirect;\n } catch {\n throw new QuickBooksOAuthError('INVALID_CONFIGURATION');\n }\n}\n\nfunction validateCallback(callbackUrl: string, redirect: URL): URL {\n try {\n const callback = new URL(callbackUrl);\n if (\n callback.protocol !== redirect.protocol ||\n callback.origin !== redirect.origin ||\n callback.pathname !== redirect.pathname ||\n callback.username ||\n callback.password ||\n callback.hash ||\n callback.searchParams.has('error')\n )\n throw new Error('invalid callback');\n return callback;\n } catch {\n throw new QuickBooksOAuthError('INVALID_CALLBACK');\n }\n}\n\nfunction single(\n params: URLSearchParams,\n name: string,\n code: 'INVALID_STATE' | 'INVALID_CALLBACK',\n): string {\n const values = params.getAll(name);\n if (values.length !== 1 || !nonempty(values[0]))\n throw new QuickBooksOAuthError(code);\n return values[0];\n}\n\nfunction validateOpaque(\n value: string,\n code: 'INVALID_STATE' | 'INVALID_TOKEN',\n): void {\n if (!nonempty(value) || value.length > 4096)\n throw new QuickBooksOAuthError(code);\n}\n\nfunction sameOpaqueValue(actual: string, expected: string): boolean {\n const digest = (value: string) => createHash('sha256').update(value).digest();\n return timingSafeEqual(digest(actual), digest(expected));\n}\n\nfunction mapTokens(token: {\n access_token?: unknown;\n refresh_token?: unknown;\n expires_in?: unknown;\n token_type?: unknown;\n}): TokenSet {\n if (\n !nonempty(token?.access_token) ||\n !nonempty(token.refresh_token) ||\n typeof token.expires_in !== 'number' ||\n !Number.isFinite(token.expires_in) ||\n token.expires_in <= 0 ||\n (token.token_type !== undefined && !nonempty(token.token_type))\n )\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n const expiresAt = new Date(Date.now() + token.expires_in * 1000);\n if (!Number.isFinite(expiresAt.getTime()))\n throw new QuickBooksOAuthError('EXCHANGE_FAILED');\n return {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt,\n ...(token.token_type ? { tokenType: token.token_type } : {}),\n };\n}\n\nfunction scopes(value: unknown): string[] | undefined {\n const values = Array.isArray(value)\n ? value\n : typeof value === 'string'\n ? value.split(/\\s+/)\n : [];\n const normalized = [\n ...new Set(values.filter((item): item is string => nonempty(item))),\n ];\n return normalized.length ? normalized : undefined;\n}\n\nfunction nonempty(value: unknown): value is string {\n return (\n typeof value === 'string' && value.length > 0 && value.trim() === value\n );\n}\n","/**\n * @happyvertical/accounting - Multi-provider accounting integration\n *\n * This package provides a unified interface for syncing and auditing\n * accounting data (AR/AP) with external providers like QuickBooks Online,\n * Stripe, PayPal, and Coinbase Commerce.\n *\n * Key components:\n * - getAccountingProvider() - Factory function for creating provider instances\n * - AccountingProvider - Unified interface for all providers\n * - Audit operations for reconciling local vs external data\n *\n * @example\n * ```typescript\n * import { getAccountingProvider } from '@happyvertical/accounting';\n *\n * const provider = await getAccountingProvider({\n * type: 'quickbooks',\n * clientId: 'xxx',\n * clientSecret: 'xxx',\n * realmId: 'xxx',\n * refreshToken: 'xxx'\n * });\n *\n * // Sync a customer\n * const result = await provider.customers.sync(customer);\n *\n * // Audit invoices\n * const report = await provider.audit.reconcileInvoices(localInvoices);\n * ```\n */\n\nimport { loadEnvConfig } from '@happyvertical/utils';\nimport type {\n AccountingOptions,\n AccountingProvider,\n CreditMemoOperations,\n QuickBooksOptions,\n StripeOptions,\n} from './types.js';\n\nexport type { QuickBooksOAuthErrorCode } from './errors.js';\nexport {\n QuickBooksOAuthError,\n QuickBooksWriteError,\n StripeApiError,\n} from './errors.js';\nexport {\n type QuickBooksDocumentReadback,\n type VerifiedQuickBooksDocumentReadback,\n verifyQuickBooksCreditMemoReadback,\n verifyQuickBooksInvoiceReadback,\n} from './providers/quickbooks/document-readback.js';\nexport {\n prepareQuickBooksCreditMemoRequest,\n prepareQuickBooksInvoiceRequest,\n} from './providers/quickbooks/invoice-request.js';\nexport { createQuickBooksOAuthClient } from './providers/quickbooks/oauth.js';\n// Re-export all types\nexport * from './types.js';\n\n/**\n * Schema for environment variable type conversion\n */\nconst accountingOptionsSchema: Record<string, 'string' | 'number' | 'boolean'> =\n {\n type: 'string',\n clientId: 'string',\n clientSecret: 'string',\n realmId: 'string',\n refreshToken: 'string',\n environment: 'string',\n secretKey: 'string',\n apiKey: 'string',\n timeout: 'number',\n maxRetries: 'number',\n };\n\n/**\n * Type guard for QuickBooks options\n */\nexport function isQuickBooksOptions(\n options: AccountingOptions,\n): options is QuickBooksOptions {\n return options.type === 'quickbooks';\n}\n\n/**\n * Type guard for Stripe options\n */\nexport function isStripeOptions(\n options: AccountingOptions,\n): options is StripeOptions {\n return options.type === 'stripe';\n}\n\n/**\n * Return the provider's credit-memo capability or fail explicitly before a\n * caller attempts a write against a provider that does not implement it.\n */\nexport function requireCreditMemoOperations(\n provider: Pick<AccountingProvider, 'type' | 'creditMemos'>,\n): CreditMemoOperations {\n if (!provider.creditMemos)\n throw new Error(\n `Accounting provider '${provider.type}' does not support credit memos`,\n );\n return provider.creditMemos;\n}\n\n/**\n * Create an accounting provider instance\n *\n * Factory function that creates a provider-specific implementation\n * of the AccountingProvider interface. Uses dynamic imports to\n * load only the provider code you need.\n *\n * @param userOptions - Provider configuration options\n * @returns AccountingProvider instance\n *\n * @example\n * ```typescript\n * // QuickBooks Online\n * const qbo = await getAccountingProvider({\n * type: 'quickbooks',\n * clientId: process.env.QBO_CLIENT_ID!,\n * clientSecret: process.env.QBO_CLIENT_SECRET!,\n * realmId: process.env.QBO_REALM_ID!,\n * refreshToken: process.env.QBO_REFRESH_TOKEN!,\n * environment: 'sandbox',\n * onTokenRefresh: async (tokens) => {\n * // Persist refreshed tokens\n * await saveTokens(tokens);\n * }\n * });\n *\n * // Stripe\n * const stripe = await getAccountingProvider({\n * type: 'stripe',\n * secretKey: process.env.STRIPE_SECRET_KEY!\n * });\n *\n * // Use env vars for configuration\n * const provider = await getAccountingProvider({ type: 'quickbooks' });\n * // Reads HAVE_ACCOUNTING_CLIENT_ID, HAVE_ACCOUNTING_REALM_ID, etc.\n * ```\n */\nexport async function getAccountingProvider(\n userOptions: Partial<AccountingOptions> & { type: AccountingOptions['type'] },\n): Promise<AccountingProvider> {\n // Load config from env vars, user options take precedence\n const options = loadEnvConfig<AccountingOptions>(userOptions, {\n packageName: 'accounting',\n schema: accountingOptionsSchema,\n });\n\n switch (options.type) {\n case 'quickbooks': {\n if (!isQuickBooksOptions(options)) {\n throw new Error('Invalid QuickBooks options');\n }\n const { QuickBooksProvider } = await import(\n './providers/quickbooks/index.js'\n );\n return new QuickBooksProvider(options);\n }\n\n case 'stripe': {\n if (!isStripeOptions(options)) {\n throw new Error('Invalid Stripe options');\n }\n const { StripeProvider } = await import('./providers/stripe/index.js');\n return new StripeProvider(options);\n }\n\n case 'paypal':\n throw new Error('PayPal provider not yet implemented');\n\n case 'coinbase':\n throw new Error('Coinbase provider not yet implemented');\n\n default:\n throw new Error(`Unknown provider type: ${(options as any).type}`);\n }\n}\n\n/** @internal */\nexport const PACKAGE_VERSION_INITIALIZED = true;\n\nexport type {\n QuickBooksNonCashApplicationInput,\n QuickBooksOrdinaryReceivableMapping,\n QuickBooksReceivableInput,\n QuickBooksReceivableMapping,\n QuickBooksReceivableOperationMapping,\n QuickBooksReceivableReadback,\n QuickBooksReceivableRequest,\n QuickBooksReceivableSource,\n QuickBooksReceivableTransferInput,\n QuickBooksReceivableTransferOperations,\n} from './providers/quickbooks/receivable-transfer.js';\nexport {\n prepareQuickBooksReceivableRequest,\n reconcileQuickBooksReceivableRecord,\n} from './providers/quickbooks/receivable-transfer.js';\n"],"mappings":"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"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { QuickBooksProvider } from './index.js';
|
|
2
|
-
import { type
|
|
2
|
+
import { type QuickBooksReceivableOperationMapping, type QuickBooksReceivableReadback, type QuickBooksReceivableRequest, type QuickBooksReceivableTransferOperations } from './receivable-transfer.js';
|
|
3
3
|
/** Each operation is separately durable in the host. This class does not pretend QBO supports a saga transaction. */
|
|
4
4
|
export declare class QuickBooksReceivableTransfers implements QuickBooksReceivableTransferOperations {
|
|
5
5
|
private provider;
|
|
6
6
|
constructor(provider: QuickBooksProvider);
|
|
7
7
|
private assertScope;
|
|
8
8
|
private entity;
|
|
9
|
-
verifyMapping(mapping:
|
|
9
|
+
verifyMapping(mapping: QuickBooksReceivableOperationMapping): Promise<{
|
|
10
10
|
mappingHash: string;
|
|
11
11
|
homeCurrency: string;
|
|
12
12
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receivable-operations.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/receivable-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,OAAO,
|
|
1
|
+
{"version":3,"file":"receivable-operations.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/receivable-operations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,OAAO,EAGL,KAAK,oCAAoC,EACzC,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAChC,KAAK,sCAAsC,EAI5C,MAAM,0BAA0B,CAAC;AAGlC,qHAAqH;AACrH,qBAAa,6BACX,YAAW,sCAAsC;IAErC,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,kBAAkB;IAChD,OAAO,CAAC,WAAW;YAUL,MAAM;IAYd,aAAa,CAAC,OAAO,EAAE,oCAAoC;;;;IAkDjE,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,KAAK;IAUb,OAAO,CAAC,gBAAgB;YA4BV,gBAAgB;YAsBhB,SAAS;YA8CT,SAAS;IAoBjB,OAAO,CACX,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,4BAA4B,CAAC;IAiClC,IAAI,CACR,OAAO,EAAE,2BAA2B,EACpC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,4BAA4B,CAAC;CAczC"}
|
|
@@ -12,6 +12,15 @@ export interface QuickBooksReceivableMapping {
|
|
|
12
12
|
retainedAssetAccountRef: string;
|
|
13
13
|
cashAccountRef: string | null;
|
|
14
14
|
}
|
|
15
|
+
/** Ordinary AR/cash authority; cannot authorize retention reclassification. */
|
|
16
|
+
export interface QuickBooksOrdinaryReceivableMapping extends Omit<QuickBooksReceivableMapping, 'retainedAssetAccountRef' | 'releaseDueDates'> {
|
|
17
|
+
kind: 'ordinary';
|
|
18
|
+
retainedAssetAccountRef?: never;
|
|
19
|
+
releaseDueDates?: never;
|
|
20
|
+
}
|
|
21
|
+
export type QuickBooksReceivableOperationMapping = QuickBooksReceivableMapping | QuickBooksOrdinaryReceivableMapping;
|
|
22
|
+
/** @internal */
|
|
23
|
+
export declare function isOrdinaryReceivableMapping(mapping: QuickBooksReceivableOperationMapping): mapping is QuickBooksOrdinaryReceivableMapping;
|
|
15
24
|
export interface QuickBooksReceivableSource {
|
|
16
25
|
type: 'Invoice' | 'CreditMemo' | 'JournalEntry';
|
|
17
26
|
id: string;
|
|
@@ -20,7 +29,7 @@ export interface QuickBooksReceivableSource {
|
|
|
20
29
|
evidenceRef: string;
|
|
21
30
|
}
|
|
22
31
|
interface TransferEvidence {
|
|
23
|
-
mapping:
|
|
32
|
+
mapping: QuickBooksReceivableOperationMapping;
|
|
24
33
|
source: QuickBooksReceivableSource;
|
|
25
34
|
requestId: string;
|
|
26
35
|
effectiveOn: string;
|
|
@@ -70,7 +79,7 @@ export interface QuickBooksReceivableReadback {
|
|
|
70
79
|
payloadHash: string;
|
|
71
80
|
}
|
|
72
81
|
export interface QuickBooksReceivableTransferOperations {
|
|
73
|
-
verifyMapping(mapping:
|
|
82
|
+
verifyMapping(mapping: QuickBooksReceivableOperationMapping): Promise<{
|
|
74
83
|
mappingHash: string;
|
|
75
84
|
homeCurrency: string;
|
|
76
85
|
}>;
|
|
@@ -78,7 +87,7 @@ export interface QuickBooksReceivableTransferOperations {
|
|
|
78
87
|
/** Reconcile a known remote ID against the complete prepared contract, not just its total. */
|
|
79
88
|
read(request: QuickBooksReceivableRequest, externalId: string): Promise<QuickBooksReceivableReadback>;
|
|
80
89
|
}
|
|
81
|
-
export declare function validateQuickBooksReceivableMapping(mapping:
|
|
90
|
+
export declare function validateQuickBooksReceivableMapping(mapping: QuickBooksReceivableOperationMapping): void;
|
|
82
91
|
export declare function mapQuickBooksReceivableRequest(input: QuickBooksReceivableInput): Record<string, unknown>;
|
|
83
92
|
/** Pure preparation. Persist before sending; the hash does not prove a remote write occurred once. */
|
|
84
93
|
export declare function prepareQuickBooksReceivableRequest(input: QuickBooksReceivableInput): QuickBooksReceivableRequest;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receivable-transfer.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/receivable-transfer.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,SAAS,GAAG,YAAY,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,SAAS,CAAC;IAC3B,SAAS,EAAE,mBAAmB,CAAC;IAC/B,eAAe,EAAE,cAAc,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,uBAAuB,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AACD,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,SAAS,GAAG,YAAY,GAAG,cAAc,CAAC;IAChD,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,WAAW,EAAE,MAAM,CAAC;CACrB;AACD,UAAU,gBAAgB;IACxB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"receivable-transfer.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/receivable-transfer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/accounting",
|
|
3
|
-
"version": "0.105.
|
|
3
|
+
"version": "0.105.2",
|
|
4
4
|
"description": "Multi-provider accounting integration for AR/AP sync and audit with QuickBooks, Stripe, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"homepage": "https://github.com/happyvertical/sdk/tree/main/packages/accounting#readme",
|
|
37
37
|
"license": "MIT",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@happyvertical/utils": "0.105.
|
|
39
|
+
"@happyvertical/utils": "0.105.2",
|
|
40
40
|
"intuit-oauth": "^4.2.3"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"quickbooks-Bh9k87sj.js","names":[],"sources":["../../src/providers/quickbooks/receivable-operations.ts","../../src/providers/quickbooks/index.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { QuickBooksWriteError } from '../../errors.js';\nimport type { QuickBooksProvider } from './index.js';\nimport { currencyMinorUnitFactor, isCurrencyMinorUnit } from './line-amount.js';\nimport {\n mapQuickBooksReceivableRequest,\n type QuickBooksReceivableMapping,\n type QuickBooksReceivableReadback,\n type QuickBooksReceivableRequest,\n type QuickBooksReceivableTransferOperations,\n reconcileQuickBooksReceivableRecord,\n validateQuickBooksReceivableMapping,\n validateQuickBooksReceivableRequest,\n} from './receivable-transfer.js';\n\ntype ProviderRecord = Record<string, any>;\n/** Each operation is separately durable in the host. This class does not pretend QBO supports a saga transaction. */\nexport class QuickBooksReceivableTransfers\n implements QuickBooksReceivableTransferOperations\n{\n constructor(private provider: QuickBooksProvider) {}\n private assertScope(mapping: QuickBooksReceivableMapping) {\n validateQuickBooksReceivableMapping(mapping);\n if (\n mapping.realmId !== this.provider.realmId ||\n mapping.environment !== this.provider.environment\n )\n throw new Error(\n 'Receivable mapping belongs to another provider realm or environment',\n );\n }\n private async entity(type: string, id: string): Promise<ProviderRecord> {\n if (!/^[A-Za-z0-9._-]{1,100}$/.test(id))\n throw new Error('Unsupported provider entity reference');\n const result = await this.provider.request<Record<string, ProviderRecord>>(\n 'GET',\n `${type.toLowerCase()}/${encodeURIComponent(id)}`,\n );\n const value = result[type];\n if (!value || value.Id !== id)\n throw new Error(`Provider ${type} identity differs`);\n return value;\n }\n async verifyMapping(mapping: QuickBooksReceivableMapping) {\n this.assertScope(mapping);\n const prefs = await this.provider.request<{ Preferences?: ProviderRecord }>(\n 'GET',\n 'preferences',\n );\n const currencies = prefs.Preferences?.CurrencyPrefs;\n if (\n currencies?.HomeCurrency?.value !== mapping.currency ||\n typeof currencies?.MultiCurrencyEnabled !== 'boolean'\n )\n throw new Error(\n 'Receivable transfers require verified home currency; foreign exchange is unsupported',\n );\n const customer = await this.entity('Customer', mapping.customerRef);\n if (\n customer.Active !== true ||\n (customer.CurrencyRef?.value ??\n (currencies.MultiCurrencyEnabled === false\n ? mapping.currency\n : undefined)) !== mapping.currency\n )\n throw new Error(\n 'Receivable customer must be active and use the verified home currency',\n );\n for (const [ref, type] of [\n [mapping.receivablesAccountRef, 'Accounts Receivable'],\n [mapping.retainedAssetAccountRef, 'Other Current Asset'],\n ...(mapping.cashAccountRef ? [[mapping.cashAccountRef, 'Bank']] : []),\n ]) {\n const account = await this.entity('Account', ref);\n if (\n account.Active !== true ||\n account.AccountType !== type ||\n (account.CurrencyRef !== undefined &&\n account.CurrencyRef?.value !== mapping.currency)\n )\n throw new Error(\n 'Receivable account type, activity or currency differs from the reviewed mapping',\n );\n }\n return {\n mappingHash: createHash('sha256')\n .update(JSON.stringify(mapping))\n .digest('hex'),\n homeCurrency: mapping.currency,\n };\n }\n private currency(\n record: ProviderRecord,\n mapping: QuickBooksReceivableMapping,\n ) {\n if (record.CurrencyRef?.value !== mapping.currency)\n throw new Error('Provider transaction currency differs');\n }\n private minor(amount: unknown, currency: string): number {\n if (typeof amount !== 'number' || !isCurrencyMinorUnit(amount, currency))\n throw new Error(\n 'Provider amount is missing or outside the exact currency grid',\n );\n const value = Math.round(amount * currencyMinorUnitFactor(currency)!);\n if (!Number.isSafeInteger(value) || value < 0)\n throw new Error('Provider amount is outside supported safe minor units');\n return value;\n }\n private journalDirection(\n record: ProviderRecord,\n mapping: QuickBooksReceivableMapping,\n ): { kind: 'debit' | 'credit'; amountMinor: number } {\n this.currency(record, mapping);\n if (!Array.isArray(record.Line))\n throw new Error('Provider journal lines are missing');\n const ar = record.Line.filter(\n (line: ProviderRecord) =>\n line.JournalEntryLineDetail?.AccountRef?.value ===\n mapping.receivablesAccountRef,\n );\n if (ar.length !== 1)\n throw new Error(\n 'Provider receivable journal needs exactly one reviewed AR line',\n );\n const detail = ar[0].JournalEntryLineDetail;\n if (\n detail.Entity?.Type !== 'Customer' ||\n detail.Entity?.EntityRef?.value !== mapping.customerRef ||\n !['Debit', 'Credit'].includes(detail.PostingType)\n )\n throw new Error('Provider journal customer or AR direction differs');\n return {\n kind: detail.PostingType === 'Debit' ? 'debit' : 'credit',\n amountMinor: this.minor(ar[0].Amount, mapping.currency),\n };\n }\n private async customerPayments(\n mapping: QuickBooksReceivableMapping,\n ): Promise<ProviderRecord[]> {\n const rows: ProviderRecord[] = [];\n // Complete pagination is mandatory for capacity; no ordinary list default cap may truncate it.\n for (let page = 0; page < 10000; page++) {\n const query = `SELECT * FROM Payment WHERE CustomerRef = '${mapping.customerRef}' STARTPOSITION ${page * 100 + 1} MAXRESULTS 100`;\n const result = await this.provider.request<{\n QueryResponse?: { Payment?: ProviderRecord[] };\n }>('GET', `query?query=${encodeURIComponent(query)}`);\n if (!result.QueryResponse)\n throw new Error('Provider payment query omitted its result');\n const batch = result.QueryResponse.Payment ?? [];\n if (!Array.isArray(batch))\n throw new Error('Provider payment query is malformed');\n rows.push(...batch);\n if (batch.length < 100) return rows;\n }\n throw new Error(\n 'Complete provider payment history is required before receivable application',\n );\n }\n private async available(\n ref: { type: string; id: string },\n mapping: QuickBooksReceivableMapping,\n direction: 'debit' | 'credit',\n ) {\n const record = await this.entity(ref.type, ref.id);\n this.currency(record, mapping);\n if (ref.type !== 'JournalEntry') {\n if (record.CustomerRef?.value !== mapping.customerRef)\n throw new Error('Application transaction belongs to another customer');\n return this.minor(\n ref.type === 'Invoice' ? record.Balance : record.RemainingCredit,\n mapping.currency,\n );\n }\n const journal = this.journalDirection(record, mapping);\n if (journal.kind !== direction)\n throw new Error('Application journal has the wrong receivable direction');\n let used = 0n;\n for (const payment of await this.customerPayments(mapping)) {\n if (payment.CustomerRef?.value !== mapping.customerRef)\n throw new Error('Payment query crossed customer authority');\n for (const line of payment.Line ?? []) {\n const links = line.LinkedTxn ?? [];\n if (\n links.some(\n (link: ProviderRecord) =>\n link.TxnType === 'JournalEntry' && link.TxnId === ref.id,\n )\n ) {\n if (links.length !== 1)\n throw new Error(\n 'Ambiguous multi-transaction payment allocation requires reconciliation',\n );\n this.currency(payment, mapping);\n used += BigInt(this.minor(line.Amount, mapping.currency));\n }\n }\n }\n const available = BigInt(journal.amountMinor) - used;\n if (available < 0n)\n throw new Error(\n 'Provider journal is overapplied and requires reconciliation',\n );\n return Number(available);\n }\n private async preflight(request: QuickBooksReceivableRequest) {\n await this.verifyMapping(request.input.mapping);\n const input = request.input,\n source = await this.entity(input.source.type, input.source.id);\n this.currency(source, input.mapping);\n if (input.source.type === 'JournalEntry')\n this.journalDirection(source, input.mapping);\n else if (source.CustomerRef?.value !== input.mapping.customerRef)\n throw new Error(\n 'Source provider transaction belongs to another customer',\n );\n if (input.kind === 'application') {\n const debit = await this.available(input.debit, input.mapping, 'debit'),\n credit = await this.available(input.credit, input.mapping, 'credit');\n if (input.amountMinor > debit || input.amountMinor > credit)\n throw new Error(\n 'Noncash application exceeds current source debit or credit capacity',\n );\n }\n }\n async execute(\n request: QuickBooksReceivableRequest,\n ): Promise<QuickBooksReceivableReadback> {\n // Reconstruct and retain exact bytes before any asynchronous metadata lookup.\n const retained = structuredClone(request);\n validateQuickBooksReceivableRequest(\n retained,\n this.provider.realmId,\n this.provider.environment,\n );\n const body = mapQuickBooksReceivableRequest(retained.input);\n await this.preflight(retained);\n const response = await this.provider.request<\n Record<string, ProviderRecord>\n >('POST', retained.endpoint, body, retained);\n const type =\n retained.endpoint === 'journalentry' ? 'JournalEntry' : 'Payment';\n // A malformed success is unresolved, never a confirmed operation.\n try {\n return reconcileQuickBooksReceivableRecord(retained, response[type]);\n } catch (cause) {\n const externalId = response?.[type]?.Id;\n throw new QuickBooksWriteError({\n outcome: 'unknown',\n realmId: retained.realmId,\n environment: retained.environment,\n endpoint: retained.endpoint,\n requestId: retained.requestId,\n payloadHash: retained.payloadHash,\n externalId:\n typeof externalId === 'string' && externalId ? externalId : undefined,\n cause,\n });\n }\n }\n async read(\n request: QuickBooksReceivableRequest,\n externalId: string,\n ): Promise<QuickBooksReceivableReadback> {\n const retained = structuredClone(request);\n validateQuickBooksReceivableRequest(\n retained,\n this.provider.realmId,\n this.provider.environment,\n );\n const type =\n retained.endpoint === 'journalentry' ? 'JournalEntry' : 'Payment';\n return reconcileQuickBooksReceivableRecord(\n retained,\n await this.entity(type, externalId),\n );\n }\n}\n","import { QuickBooksReceivableTransfers } from './receivable-operations.js';\nimport {\n type QuickBooksReceivableRequest,\n validateQuickBooksReceivableRequest,\n} from './receivable-transfer.js';\n/**\n * QuickBooks Online Provider\n *\n * Implements the AccountingProvider interface for QuickBooks Online.\n * Uses the Intuit OAuth2 library for authentication and the QBO API for operations.\n */\n\n/// <reference path=\"../../intuit-oauth.d.ts\" />\n\nimport { createHmac } from 'node:crypto';\nimport { QuickBooksWriteError } from '../../errors.js';\nimport type {\n AccountingProvider,\n Address,\n AuditDiscrepancy,\n AuditMatch,\n AuditOperations,\n AuditReport,\n BillInput,\n BillOperations,\n CreditMemoInput,\n CreditMemoOperations,\n CustomerInput,\n CustomerOperations,\n DateRange,\n ExternalBill,\n ExternalCustomer,\n ExternalInvoice,\n ExternalPayment,\n ExternalRecord,\n ExternalVendor,\n FieldDiff,\n InvoiceInput,\n InvoiceOperations,\n ListOptions,\n PaymentInput,\n PaymentOperations,\n QuickBooksCreditMemoRequest,\n QuickBooksInvoiceRequest,\n QuickBooksOptions,\n SyncResult,\n TokenSet,\n VendorInput,\n VendorOperations,\n WebhookEvent,\n WebhookOperations,\n} from '../../types.js';\nimport {\n mapCreditMemoToQBO,\n mapInvoiceToQBO,\n validateQuickBooksCreditMemoRequest,\n validateQuickBooksInvoiceRequest,\n} from './invoice-request.js';\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Format a Date to YYYY-MM-DD in local timezone (not UTC)\n * This prevents timezone conversion issues where dates shift by a day\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\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Compare two values for equality (handles dates, objects, etc.)\n */\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a instanceof Date && b instanceof Date) {\n return a.getTime() === b.getTime();\n }\n if (typeof a === 'number' && typeof b === 'number') {\n // Allow for floating point precision issues\n return Math.abs(a - b) < 0.01;\n }\n return false;\n}\n\n// =============================================================================\n// QuickBooks Provider\n// =============================================================================\n\n/**\n * QuickBooks Online accounting provider\n */\nexport class QuickBooksProvider implements AccountingProvider {\n readonly type = 'quickbooks' as const;\n readonly receivableTransfers: QuickBooksReceivableTransfers;\n\n private options: QuickBooksOptions;\n private accessToken: string | null = null;\n private tokenExpiresAt: Date | null = null;\n\n readonly customers: CustomerOperations;\n readonly invoices: InvoiceOperations;\n readonly creditMemos: CreditMemoOperations;\n readonly vendors: VendorOperations;\n readonly bills: BillOperations;\n readonly payments: PaymentOperations;\n readonly audit: AuditOperations;\n readonly webhooks: WebhookOperations;\n\n constructor(options: QuickBooksOptions) {\n this.options = {\n timeout: 30000,\n maxRetries: 3,\n ...options,\n };\n\n this.receivableTransfers = new QuickBooksReceivableTransfers(this);\n // Initialize operation handlers\n this.customers = new QuickBooksCustomerOperations(this);\n this.invoices = new QuickBooksInvoiceOperations(this);\n this.creditMemos = new QuickBooksCreditMemoOperations(this);\n this.vendors = new QuickBooksVendorOperations(this);\n this.bills = new QuickBooksBillOperations(this);\n this.payments = new QuickBooksPaymentOperations(this);\n this.audit = new QuickBooksAuditOperations(this);\n this.webhooks = new QuickBooksWebhookOperations(this.options);\n }\n\n /**\n * Get the QBO API base URL\n */\n get baseUrl(): string {\n return this.options.environment === 'production'\n ? 'https://quickbooks.api.intuit.com'\n : 'https://sandbox-quickbooks.api.intuit.com';\n }\n\n /**\n * Get the company/realm ID\n */\n get environment(): 'sandbox' | 'production' {\n return this.options.environment === 'production' ? 'production' : 'sandbox';\n }\n\n get realmId(): string {\n return this.options.realmId;\n }\n\n /**\n * Ensure we have a valid access token, refreshing if needed\n */\n async ensureAccessToken(): Promise<string> {\n // Check if current token is still valid (with 5 min buffer)\n if (this.accessToken && this.tokenExpiresAt) {\n const bufferMs = 5 * 60 * 1000;\n if (new Date().getTime() < this.tokenExpiresAt.getTime() - bufferMs) {\n return this.accessToken;\n }\n }\n\n // Refresh the token\n const tokens = await this.refreshAccessToken();\n this.accessToken = tokens.accessToken;\n this.tokenExpiresAt = tokens.expiresAt;\n\n // Update stored refresh token so subsequent refreshes use the new token\n this.options.refreshToken = tokens.refreshToken;\n\n // Notify callback if provided\n if (this.options.onTokenRefresh) {\n await this.options.onTokenRefresh(tokens);\n }\n\n return this.accessToken;\n }\n\n /**\n * Refresh the OAuth access token\n */\n private async refreshAccessToken(): Promise<TokenSet> {\n // Import intuit-oauth dynamically\n const OAuthClient = (await import('intuit-oauth')).default;\n\n const redirectUri =\n this.options.redirectUri ||\n 'https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl';\n\n const oauthClient = new OAuthClient({\n clientId: this.options.clientId,\n clientSecret: this.options.clientSecret,\n environment:\n this.options.environment === 'production' ? 'production' : 'sandbox',\n redirectUri,\n });\n\n oauthClient.setToken({\n refresh_token: this.options.refreshToken,\n access_token: this.accessToken || '',\n });\n\n const response = await oauthClient.refresh();\n const token = response.getJson();\n\n return {\n accessToken: token.access_token,\n refreshToken: token.refresh_token,\n expiresAt: new Date(Date.now() + token.expires_in * 1000),\n tokenType: token.token_type,\n };\n }\n\n /**\n * Make an authenticated request to the QBO API with timeout and retry support\n */\n async request<T>(\n method: 'GET' | 'POST' | 'DELETE',\n endpoint: string,\n body?: unknown,\n createRequest?:\n | QuickBooksInvoiceRequest\n | QuickBooksCreditMemoRequest\n | QuickBooksReceivableRequest,\n ): Promise<T> {\n // Freeze identity and bytes before any asynchronous work.\n const serializedBody =\n body === undefined ? undefined : JSON.stringify(body);\n const realmId = this.realmId;\n const environment =\n this.options.environment === 'production' ? 'production' : 'sandbox';\n if (createRequest) {\n if (\n method !== 'POST' ||\n !['invoice', 'creditmemo', 'journalentry', 'payment'].includes(endpoint)\n ) {\n throw new Error(\n 'QuickBooks request identity is only supported for prepared invoice, credit memo, journal or noncash application creation',\n );\n }\n if (endpoint === 'journalentry' || endpoint === 'payment') {\n if (\n !('endpoint' in createRequest) ||\n createRequest.endpoint !== endpoint\n )\n throw new Error('Receivable endpoint differs from request identity');\n validateQuickBooksReceivableRequest(\n createRequest,\n realmId,\n environment,\n serializedBody,\n );\n } else if (endpoint === 'invoice')\n validateQuickBooksInvoiceRequest(\n createRequest as QuickBooksInvoiceRequest,\n realmId,\n environment,\n serializedBody,\n );\n else\n validateQuickBooksCreditMemoRequest(\n createRequest as QuickBooksCreditMemoRequest,\n realmId,\n environment,\n serializedBody,\n );\n }\n const requestId = createRequest?.requestId;\n const payloadHash = createRequest?.payloadHash;\n const url = new URL(`${this.baseUrl}/v3/company/${realmId}/${endpoint}`);\n if (requestId) url.searchParams.set('requestid', requestId);\n const timeout = this.options.timeout ?? 30000;\n const maxRetries =\n method === 'GET' || requestId ? (this.options.maxRetries ?? 3) : 0;\n const responseEntity = [\n 'Customer',\n 'Vendor',\n 'Bill',\n 'Invoice',\n 'CreditMemo',\n 'Payment',\n 'JournalEntry',\n ].find((entity) => entity.toLowerCase() === endpoint.split(/[/?]/, 1)[0]);\n const accessToken = await this.ensureAccessToken();\n // A persisted identity may have been sent by an earlier worker. Without a\n // durable attempt history, even its first observed 4xx cannot prove that\n // the logical write was never accepted. Fail closed across process retries.\n let uncertain = requestId !== undefined;\n\n for (let attempt = 0; ; attempt++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n let status: number | undefined;\n let failure: unknown;\n try {\n const response = await fetch(url.toString(), {\n method,\n headers: {\n Authorization: `Bearer ${accessToken}`,\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: serializedBody,\n signal: controller.signal,\n });\n status = response.status;\n if (!response.ok) {\n throw new Error(\n `QBO API error (${status}): ${await response.text()}`,\n );\n }\n const result = await response.json();\n // Every supported write must return a usable remote identity. Validate\n // inside this boundary so malformed successes cannot escape reconciliation.\n if (\n method !== 'GET' &&\n responseEntity &&\n (typeof result?.[responseEntity]?.Id !== 'string' ||\n !result[responseEntity].Id.trim())\n ) {\n throw new Error(`QBO response is missing ${responseEntity}.Id`);\n }\n return result as T;\n } catch (error) {\n failure = error;\n uncertain ||=\n status === undefined ||\n status >= 500 ||\n (status >= 200 && status < 300);\n } finally {\n clearTimeout(timeoutId);\n }\n const retryable =\n status === undefined ||\n status === 429 ||\n status >= 500 ||\n (status >= 200 && status < 300);\n if (!retryable || attempt >= maxRetries) {\n if (method !== 'GET') {\n throw new QuickBooksWriteError({\n realmId,\n environment,\n endpoint,\n requestId,\n status,\n payloadHash,\n outcome: uncertain ? 'unknown' : 'rejected',\n cause: failure,\n });\n }\n throw failure;\n }\n await sleep(2 ** attempt * 1000);\n }\n }\n\n /**\n * Execute a QBO query with pagination support\n */\n async queryAll<T>(\n entity: string,\n whereClause?: string,\n maxResults = 1000,\n ): Promise<T[]> {\n const results: T[] = [];\n let startPosition = 1;\n const pageSize = 100; // QBO max is 1000, but smaller pages are safer\n\n while (results.length < maxResults) {\n let query = `SELECT * FROM ${entity}`;\n if (whereClause) {\n query += ` WHERE ${whereClause}`;\n }\n query += ` MAXRESULTS ${pageSize} STARTPOSITION ${startPosition}`;\n\n const response = await this.request<{\n QueryResponse: Record<string, T[] | undefined>;\n }>('GET', `query?query=${encodeURIComponent(query)}`);\n\n const items = response.QueryResponse[entity] || [];\n results.push(...items);\n\n // If we got fewer than pageSize, we've reached the end\n if (items.length < pageSize) {\n break;\n }\n\n startPosition += pageSize;\n }\n\n return results;\n }\n}\n\n// =============================================================================\n// Customer Operations\n// =============================================================================\n\nclass QuickBooksCustomerOperations implements CustomerOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(customer: CustomerInput): Promise<SyncResult> {\n const qboCustomer = mapCustomerToQBO(customer);\n\n const response = await this.provider.request<{ Customer: QBOCustomer }>(\n 'POST',\n 'customer',\n qboCustomer,\n );\n\n return {\n action: 'created',\n externalId: response.Customer.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalCustomer> {\n const response = await this.provider.request<{ Customer: QBOCustomer }>(\n 'GET',\n `customer/${externalId}`,\n );\n\n return mapQBOToCustomer(response.Customer);\n }\n\n async list(options?: ListOptions): Promise<ExternalCustomer[]> {\n const limit = options?.limit || 1000;\n const customers = await this.provider.queryAll<QBOCustomer>(\n 'Customer',\n undefined,\n limit,\n );\n return customers.map(mapQBOToCustomer);\n }\n\n async sync(customer: CustomerInput): Promise<SyncResult> {\n if (customer.externalId) {\n // Update existing\n const existing = await this.provider.request<{ Customer: QBOCustomer }>(\n 'GET',\n `customer/${customer.externalId}`,\n );\n\n const qboCustomer: QBOCustomerUpdate = {\n ...mapCustomerToQBO(customer),\n Id: customer.externalId,\n SyncToken: existing.Customer.SyncToken,\n };\n\n await this.provider.request('POST', 'customer', qboCustomer);\n\n return {\n action: 'updated',\n externalId: customer.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(customer);\n }\n}\n\n// =============================================================================\n// Invoice Operations\n// =============================================================================\n\nclass QuickBooksInvoiceOperations implements InvoiceOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(invoice: InvoiceInput): Promise<SyncResult> {\n if (invoice.externalId && invoice.quickbooksRequest)\n throw new Error(\n 'QuickBooks invoice request identity cannot be used for updates',\n );\n const qboInvoice = mapInvoiceToQBO(invoice);\n\n const response = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'POST',\n 'invoice',\n qboInvoice,\n invoice.quickbooksRequest,\n );\n\n return {\n action: 'created',\n externalId: response.Invoice.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalInvoice> {\n const response = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${externalId}`,\n );\n\n return mapQBOToInvoice(response.Invoice);\n }\n\n async list(options?: ListOptions): Promise<ExternalInvoice[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const invoices = await this.provider.queryAll<QBOInvoice>(\n 'Invoice',\n whereClause,\n limit,\n );\n return invoices.map(mapQBOToInvoice);\n }\n\n async sync(invoice: InvoiceInput): Promise<SyncResult> {\n if (invoice.externalId) {\n if (invoice.quickbooksRequest)\n throw new Error(\n 'QuickBooks invoice request identity cannot be used for updates',\n );\n const existing = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${invoice.externalId}`,\n );\n\n const qboInvoice: QBOInvoiceUpdate = {\n ...mapInvoiceToQBO(invoice),\n Id: invoice.externalId,\n SyncToken: existing.Invoice.SyncToken,\n };\n\n await this.provider.request('POST', 'invoice', qboInvoice);\n\n return {\n action: 'updated',\n externalId: invoice.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(invoice);\n }\n\n async send(externalId: string): Promise<void> {\n await this.provider.request('POST', `invoice/${externalId}/send`);\n }\n\n async void(externalId: string): Promise<void> {\n const existing = await this.provider.request<{ Invoice: QBOInvoice }>(\n 'GET',\n `invoice/${externalId}`,\n );\n\n await this.provider.request('POST', 'invoice', {\n Id: externalId,\n SyncToken: existing.Invoice.SyncToken,\n sparse: true,\n // QBO doesn't have a Void field - you delete the invoice instead\n // or create a credit memo. For now, we'll use sparse update to mark private note\n PrivateNote: 'VOIDED',\n });\n }\n}\n\n// =============================================================================\n// Credit memo operations\n// =============================================================================\n\nclass QuickBooksCreditMemoOperations implements CreditMemoOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async pull(externalId: string): Promise<ExternalRecord> {\n if (\n !externalId ||\n externalId.trim() !== externalId ||\n externalId.length > 500\n )\n throw new Error(\n 'QuickBooks credit memo readback requires an exact external ID',\n );\n const response = await this.provider.request<{\n CreditMemo: Record<string, unknown>;\n }>('GET', `creditmemo/${encodeURIComponent(externalId)}`);\n if (!response.CreditMemo || response.CreditMemo.Id !== externalId)\n throw new Error('QuickBooks credit memo readback identity differs');\n return {\n provider: 'quickbooks',\n externalId,\n syncedAt: new Date(),\n raw: response.CreditMemo,\n };\n }\n\n async push(creditMemo: CreditMemoInput): Promise<SyncResult> {\n if (creditMemo.externalId && creditMemo.quickbooksCreditMemoRequest)\n throw new Error(\n 'QuickBooks credit memo request identity cannot be used for updates',\n );\n const mapped = mapCreditMemoToQBO(creditMemo);\n if (\n creditMemo.quickbooksCreditMemoRequest &&\n creditMemo.quickbooksCreditMemoRequest.creditedInvoiceExternalId !==\n creditMemo.creditedInvoiceExternalId\n )\n throw new Error(\n 'QuickBooks credit memo request linkage mismatch; reconcile the original request',\n );\n const response = await this.provider.request<{\n CreditMemo: { Id: string };\n }>('POST', 'creditmemo', mapped, creditMemo.quickbooksCreditMemoRequest);\n return {\n action: 'created',\n externalId: response.CreditMemo.Id,\n syncedAt: new Date(),\n };\n }\n\n async sync(creditMemo: CreditMemoInput): Promise<SyncResult> {\n if (!creditMemo.externalId) return this.push(creditMemo);\n if (creditMemo.quickbooksCreditMemoRequest)\n throw new Error(\n 'QuickBooks credit memo request identity cannot be used for updates',\n );\n // Refuse malformed frozen snapshots before authenticating or contacting QBO.\n const mapped = mapCreditMemoToQBO(creditMemo);\n const existing = await this.provider.request<{\n CreditMemo: { SyncToken: string };\n }>('GET', `creditmemo/${creditMemo.externalId}`);\n await this.provider.request('POST', 'creditmemo', {\n ...mapped,\n Id: creditMemo.externalId,\n SyncToken: existing.CreditMemo.SyncToken,\n });\n return {\n action: 'updated',\n externalId: creditMemo.externalId,\n syncedAt: new Date(),\n };\n }\n}\n\n// =============================================================================\n// Vendor Operations\n// =============================================================================\n\nclass QuickBooksVendorOperations implements VendorOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(vendor: VendorInput): Promise<SyncResult> {\n const qboVendor = mapVendorToQBO(vendor);\n\n const response = await this.provider.request<{ Vendor: QBOVendor }>(\n 'POST',\n 'vendor',\n qboVendor,\n );\n\n return {\n action: 'created',\n externalId: response.Vendor.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalVendor> {\n const response = await this.provider.request<{ Vendor: QBOVendor }>(\n 'GET',\n `vendor/${externalId}`,\n );\n\n return mapQBOToVendor(response.Vendor);\n }\n\n async list(options?: ListOptions): Promise<ExternalVendor[]> {\n const limit = options?.limit || 1000;\n const vendors = await this.provider.queryAll<QBOVendor>(\n 'Vendor',\n undefined,\n limit,\n );\n return vendors.map(mapQBOToVendor);\n }\n\n async sync(vendor: VendorInput): Promise<SyncResult> {\n if (vendor.externalId) {\n const existing = await this.provider.request<{ Vendor: QBOVendor }>(\n 'GET',\n `vendor/${vendor.externalId}`,\n );\n\n const qboVendor: QBOVendorUpdate = {\n ...mapVendorToQBO(vendor),\n Id: vendor.externalId,\n SyncToken: existing.Vendor.SyncToken,\n };\n\n await this.provider.request('POST', 'vendor', qboVendor);\n\n return {\n action: 'updated',\n externalId: vendor.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(vendor);\n }\n}\n\n// =============================================================================\n// Bill Operations\n// =============================================================================\n\nclass QuickBooksBillOperations implements BillOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async push(bill: BillInput): Promise<SyncResult> {\n const qboBill = mapBillToQBO(bill);\n\n const response = await this.provider.request<{ Bill: QBOBill }>(\n 'POST',\n 'bill',\n qboBill,\n );\n\n return {\n action: 'created',\n externalId: response.Bill.Id,\n syncedAt: new Date(),\n };\n }\n\n async pull(externalId: string): Promise<ExternalBill> {\n const response = await this.provider.request<{ Bill: QBOBill }>(\n 'GET',\n `bill/${externalId}`,\n );\n\n return mapQBOToBill(response.Bill);\n }\n\n async list(options?: ListOptions): Promise<ExternalBill[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const bills = await this.provider.queryAll<QBOBill>(\n 'Bill',\n whereClause,\n limit,\n );\n return bills.map(mapQBOToBill);\n }\n\n async sync(bill: BillInput): Promise<SyncResult> {\n if (bill.externalId) {\n const existing = await this.provider.request<{ Bill: QBOBill }>(\n 'GET',\n `bill/${bill.externalId}`,\n );\n\n const qboBill: QBOBillUpdate = {\n ...mapBillToQBO(bill),\n Id: bill.externalId,\n SyncToken: existing.Bill.SyncToken,\n };\n\n await this.provider.request('POST', 'bill', qboBill);\n\n return {\n action: 'updated',\n externalId: bill.externalId,\n syncedAt: new Date(),\n };\n }\n\n return this.push(bill);\n }\n}\n\n// =============================================================================\n// Payment Operations\n// =============================================================================\n\nclass QuickBooksPaymentOperations implements PaymentOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async pull(externalId: string): Promise<ExternalPayment> {\n const response = await this.provider.request<{ Payment: QBOPayment }>(\n 'GET',\n `payment/${externalId}`,\n );\n\n return mapQBOToPayment(response.Payment);\n }\n\n async list(options?: ListOptions): Promise<ExternalPayment[]> {\n const limit = options?.limit || 1000;\n let whereClause: string | undefined;\n\n if (options?.startDate) {\n whereClause = `TxnDate >= '${formatLocalDate(options.startDate)}'`;\n if (options?.endDate) {\n whereClause += ` AND TxnDate <= '${formatLocalDate(options.endDate)}'`;\n }\n }\n\n const payments = await this.provider.queryAll<QBOPayment>(\n 'Payment',\n whereClause,\n limit,\n );\n return payments.map(mapQBOToPayment);\n }\n}\n\n// =============================================================================\n// Audit Operations\n// =============================================================================\n\nclass QuickBooksAuditOperations implements AuditOperations {\n constructor(private provider: QuickBooksProvider) {}\n\n async reconcileCustomers(\n locals: CustomerInput[],\n ): Promise<AuditReport<CustomerInput>> {\n const externals = await this.provider.customers.list({ limit: 10000 });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareCustomer,\n );\n }\n\n async reconcileInvoices(\n locals: InvoiceInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<InvoiceInput>> {\n const externals = await this.provider.invoices.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareInvoice,\n );\n }\n\n async reconcileVendors(\n locals: VendorInput[],\n ): Promise<AuditReport<VendorInput>> {\n const externals = await this.provider.vendors.list({ limit: 10000 });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareVendor,\n );\n }\n\n async reconcileBills(\n locals: BillInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<BillInput>> {\n const externals = await this.provider.bills.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n compareBill,\n );\n }\n\n async reconcilePayments(\n locals: PaymentInput[],\n dateRange?: DateRange,\n ): Promise<AuditReport<PaymentInput>> {\n const externals = await this.provider.payments.list({\n limit: 10000,\n startDate: dateRange?.start,\n endDate: dateRange?.end,\n });\n return reconcileRecords(\n locals,\n externals,\n (l) => l.externalId,\n (e) => e.externalId,\n comparePayment,\n );\n }\n}\n\n/**\n * Generic reconciliation function with field comparison\n */\nfunction reconcileRecords<TLocal, TExternal extends ExternalRecord>(\n locals: TLocal[],\n externals: TExternal[],\n getLocalExternalId: (local: TLocal) => string | undefined,\n getExternalId: (external: TExternal) => string,\n compareFields: (local: TLocal, external: TExternal) => FieldDiff[],\n): AuditReport<TLocal> {\n const externalMap = new Map(externals.map((e) => [getExternalId(e), e]));\n const matchedExternalIds = new Set<string>();\n\n const matched: AuditMatch<TLocal>[] = [];\n const localOnly: TLocal[] = [];\n const discrepancies: AuditDiscrepancy<TLocal>[] = [];\n\n for (const local of locals) {\n const externalId = getLocalExternalId(local);\n if (externalId && externalMap.has(externalId)) {\n const external = externalMap.get(externalId)!;\n matchedExternalIds.add(externalId);\n\n // Compare fields\n const differences = compareFields(local, external);\n\n if (differences.length === 0) {\n matched.push({\n local,\n external,\n status: 'identical',\n });\n } else {\n discrepancies.push({\n local,\n external,\n differences,\n });\n }\n } else {\n localOnly.push(local);\n }\n }\n\n const externalOnly = externals.filter(\n (e) => !matchedExternalIds.has(getExternalId(e)),\n );\n\n return {\n provider: 'quickbooks',\n auditedAt: new Date(),\n matched,\n localOnly,\n externalOnly,\n discrepancies,\n summary: {\n total: locals.length + externalOnly.length,\n matched: matched.length,\n localOnly: localOnly.length,\n externalOnly: externalOnly.length,\n discrepancies: discrepancies.length,\n },\n };\n}\n\n// Field comparison functions\nfunction compareCustomer(\n local: CustomerInput,\n external: ExternalCustomer,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (local.name !== external.name) {\n diffs.push({\n field: 'name',\n localValue: local.name,\n externalValue: external.name,\n });\n }\n if (local.email !== external.email) {\n diffs.push({\n field: 'email',\n localValue: local.email,\n externalValue: external.email,\n });\n }\n\n return diffs;\n}\n\nfunction compareInvoice(\n local: InvoiceInput,\n external: ExternalInvoice,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.totalAmount, external.totalAmount)) {\n diffs.push({\n field: 'totalAmount',\n localValue: local.totalAmount,\n externalValue: external.totalAmount,\n });\n }\n if (local.invoiceNumber !== external.invoiceNumber) {\n diffs.push({\n field: 'invoiceNumber',\n localValue: local.invoiceNumber,\n externalValue: external.invoiceNumber,\n });\n }\n\n return diffs;\n}\n\nfunction compareVendor(\n local: VendorInput,\n external: ExternalVendor,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (local.name !== external.name) {\n diffs.push({\n field: 'name',\n localValue: local.name,\n externalValue: external.name,\n });\n }\n if (local.email !== external.email) {\n diffs.push({\n field: 'email',\n localValue: local.email,\n externalValue: external.email,\n });\n }\n\n return diffs;\n}\n\nfunction compareBill(local: BillInput, external: ExternalBill): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.totalAmount, external.totalAmount)) {\n diffs.push({\n field: 'totalAmount',\n localValue: local.totalAmount,\n externalValue: external.totalAmount,\n });\n }\n\n return diffs;\n}\n\nfunction comparePayment(\n local: PaymentInput,\n external: ExternalPayment,\n): FieldDiff[] {\n const diffs: FieldDiff[] = [];\n\n if (!valuesEqual(local.amount, external.amount)) {\n diffs.push({\n field: 'amount',\n localValue: local.amount,\n externalValue: external.amount,\n });\n }\n\n return diffs;\n}\n\n// =============================================================================\n// Webhook Operations\n// =============================================================================\n\nclass QuickBooksWebhookOperations implements WebhookOperations {\n constructor(private options: QuickBooksOptions) {}\n\n /**\n * Verify webhook signature using HMAC-SHA256\n * @see https://developer.intuit.com/app/developer/qbo/docs/develop/webhooks/verify-webhooks\n */\n verify(payload: string, signature: string, secret: string): boolean {\n // Use provided secret or fall back to configured webhook verifier token\n const verifierToken = secret || this.options.webhookVerifierToken;\n\n if (!verifierToken) {\n throw new Error(\n 'Webhook verifier token not provided. Pass it as the secret parameter or configure webhookVerifierToken in options.',\n );\n }\n\n // QBO uses HMAC-SHA256 and base64 encodes the signature\n const hmac = createHmac('sha256', verifierToken);\n hmac.update(payload);\n const expectedSignature = hmac.digest('base64');\n\n // Constant-time comparison to prevent timing attacks\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < signature.length; i++) {\n result |= signature.charCodeAt(i) ^ expectedSignature.charCodeAt(i);\n }\n return result === 0;\n }\n\n parse(payload: string): WebhookEvent {\n let data: QBOWebhookPayload;\n try {\n data = JSON.parse(payload) as QBOWebhookPayload;\n } catch (error) {\n const message =\n error instanceof Error ? error.message : 'Unknown JSON parse error';\n throw new Error(`Invalid QuickBooks webhook payload: ${message}`);\n }\n\n // QBO webhook payload structure\n const eventNotifications = data.eventNotifications || [];\n const firstEvent = eventNotifications[0]?.dataChangeEvent?.entities?.[0];\n\n return {\n type: firstEvent?.operation || 'unknown',\n provider: 'quickbooks',\n timestamp: new Date(),\n payload: data,\n resourceType: mapQBOResourceType(firstEvent?.name),\n resourceId: firstEvent?.id,\n };\n }\n}\n\nfunction mapQBOResourceType(\n name?: string,\n): WebhookEvent['resourceType'] | undefined {\n switch (name?.toLowerCase()) {\n case 'customer':\n return 'customer';\n case 'invoice':\n return 'invoice';\n case 'payment':\n return 'payment';\n case 'vendor':\n return 'vendor';\n case 'bill':\n return 'bill';\n default:\n return undefined;\n }\n}\n\n// =============================================================================\n// Mapping Functions\n// =============================================================================\n\nfunction mapCustomerToQBO(customer: CustomerInput): QBOCustomerCreate {\n return {\n DisplayName: customer.name,\n PrimaryEmailAddr: customer.email ? { Address: customer.email } : undefined,\n PrimaryPhone: customer.phone\n ? { FreeFormNumber: customer.phone }\n : undefined,\n BillAddr: mapAddressToQBO(customer.billingAddress),\n ShipAddr: mapAddressToQBO(customer.shippingAddress),\n CurrencyRef: customer.currency ? { value: customer.currency } : undefined,\n };\n}\n\nfunction mapQBOToCustomer(qbo: QBOCustomer): ExternalCustomer {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n name: qbo.DisplayName,\n email: qbo.PrimaryEmailAddr?.Address,\n phone: qbo.PrimaryPhone?.FreeFormNumber,\n billingAddress: mapQBOToAddress(qbo.BillAddr),\n balance: qbo.Balance,\n currency: qbo.CurrencyRef?.value,\n raw: qbo,\n };\n}\n\nfunction mapQBOToInvoice(qbo: QBOInvoice): ExternalInvoice {\n const balance = qbo.Balance ?? 0;\n const totalAmount = qbo.TotalAmt ?? 0;\n\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n invoiceNumber: qbo.DocNumber || '',\n customerExternalId: qbo.CustomerRef?.value || '',\n issueDate: new Date(qbo.TxnDate),\n dueDate: new Date(qbo.DueDate),\n subtotal: totalAmount - (qbo.TxnTaxDetail?.TotalTax ?? 0),\n taxAmount: qbo.TxnTaxDetail?.TotalTax ?? 0,\n totalAmount,\n amountPaid: totalAmount - balance,\n balance,\n status: mapInvoiceStatus(balance, totalAmount, qbo.DueDate),\n currency: qbo.CurrencyRef?.value || 'USD',\n raw: qbo,\n };\n}\n\nfunction mapInvoiceStatus(\n balance: number,\n total: number,\n dueDate: string,\n): ExternalInvoice['status'] {\n if (balance === 0) return 'paid';\n if (balance < total) return 'viewed'; // Partial payment\n if (new Date(dueDate) < new Date()) return 'overdue';\n return 'sent';\n}\n\nfunction mapVendorToQBO(vendor: VendorInput): QBOVendorCreate {\n return {\n DisplayName: vendor.name,\n PrimaryEmailAddr: vendor.email ? { Address: vendor.email } : undefined,\n PrimaryPhone: vendor.phone ? { FreeFormNumber: vendor.phone } : undefined,\n BillAddr: mapAddressToQBO(vendor.address),\n TaxIdentifier: vendor.taxId,\n CurrencyRef: vendor.currency ? { value: vendor.currency } : undefined,\n };\n}\n\nfunction mapQBOToVendor(qbo: QBOVendor): ExternalVendor {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n name: qbo.DisplayName,\n email: qbo.PrimaryEmailAddr?.Address,\n phone: qbo.PrimaryPhone?.FreeFormNumber,\n address: mapQBOToAddress(qbo.BillAddr),\n balance: qbo.Balance,\n currency: qbo.CurrencyRef?.value,\n raw: qbo,\n };\n}\n\nfunction mapBillToQBO(bill: BillInput): QBOBillCreate {\n return {\n VendorRef: { value: bill.vendorExternalId || bill.vendorId },\n DocNumber: bill.billNumber,\n TxnDate: formatLocalDate(bill.billDate),\n DueDate: formatLocalDate(bill.dueDate),\n Line: bill.lineItems.map((item, idx) => ({\n LineNum: idx + 1,\n Description: item.description,\n Amount: item.amount ?? item.quantity * item.unitPrice,\n DetailType: 'AccountBasedExpenseLineDetail' as const,\n AccountBasedExpenseLineDetail: {\n AccountRef: item.accountCode ? { value: item.accountCode } : undefined,\n },\n })),\n CurrencyRef: bill.currency ? { value: bill.currency } : undefined,\n };\n}\n\nfunction mapQBOToBill(qbo: QBOBill): ExternalBill {\n const balance = qbo.Balance ?? 0;\n const totalAmount = qbo.TotalAmt ?? 0;\n\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n billNumber: qbo.DocNumber,\n vendorExternalId: qbo.VendorRef?.value || '',\n billDate: new Date(qbo.TxnDate),\n dueDate: new Date(qbo.DueDate),\n subtotal: totalAmount - (qbo.TxnTaxDetail?.TotalTax ?? 0),\n taxAmount: qbo.TxnTaxDetail?.TotalTax ?? 0,\n totalAmount,\n amountPaid: totalAmount - balance,\n balance,\n status: mapBillStatus(balance, totalAmount, qbo.DueDate),\n currency: qbo.CurrencyRef?.value || 'USD',\n raw: qbo,\n };\n}\n\nfunction mapBillStatus(\n balance: number,\n total: number,\n dueDate: string,\n): ExternalBill['status'] {\n if (balance === 0) return 'paid';\n if (new Date(dueDate) < new Date()) return 'overdue';\n return 'pending';\n}\n\nfunction mapQBOToPayment(qbo: QBOPayment): ExternalPayment {\n return {\n externalId: qbo.Id,\n provider: 'quickbooks',\n syncedAt: new Date(),\n amount: qbo.TotalAmt ?? 0,\n currency: qbo.CurrencyRef?.value || 'USD',\n paidAt: new Date(qbo.TxnDate),\n method: qbo.PaymentMethodRef?.name,\n transactionId: qbo.PaymentRefNum,\n invoiceExternalIds: qbo.Line?.filter((l) => l.LinkedTxn).flatMap(\n (l) => l.LinkedTxn?.map((t) => t.TxnId) || [],\n ),\n status: 'completed',\n raw: qbo,\n };\n}\n\nfunction mapAddressToQBO(address?: Address): QBOAddress | undefined {\n if (!address) return undefined;\n return {\n Line1: address.street1,\n Line2: address.street2,\n City: address.city,\n CountrySubDivisionCode: address.state,\n PostalCode: address.postalCode,\n Country: address.country,\n };\n}\n\nfunction mapQBOToAddress(qbo?: QBOAddress): Address | undefined {\n if (!qbo) return undefined;\n return {\n street1: qbo.Line1,\n street2: qbo.Line2,\n city: qbo.City,\n state: qbo.CountrySubDivisionCode,\n postalCode: qbo.PostalCode,\n country: qbo.Country,\n };\n}\n\n// =============================================================================\n// QBO API Types (internal, strongly typed)\n// =============================================================================\n\ninterface QBORef {\n value: string;\n name?: string;\n}\n\ninterface QBOAddress {\n Line1?: string;\n Line2?: string;\n City?: string;\n CountrySubDivisionCode?: string;\n PostalCode?: string;\n Country?: string;\n}\n\ninterface QBOEmail {\n Address: string;\n}\n\ninterface QBOPhone {\n FreeFormNumber: string;\n}\n\n// Customer types\ninterface QBOCustomerBase {\n DisplayName: string;\n PrimaryEmailAddr?: QBOEmail;\n PrimaryPhone?: QBOPhone;\n BillAddr?: QBOAddress;\n ShipAddr?: QBOAddress;\n Balance?: number;\n CurrencyRef?: QBORef;\n}\n\ninterface QBOCustomerCreate extends QBOCustomerBase {}\n\ninterface QBOCustomerUpdate extends QBOCustomerBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOCustomer extends QBOCustomerBase {\n Id: string;\n SyncToken: string;\n}\n\n// Invoice types\ninterface QBOInvoiceLine {\n LineNum: number;\n Description?: string;\n Amount: number;\n DetailType: 'SalesItemLineDetail';\n SalesItemLineDetail?: {\n Qty?: number;\n UnitPrice?: number;\n ItemRef?: QBORef;\n TaxCodeRef?: QBORef;\n TaxInclusiveAmt?: number;\n };\n}\n\ninterface QBOInvoiceBase {\n CustomerRef: QBORef;\n DocNumber?: string;\n TxnDate: string;\n DueDate: string;\n Line: QBOInvoiceLine[];\n TotalAmt?: number;\n Balance?: number;\n TxnTaxDetail?: {\n TotalTax?: number;\n };\n GlobalTaxCalculation?: 'TaxExcluded' | 'TaxInclusive' | 'NotApplicable';\n CurrencyRef?: QBORef;\n CustomerMemo?: { value: string };\n}\n\ninterface QBOInvoiceUpdate extends QBOInvoiceBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOInvoice extends QBOInvoiceBase {\n Id: string;\n SyncToken: string;\n}\n\n// Vendor types\ninterface QBOVendorBase {\n DisplayName: string;\n PrimaryEmailAddr?: QBOEmail;\n PrimaryPhone?: QBOPhone;\n BillAddr?: QBOAddress;\n Balance?: number;\n TaxIdentifier?: string;\n CurrencyRef?: QBORef;\n}\n\ninterface QBOVendorCreate extends QBOVendorBase {}\n\ninterface QBOVendorUpdate extends QBOVendorBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOVendor extends QBOVendorBase {\n Id: string;\n SyncToken: string;\n}\n\n// Bill types\ninterface QBOBillLine {\n LineNum: number;\n Description?: string;\n Amount: number;\n DetailType: 'AccountBasedExpenseLineDetail';\n AccountBasedExpenseLineDetail?: {\n AccountRef?: QBORef;\n };\n}\n\ninterface QBOBillBase {\n VendorRef: QBORef;\n DocNumber?: string;\n TxnDate: string;\n DueDate: string;\n Line: QBOBillLine[];\n TotalAmt?: number;\n Balance?: number;\n TxnTaxDetail?: {\n TotalTax?: number;\n };\n CurrencyRef?: QBORef;\n}\n\ninterface QBOBillCreate extends QBOBillBase {}\n\ninterface QBOBillUpdate extends QBOBillBase {\n Id: string;\n SyncToken: string;\n}\n\ninterface QBOBill extends QBOBillBase {\n Id: string;\n SyncToken: string;\n}\n\n// Payment types\ninterface QBOPaymentLine {\n Amount: number;\n LinkedTxn?: {\n TxnId: string;\n TxnType: string;\n }[];\n}\n\ninterface QBOPayment {\n Id: string;\n SyncToken: string;\n TxnDate: string;\n TotalAmt?: number;\n CustomerRef?: QBORef;\n PaymentMethodRef?: QBORef;\n PaymentRefNum?: string;\n Line?: QBOPaymentLine[];\n CurrencyRef?: QBORef;\n}\n\n// Webhook types\ninterface QBOWebhookPayload {\n eventNotifications?: {\n realmId: string;\n dataChangeEvent?: {\n entities?: {\n name: string;\n id: string;\n operation: string;\n lastUpdated: string;\n }[];\n };\n }[];\n}\n"],"mappings":";;;;;AAiBA,IAAa,gCAAb,MAEA;CACsB;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CACnD,YAAoB,SAAsC;EACxD,oCAAoC,OAAO;EAC3C,IACE,QAAQ,YAAY,KAAK,SAAS,WAClC,QAAQ,gBAAgB,KAAK,SAAS,aAEtC,MAAM,IAAI,MACR,qEACF;CACJ;CACA,MAAc,OAAO,MAAc,IAAqC;EACtE,IAAI,CAAC,0BAA0B,KAAK,EAAE,GACpC,MAAM,IAAI,MAAM,uCAAuC;EAKzD,MAAM,SAAQ,MAJO,KAAK,SAAS,QACjC,OACA,GAAG,KAAK,YAAY,EAAE,GAAG,mBAAmB,EAAE,GAChD,EAAA,CACqB;EACrB,IAAI,CAAC,SAAS,MAAM,OAAO,IACzB,MAAM,IAAI,MAAM,YAAY,KAAK,kBAAkB;EACrD,OAAO;CACT;CACA,MAAM,cAAc,SAAsC;EACxD,KAAK,YAAY,OAAO;EAKxB,MAAM,cAAa,MAJC,KAAK,SAAS,QAChC,OACA,aACF,EAAA,CACyB,aAAa;EACtC,IACE,YAAY,cAAc,UAAU,QAAQ,YAC5C,OAAO,YAAY,yBAAyB,WAE5C,MAAM,IAAI,MACR,sFACF;EACF,MAAM,WAAW,MAAM,KAAK,OAAO,YAAY,QAAQ,WAAW;EAClE,IACE,SAAS,WAAW,SACnB,SAAS,aAAa,UACpB,WAAW,yBAAyB,QACjC,QAAQ,WACR,KAAA,QAAgB,QAAQ,UAE9B,MAAM,IAAI,MACR,uEACF;EACF,KAAK,MAAM,CAAC,KAAK,SAAS;GACxB,CAAC,QAAQ,uBAAuB,qBAAqB;GACrD,CAAC,QAAQ,yBAAyB,qBAAqB;GACvD,GAAI,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,gBAAgB,MAAM,CAAC,IAAI,CAAC;EACrE,GAAG;GACD,MAAM,UAAU,MAAM,KAAK,OAAO,WAAW,GAAG;GAChD,IACE,QAAQ,WAAW,QACnB,QAAQ,gBAAgB,QACvB,QAAQ,gBAAgB,KAAA,KACvB,QAAQ,aAAa,UAAU,QAAQ,UAEzC,MAAM,IAAI,MACR,iFACF;EACJ;EACA,OAAO;GACL,aAAa,WAAW,QAAQ,CAAC,CAC9B,OAAO,KAAK,UAAU,OAAO,CAAC,CAAC,CAC/B,OAAO,KAAK;GACf,cAAc,QAAQ;EACxB;CACF;CACA,SACE,QACA,SACA;EACA,IAAI,OAAO,aAAa,UAAU,QAAQ,UACxC,MAAM,IAAI,MAAM,uCAAuC;CAC3D;CACA,MAAc,QAAiB,UAA0B;EACvD,IAAI,OAAO,WAAW,YAAY,CAAC,oBAAoB,QAAQ,QAAQ,GACrE,MAAM,IAAI,MACR,+DACF;EACF,MAAM,QAAQ,KAAK,MAAM,SAAS,wBAAwB,QAAQ,CAAE;EACpE,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAC1C,MAAM,IAAI,MAAM,uDAAuD;EACzE,OAAO;CACT;CACA,iBACE,QACA,SACmD;EACnD,KAAK,SAAS,QAAQ,OAAO;EAC7B,IAAI,CAAC,MAAM,QAAQ,OAAO,IAAI,GAC5B,MAAM,IAAI,MAAM,oCAAoC;EACtD,MAAM,KAAK,OAAO,KAAK,QACpB,SACC,KAAK,wBAAwB,YAAY,UACzC,QAAQ,qBACZ;EACA,IAAI,GAAG,WAAW,GAChB,MAAM,IAAI,MACR,gEACF;EACF,MAAM,SAAS,GAAG,EAAE,CAAC;EACrB,IACE,OAAO,QAAQ,SAAS,cACxB,OAAO,QAAQ,WAAW,UAAU,QAAQ,eAC5C,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,SAAS,OAAO,WAAW,GAEhD,MAAM,IAAI,MAAM,mDAAmD;EACrE,OAAO;GACL,MAAM,OAAO,gBAAgB,UAAU,UAAU;GACjD,aAAa,KAAK,MAAM,GAAG,EAAE,CAAC,QAAQ,QAAQ,QAAQ;EACxD;CACF;CACA,MAAc,iBACZ,SAC2B;EAC3B,MAAM,OAAyB,CAAC;EAEhC,KAAK,IAAI,OAAO,GAAG,OAAO,KAAO,QAAQ;GACvC,MAAM,QAAQ,8CAA8C,QAAQ,YAAY,kBAAkB,OAAO,MAAM,EAAE;GACjH,MAAM,SAAS,MAAM,KAAK,SAAS,QAEhC,OAAO,eAAe,mBAAmB,KAAK,GAAG;GACpD,IAAI,CAAC,OAAO,eACV,MAAM,IAAI,MAAM,2CAA2C;GAC7D,MAAM,QAAQ,OAAO,cAAc,WAAW,CAAC;GAC/C,IAAI,CAAC,MAAM,QAAQ,KAAK,GACtB,MAAM,IAAI,MAAM,qCAAqC;GACvD,KAAK,KAAK,GAAG,KAAK;GAClB,IAAI,MAAM,SAAS,KAAK,OAAO;EACjC;EACA,MAAM,IAAI,MACR,6EACF;CACF;CACA,MAAc,UACZ,KACA,SACA,WACA;EACA,MAAM,SAAS,MAAM,KAAK,OAAO,IAAI,MAAM,IAAI,EAAE;EACjD,KAAK,SAAS,QAAQ,OAAO;EAC7B,IAAI,IAAI,SAAS,gBAAgB;GAC/B,IAAI,OAAO,aAAa,UAAU,QAAQ,aACxC,MAAM,IAAI,MAAM,qDAAqD;GACvE,OAAO,KAAK,MACV,IAAI,SAAS,YAAY,OAAO,UAAU,OAAO,iBACjD,QAAQ,QACV;EACF;EACA,MAAM,UAAU,KAAK,iBAAiB,QAAQ,OAAO;EACrD,IAAI,QAAQ,SAAS,WACnB,MAAM,IAAI,MAAM,wDAAwD;EAC1E,IAAI,OAAO;EACX,KAAK,MAAM,WAAW,MAAM,KAAK,iBAAiB,OAAO,GAAG;GAC1D,IAAI,QAAQ,aAAa,UAAU,QAAQ,aACzC,MAAM,IAAI,MAAM,0CAA0C;GAC5D,KAAK,MAAM,QAAQ,QAAQ,QAAQ,CAAC,GAAG;IACrC,MAAM,QAAQ,KAAK,aAAa,CAAC;IACjC,IACE,MAAM,MACH,SACC,KAAK,YAAY,kBAAkB,KAAK,UAAU,IAAI,EAC1D,GACA;KACA,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,MACR,wEACF;KACF,KAAK,SAAS,SAAS,OAAO;KAC9B,QAAQ,OAAO,KAAK,MAAM,KAAK,QAAQ,QAAQ,QAAQ,CAAC;IAC1D;GACF;EACF;EACA,MAAM,YAAY,OAAO,QAAQ,WAAW,IAAI;EAChD,IAAI,YAAY,IACd,MAAM,IAAI,MACR,6DACF;EACF,OAAO,OAAO,SAAS;CACzB;CACA,MAAc,UAAU,SAAsC;EAC5D,MAAM,KAAK,cAAc,QAAQ,MAAM,OAAO;EAC9C,MAAM,QAAQ,QAAQ,OACpB,SAAS,MAAM,KAAK,OAAO,MAAM,OAAO,MAAM,MAAM,OAAO,EAAE;EAC/D,KAAK,SAAS,QAAQ,MAAM,OAAO;EACnC,IAAI,MAAM,OAAO,SAAS,gBACxB,KAAK,iBAAiB,QAAQ,MAAM,OAAO;OACxC,IAAI,OAAO,aAAa,UAAU,MAAM,QAAQ,aACnD,MAAM,IAAI,MACR,yDACF;EACF,IAAI,MAAM,SAAS,eAAe;GAChC,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,OAAO,MAAM,SAAS,OAAO,GACpE,SAAS,MAAM,KAAK,UAAU,MAAM,QAAQ,MAAM,SAAS,QAAQ;GACrE,IAAI,MAAM,cAAc,SAAS,MAAM,cAAc,QACnD,MAAM,IAAI,MACR,qEACF;EACJ;CACF;CACA,MAAM,QACJ,SACuC;EAEvC,MAAM,WAAW,gBAAgB,OAAO;EACxC,oCACE,UACA,KAAK,SAAS,SACd,KAAK,SAAS,WAChB;EACA,MAAM,OAAO,+BAA+B,SAAS,KAAK;EAC1D,MAAM,KAAK,UAAU,QAAQ;EAC7B,MAAM,WAAW,MAAM,KAAK,SAAS,QAEnC,QAAQ,SAAS,UAAU,MAAM,QAAQ;EAC3C,MAAM,OACJ,SAAS,aAAa,iBAAiB,iBAAiB;EAE1D,IAAI;GACF,OAAO,oCAAoC,UAAU,SAAS,KAAK;EACrE,SAAS,OAAO;GACd,MAAM,aAAa,WAAW,KAAK,EAAE;GACrC,MAAM,IAAI,qBAAqB;IAC7B,SAAS;IACT,SAAS,SAAS;IAClB,aAAa,SAAS;IACtB,UAAU,SAAS;IACnB,WAAW,SAAS;IACpB,aAAa,SAAS;IACtB,YACE,OAAO,eAAe,YAAY,aAAa,aAAa,KAAA;IAC9D;GACF,CAAC;EACH;CACF;CACA,MAAM,KACJ,SACA,YACuC;EACvC,MAAM,WAAW,gBAAgB,OAAO;EACxC,oCACE,UACA,KAAK,SAAS,SACd,KAAK,SAAS,WAChB;EACA,MAAM,OACJ,SAAS,aAAa,iBAAiB,iBAAiB;EAC1D,OAAO,oCACL,UACA,MAAM,KAAK,OAAO,MAAM,UAAU,CACpC;CACF;AACF;;;;;;;;;;;;;ACjNA,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;;;;AAKA,SAAS,MAAM,IAA2B;CACxC,OAAO,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;;;;AAKA,SAAS,YAAY,GAAY,GAAqB;CACpD,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,aAAa,QAAQ,aAAa,MACpC,OAAO,EAAE,QAAQ,MAAM,EAAE,QAAQ;CAEnC,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAExC,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI;CAE3B,OAAO;AACT;;;;AASA,IAAa,qBAAb,MAA8D;CAC5D,OAAgB;CAChB;CAEA;CACA,cAAqC;CACrC,iBAAsC;CAEtC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,YAAY,SAA4B;EACtC,KAAK,UAAU;GACb,SAAS;GACT,YAAY;GACZ,GAAG;EACL;EAEA,KAAK,sBAAsB,IAAI,8BAA8B,IAAI;EAEjE,KAAK,YAAY,IAAI,6BAA6B,IAAI;EACtD,KAAK,WAAW,IAAI,4BAA4B,IAAI;EACpD,KAAK,cAAc,IAAI,+BAA+B,IAAI;EAC1D,KAAK,UAAU,IAAI,2BAA2B,IAAI;EAClD,KAAK,QAAQ,IAAI,yBAAyB,IAAI;EAC9C,KAAK,WAAW,IAAI,4BAA4B,IAAI;EACpD,KAAK,QAAQ,IAAI,0BAA0B,IAAI;EAC/C,KAAK,WAAW,IAAI,4BAA4B,KAAK,OAAO;CAC9D;;;;CAKA,IAAI,UAAkB;EACpB,OAAO,KAAK,QAAQ,gBAAgB,eAChC,sCACA;CACN;;;;CAKA,IAAI,cAAwC;EAC1C,OAAO,KAAK,QAAQ,gBAAgB,eAAe,eAAe;CACpE;CAEA,IAAI,UAAkB;EACpB,OAAO,KAAK,QAAQ;CACtB;;;;CAKA,MAAM,oBAAqC;EAEzC,IAAI,KAAK,eAAe,KAAK;wBAEvB,IAAI,KAAK,EAAA,CAAE,QAAQ,IAAI,KAAK,eAAe,QAAQ,IADtC,MAAS,KAExB,OAAO,KAAK;EAAA;EAKhB,MAAM,SAAS,MAAM,KAAK,mBAAmB;EAC7C,KAAK,cAAc,OAAO;EAC1B,KAAK,iBAAiB,OAAO;EAG7B,KAAK,QAAQ,eAAe,OAAO;EAGnC,IAAI,KAAK,QAAQ,gBACf,MAAM,KAAK,QAAQ,eAAe,MAAM;EAG1C,OAAO,KAAK;CACd;;;;CAKA,MAAc,qBAAwC;EAEpD,MAAM,eAAe,MAAM,OAAO,gBAAA,CAAiB;EAEnD,MAAM,cACJ,KAAK,QAAQ,eACb;EAEF,MAAM,cAAc,IAAI,YAAY;GAClC,UAAU,KAAK,QAAQ;GACvB,cAAc,KAAK,QAAQ;GAC3B,aACE,KAAK,QAAQ,gBAAgB,eAAe,eAAe;GAC7D;EACF,CAAC;EAED,YAAY,SAAS;GACnB,eAAe,KAAK,QAAQ;GAC5B,cAAc,KAAK,eAAe;EACpC,CAAC;EAGD,MAAM,SAAQ,MADS,YAAY,QAAQ,EAAA,CACpB,QAAQ;EAE/B,OAAO;GACL,aAAa,MAAM;GACnB,cAAc,MAAM;GACpB,WAAW,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,aAAa,GAAI;GACxD,WAAW,MAAM;EACnB;CACF;;;;CAKA,MAAM,QACJ,QACA,UACA,MACA,eAIY;EAEZ,MAAM,iBACJ,SAAS,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU,IAAI;EACtD,MAAM,UAAU,KAAK;EACrB,MAAM,cACJ,KAAK,QAAQ,gBAAgB,eAAe,eAAe;EAC7D,IAAI,eAAe;GACjB,IACE,WAAW,UACX,CAAC;IAAC;IAAW;IAAc;IAAgB;GAAS,CAAC,CAAC,SAAS,QAAQ,GAEvE,MAAM,IAAI,MACR,0HACF;GAEF,IAAI,aAAa,kBAAkB,aAAa,WAAW;IACzD,IACE,EAAE,cAAc,kBAChB,cAAc,aAAa,UAE3B,MAAM,IAAI,MAAM,mDAAmD;IACrE,oCACE,eACA,SACA,aACA,cACF;GACF,OAAO,IAAI,aAAa,WACtB,iCACE,eACA,SACA,aACA,cACF;QAEA,oCACE,eACA,SACA,aACA,cACF;EACJ;EACA,MAAM,YAAY,eAAe;EACjC,MAAM,cAAc,eAAe;EACnC,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,QAAQ,cAAc,QAAQ,GAAG,UAAU;EACvE,IAAI,WAAW,IAAI,aAAa,IAAI,aAAa,SAAS;EAC1D,MAAM,UAAU,KAAK,QAAQ,WAAW;EACxC,MAAM,aACJ,WAAW,SAAS,YAAa,KAAK,QAAQ,cAAc,IAAK;EACnE,MAAM,iBAAiB;GACrB;GACA;GACA;GACA;GACA;GACA;GACA;EACF,CAAC,CAAC,MAAM,WAAW,OAAO,YAAY,MAAM,SAAS,MAAM,QAAQ,CAAC,CAAC,CAAC,EAAE;EACxE,MAAM,cAAc,MAAM,KAAK,kBAAkB;EAIjD,IAAI,YAAY,cAAc,KAAA;EAE9B,KAAK,IAAI,UAAU,IAAK,WAAW;GACjC,MAAM,aAAa,IAAI,gBAAgB;GACvC,MAAM,YAAY,iBAAiB,WAAW,MAAM,GAAG,OAAO;GAC9D,IAAI;GACJ,IAAI;GACJ,IAAI;IACF,MAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;KAC3C;KACA,SAAS;MACP,eAAe,UAAU;MACzB,QAAQ;MACR,gBAAgB;KAClB;KACA,MAAM;KACN,QAAQ,WAAW;IACrB,CAAC;IACD,SAAS,SAAS;IAClB,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MACR,kBAAkB,OAAO,KAAK,MAAM,SAAS,KAAK,GACpD;IAEF,MAAM,SAAS,MAAM,SAAS,KAAK;IAGnC,IACE,WAAW,SACX,mBACC,OAAO,SAAS,eAAe,EAAE,OAAO,YACvC,CAAC,OAAO,eAAe,CAAC,GAAG,KAAK,IAElC,MAAM,IAAI,MAAM,2BAA2B,eAAe,IAAI;IAEhE,OAAO;GACT,SAAS,OAAO;IACd,UAAU;IACV,cACE,WAAW,KAAA,KACX,UAAU,OACT,UAAU,OAAO,SAAS;GAC/B,UAAU;IACR,aAAa,SAAS;GACxB;GAMA,IAAI,EAJF,WAAW,KAAA,KACX,WAAW,OACX,UAAU,OACT,UAAU,OAAO,SAAS,QACX,WAAW,YAAY;IACvC,IAAI,WAAW,OACb,MAAM,IAAI,qBAAqB;KAC7B;KACA;KACA;KACA;KACA;KACA;KACA,SAAS,YAAY,YAAY;KACjC,OAAO;IACT,CAAC;IAEH,MAAM;GACR;GACA,MAAM,MAAM,KAAK,UAAU,GAAI;EACjC;CACF;;;;CAKA,MAAM,SACJ,QACA,aACA,aAAa,KACC;EACd,MAAM,UAAe,CAAC;EACtB,IAAI,gBAAgB;EACpB,MAAM,WAAW;EAEjB,OAAO,QAAQ,SAAS,YAAY;GAClC,IAAI,QAAQ,iBAAiB;GAC7B,IAAI,aACF,SAAS,UAAU;GAErB,SAAS,eAAe,SAAS,iBAAiB;GAMlD,MAAM,SAAQ,MAJS,KAAK,QAEzB,OAAO,eAAe,mBAAmB,KAAK,GAAG,EAAA,CAE7B,cAAc,WAAW,CAAC;GACjD,QAAQ,KAAK,GAAG,KAAK;GAGrB,IAAI,MAAM,SAAS,UACjB;GAGF,iBAAiB;EACnB;EAEA,OAAO;CACT;AACF;AAMA,IAAM,+BAAN,MAAiE;CAC3C;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,UAA8C;EACvD,MAAM,cAAc,iBAAiB,QAAQ;EAQ7C,OAAO;GACL,QAAQ;GACR,aAAY,MARS,KAAK,SAAS,QACnC,QACA,YACA,WACF,EAAA,CAIuB,SAAS;GAC9B,0BAAU,IAAI,KAAK;EACrB;CACF;CAEA,MAAM,KAAK,YAA+C;EAMxD,OAAO,kBAAiB,MALD,KAAK,SAAS,QACnC,OACA,YAAY,YACd,EAAA,CAEiC,QAAQ;CAC3C;CAEA,MAAM,KAAK,SAAoD;EAC7D,MAAM,QAAQ,SAAS,SAAS;EAMhC,QAAO,MALiB,KAAK,SAAS,SACpC,YACA,KAAA,GACA,KACF,EAAA,CACiB,IAAI,gBAAgB;CACvC;CAEA,MAAM,KAAK,UAA8C;EACvD,IAAI,SAAS,YAAY;GAEvB,MAAM,WAAW,MAAM,KAAK,SAAS,QACnC,OACA,YAAY,SAAS,YACvB;GAEA,MAAM,cAAiC;IACrC,GAAG,iBAAiB,QAAQ;IAC5B,IAAI,SAAS;IACb,WAAW,SAAS,SAAS;GAC/B;GAEA,MAAM,KAAK,SAAS,QAAQ,QAAQ,YAAY,WAAW;GAE3D,OAAO;IACL,QAAQ;IACR,YAAY,SAAS;IACrB,0BAAU,IAAI,KAAK;GACrB;EACF;EAEA,OAAO,KAAK,KAAK,QAAQ;CAC3B;AACF;AAMA,IAAM,8BAAN,MAA+D;CACzC;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,SAA4C;EACrD,IAAI,QAAQ,cAAc,QAAQ,mBAChC,MAAM,IAAI,MACR,gEACF;EACF,MAAM,aAAa,gBAAgB,OAAO;EAS1C,OAAO;GACL,QAAQ;GACR,aAAY,MATS,KAAK,SAAS,QACnC,QACA,WACA,YACA,QAAQ,iBACV,EAAA,CAIuB,QAAQ;GAC7B,0BAAU,IAAI,KAAK;EACrB;CACF;CAEA,MAAM,KAAK,YAA8C;EAMvD,OAAO,iBAAgB,MALA,KAAK,SAAS,QACnC,OACA,WAAW,YACb,EAAA,CAEgC,OAAO;CACzC;CAEA,MAAM,KAAK,SAAmD;EAC5D,MAAM,QAAQ,SAAS,SAAS;EAChC,IAAI;EAEJ,IAAI,SAAS,WAAW;GACtB,cAAc,eAAe,gBAAgB,QAAQ,SAAS,EAAE;GAChE,IAAI,SAAS,SACX,eAAe,oBAAoB,gBAAgB,QAAQ,OAAO,EAAE;EAExE;EAOA,QAAO,MALgB,KAAK,SAAS,SACnC,WACA,aACA,KACF,EAAA,CACgB,IAAI,eAAe;CACrC;CAEA,MAAM,KAAK,SAA4C;EACrD,IAAI,QAAQ,YAAY;GACtB,IAAI,QAAQ,mBACV,MAAM,IAAI,MACR,gEACF;GACF,MAAM,WAAW,MAAM,KAAK,SAAS,QACnC,OACA,WAAW,QAAQ,YACrB;GAEA,MAAM,aAA+B;IACnC,GAAG,gBAAgB,OAAO;IAC1B,IAAI,QAAQ;IACZ,WAAW,SAAS,QAAQ;GAC9B;GAEA,MAAM,KAAK,SAAS,QAAQ,QAAQ,WAAW,UAAU;GAEzD,OAAO;IACL,QAAQ;IACR,YAAY,QAAQ;IACpB,0BAAU,IAAI,KAAK;GACrB;EACF;EAEA,OAAO,KAAK,KAAK,OAAO;CAC1B;CAEA,MAAM,KAAK,YAAmC;EAC5C,MAAM,KAAK,SAAS,QAAQ,QAAQ,WAAW,WAAW,MAAM;CAClE;CAEA,MAAM,KAAK,YAAmC;EAC5C,MAAM,WAAW,MAAM,KAAK,SAAS,QACnC,OACA,WAAW,YACb;EAEA,MAAM,KAAK,SAAS,QAAQ,QAAQ,WAAW;GAC7C,IAAI;GACJ,WAAW,SAAS,QAAQ;GAC5B,QAAQ;GAGR,aAAa;EACf,CAAC;CACH;AACF;AAMA,IAAM,iCAAN,MAAqE;CAC/C;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,YAA6C;EACtD,IACE,CAAC,cACD,WAAW,KAAK,MAAM,cACtB,WAAW,SAAS,KAEpB,MAAM,IAAI,MACR,+DACF;EACF,MAAM,WAAW,MAAM,KAAK,SAAS,QAElC,OAAO,cAAc,mBAAmB,UAAU,GAAG;EACxD,IAAI,CAAC,SAAS,cAAc,SAAS,WAAW,OAAO,YACrD,MAAM,IAAI,MAAM,kDAAkD;EACpE,OAAO;GACL,UAAU;GACV;GACA,0BAAU,IAAI,KAAK;GACnB,KAAK,SAAS;EAChB;CACF;CAEA,MAAM,KAAK,YAAkD;EAC3D,IAAI,WAAW,cAAc,WAAW,6BACtC,MAAM,IAAI,MACR,oEACF;EACF,MAAM,SAAS,mBAAmB,UAAU;EAC5C,IACE,WAAW,+BACX,WAAW,4BAA4B,8BACrC,WAAW,2BAEb,MAAM,IAAI,MACR,iFACF;EAIF,OAAO;GACL,QAAQ;GACR,aAAY,MALS,KAAK,SAAS,QAElC,QAAQ,cAAc,QAAQ,WAAW,2BAA2B,EAAA,CAGhD,WAAW;GAChC,0BAAU,IAAI,KAAK;EACrB;CACF;CAEA,MAAM,KAAK,YAAkD;EAC3D,IAAI,CAAC,WAAW,YAAY,OAAO,KAAK,KAAK,UAAU;EACvD,IAAI,WAAW,6BACb,MAAM,IAAI,MACR,oEACF;EAEF,MAAM,SAAS,mBAAmB,UAAU;EAC5C,MAAM,WAAW,MAAM,KAAK,SAAS,QAElC,OAAO,cAAc,WAAW,YAAY;EAC/C,MAAM,KAAK,SAAS,QAAQ,QAAQ,cAAc;GAChD,GAAG;GACH,IAAI,WAAW;GACf,WAAW,SAAS,WAAW;EACjC,CAAC;EACD,OAAO;GACL,QAAQ;GACR,YAAY,WAAW;GACvB,0BAAU,IAAI,KAAK;EACrB;CACF;AACF;AAMA,IAAM,6BAAN,MAA6D;CACvC;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,QAA0C;EACnD,MAAM,YAAY,eAAe,MAAM;EAQvC,OAAO;GACL,QAAQ;GACR,aAAY,MARS,KAAK,SAAS,QACnC,QACA,UACA,SACF,EAAA,CAIuB,OAAO;GAC5B,0BAAU,IAAI,KAAK;EACrB;CACF;CAEA,MAAM,KAAK,YAA6C;EAMtD,OAAO,gBAAe,MALC,KAAK,SAAS,QACnC,OACA,UAAU,YACZ,EAAA,CAE+B,MAAM;CACvC;CAEA,MAAM,KAAK,SAAkD;EAC3D,MAAM,QAAQ,SAAS,SAAS;EAMhC,QAAO,MALe,KAAK,SAAS,SAClC,UACA,KAAA,GACA,KACF,EAAA,CACe,IAAI,cAAc;CACnC;CAEA,MAAM,KAAK,QAA0C;EACnD,IAAI,OAAO,YAAY;GACrB,MAAM,WAAW,MAAM,KAAK,SAAS,QACnC,OACA,UAAU,OAAO,YACnB;GAEA,MAAM,YAA6B;IACjC,GAAG,eAAe,MAAM;IACxB,IAAI,OAAO;IACX,WAAW,SAAS,OAAO;GAC7B;GAEA,MAAM,KAAK,SAAS,QAAQ,QAAQ,UAAU,SAAS;GAEvD,OAAO;IACL,QAAQ;IACR,YAAY,OAAO;IACnB,0BAAU,IAAI,KAAK;GACrB;EACF;EAEA,OAAO,KAAK,KAAK,MAAM;CACzB;AACF;AAMA,IAAM,2BAAN,MAAyD;CACnC;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,MAAsC;EAC/C,MAAM,UAAU,aAAa,IAAI;EAQjC,OAAO;GACL,QAAQ;GACR,aAAY,MARS,KAAK,SAAS,QACnC,QACA,QACA,OACF,EAAA,CAIuB,KAAK;GAC1B,0BAAU,IAAI,KAAK;EACrB;CACF;CAEA,MAAM,KAAK,YAA2C;EAMpD,OAAO,cAAa,MALG,KAAK,SAAS,QACnC,OACA,QAAQ,YACV,EAAA,CAE6B,IAAI;CACnC;CAEA,MAAM,KAAK,SAAgD;EACzD,MAAM,QAAQ,SAAS,SAAS;EAChC,IAAI;EAEJ,IAAI,SAAS,WAAW;GACtB,cAAc,eAAe,gBAAgB,QAAQ,SAAS,EAAE;GAChE,IAAI,SAAS,SACX,eAAe,oBAAoB,gBAAgB,QAAQ,OAAO,EAAE;EAExE;EAOA,QAAO,MALa,KAAK,SAAS,SAChC,QACA,aACA,KACF,EAAA,CACa,IAAI,YAAY;CAC/B;CAEA,MAAM,KAAK,MAAsC;EAC/C,IAAI,KAAK,YAAY;GACnB,MAAM,WAAW,MAAM,KAAK,SAAS,QACnC,OACA,QAAQ,KAAK,YACf;GAEA,MAAM,UAAyB;IAC7B,GAAG,aAAa,IAAI;IACpB,IAAI,KAAK;IACT,WAAW,SAAS,KAAK;GAC3B;GAEA,MAAM,KAAK,SAAS,QAAQ,QAAQ,QAAQ,OAAO;GAEnD,OAAO;IACL,QAAQ;IACR,YAAY,KAAK;IACjB,0BAAU,IAAI,KAAK;GACrB;EACF;EAEA,OAAO,KAAK,KAAK,IAAI;CACvB;AACF;AAMA,IAAM,8BAAN,MAA+D;CACzC;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,KAAK,YAA8C;EAMvD,OAAO,iBAAgB,MALA,KAAK,SAAS,QACnC,OACA,WAAW,YACb,EAAA,CAEgC,OAAO;CACzC;CAEA,MAAM,KAAK,SAAmD;EAC5D,MAAM,QAAQ,SAAS,SAAS;EAChC,IAAI;EAEJ,IAAI,SAAS,WAAW;GACtB,cAAc,eAAe,gBAAgB,QAAQ,SAAS,EAAE;GAChE,IAAI,SAAS,SACX,eAAe,oBAAoB,gBAAgB,QAAQ,OAAO,EAAE;EAExE;EAOA,QAAO,MALgB,KAAK,SAAS,SACnC,WACA,aACA,KACF,EAAA,CACgB,IAAI,eAAe;CACrC;AACF;AAMA,IAAM,4BAAN,MAA2D;CACrC;CAApB,YAAY,UAAsC;EAA9B,KAAA,WAAA;CAA+B;CAEnD,MAAM,mBACJ,QACqC;EAErC,OAAO,iBACL,QACA,MAHsB,KAAK,SAAS,UAAU,KAAK,EAAE,OAAO,IAAM,CAAC,IAIlE,MAAM,EAAE,aACR,MAAM,EAAE,YACT,eACF;CACF;CAEA,MAAM,kBACJ,QACA,WACoC;EAMpC,OAAO,iBACL,QACA,MAPsB,KAAK,SAAS,SAAS,KAAK;GAClD,OAAO;GACP,WAAW,WAAW;GACtB,SAAS,WAAW;EACtB,CAAC,IAIE,MAAM,EAAE,aACR,MAAM,EAAE,YACT,cACF;CACF;CAEA,MAAM,iBACJ,QACmC;EAEnC,OAAO,iBACL,QACA,MAHsB,KAAK,SAAS,QAAQ,KAAK,EAAE,OAAO,IAAM,CAAC,IAIhE,MAAM,EAAE,aACR,MAAM,EAAE,YACT,aACF;CACF;CAEA,MAAM,eACJ,QACA,WACiC;EAMjC,OAAO,iBACL,QACA,MAPsB,KAAK,SAAS,MAAM,KAAK;GAC/C,OAAO;GACP,WAAW,WAAW;GACtB,SAAS,WAAW;EACtB,CAAC,IAIE,MAAM,EAAE,aACR,MAAM,EAAE,YACT,WACF;CACF;CAEA,MAAM,kBACJ,QACA,WACoC;EAMpC,OAAO,iBACL,QACA,MAPsB,KAAK,SAAS,SAAS,KAAK;GAClD,OAAO;GACP,WAAW,WAAW;GACtB,SAAS,WAAW;EACtB,CAAC,IAIE,MAAM,EAAE,aACR,MAAM,EAAE,YACT,cACF;CACF;AACF;;;;AAKA,SAAS,iBACP,QACA,WACA,oBACA,eACA,eACqB;CACrB,MAAM,cAAc,IAAI,IAAI,UAAU,KAAK,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC;CACvE,MAAM,qCAAqB,IAAI,IAAY;CAE3C,MAAM,UAAgC,CAAC;CACvC,MAAM,YAAsB,CAAC;CAC7B,MAAM,gBAA4C,CAAC;CAEnD,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,aAAa,mBAAmB,KAAK;EAC3C,IAAI,cAAc,YAAY,IAAI,UAAU,GAAG;GAC7C,MAAM,WAAW,YAAY,IAAI,UAAU;GAC3C,mBAAmB,IAAI,UAAU;GAGjC,MAAM,cAAc,cAAc,OAAO,QAAQ;GAEjD,IAAI,YAAY,WAAW,GACzB,QAAQ,KAAK;IACX;IACA;IACA,QAAQ;GACV,CAAC;QAED,cAAc,KAAK;IACjB;IACA;IACA;GACF,CAAC;EAEL,OACE,UAAU,KAAK,KAAK;CAExB;CAEA,MAAM,eAAe,UAAU,QAC5B,MAAM,CAAC,mBAAmB,IAAI,cAAc,CAAC,CAAC,CACjD;CAEA,OAAO;EACL,UAAU;EACV,2BAAW,IAAI,KAAK;EACpB;EACA;EACA;EACA;EACA,SAAS;GACP,OAAO,OAAO,SAAS,aAAa;GACpC,SAAS,QAAQ;GACjB,WAAW,UAAU;GACrB,cAAc,aAAa;GAC3B,eAAe,cAAc;EAC/B;CACF;AACF;AAGA,SAAS,gBACP,OACA,UACa;CACb,MAAM,QAAqB,CAAC;CAE5B,IAAI,MAAM,SAAS,SAAS,MAC1B,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAEH,IAAI,MAAM,UAAU,SAAS,OAC3B,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,eACP,OACA,UACa;CACb,MAAM,QAAqB,CAAC;CAE5B,IAAI,CAAC,YAAY,MAAM,aAAa,SAAS,WAAW,GACtD,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAEH,IAAI,MAAM,kBAAkB,SAAS,eACnC,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,cACP,OACA,UACa;CACb,MAAM,QAAqB,CAAC;CAE5B,IAAI,MAAM,SAAS,SAAS,MAC1B,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAEH,IAAI,MAAM,UAAU,SAAS,OAC3B,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,YAAY,OAAkB,UAAqC;CAC1E,MAAM,QAAqB,CAAC;CAE5B,IAAI,CAAC,YAAY,MAAM,aAAa,SAAS,WAAW,GACtD,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAGH,OAAO;AACT;AAEA,SAAS,eACP,OACA,UACa;CACb,MAAM,QAAqB,CAAC;CAE5B,IAAI,CAAC,YAAY,MAAM,QAAQ,SAAS,MAAM,GAC5C,MAAM,KAAK;EACT,OAAO;EACP,YAAY,MAAM;EAClB,eAAe,SAAS;CAC1B,CAAC;CAGH,OAAO;AACT;AAMA,IAAM,8BAAN,MAA+D;CACzC;CAApB,YAAY,SAAoC;EAA5B,KAAA,UAAA;CAA6B;;;;;CAMjD,OAAO,SAAiB,WAAmB,QAAyB;EAElE,MAAM,gBAAgB,UAAU,KAAK,QAAQ;EAE7C,IAAI,CAAC,eACH,MAAM,IAAI,MACR,oHACF;EAIF,MAAM,OAAO,WAAW,UAAU,aAAa;EAC/C,KAAK,OAAO,OAAO;EACnB,MAAM,oBAAoB,KAAK,OAAO,QAAQ;EAG9C,IAAI,UAAU,WAAW,kBAAkB,QACzC,OAAO;EAGT,IAAI,SAAS;EACb,KAAK,IAAI,IAAI,GAAG,IAAI,UAAU,QAAQ,KACpC,UAAU,UAAU,WAAW,CAAC,IAAI,kBAAkB,WAAW,CAAC;EAEpE,OAAO,WAAW;CACpB;CAEA,MAAM,SAA+B;EACnC,IAAI;EACJ,IAAI;GACF,OAAO,KAAK,MAAM,OAAO;EAC3B,SAAS,OAAO;GACd,MAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU;GAC3C,MAAM,IAAI,MAAM,uCAAuC,SAAS;EAClE;EAIA,MAAM,cADqB,KAAK,sBAAsB,CAAC,EAAA,CACjB,EAAE,EAAE,iBAAiB,WAAW;EAEtE,OAAO;GACL,MAAM,YAAY,aAAa;GAC/B,UAAU;GACV,2BAAW,IAAI,KAAK;GACpB,SAAS;GACT,cAAc,mBAAmB,YAAY,IAAI;GACjD,YAAY,YAAY;EAC1B;CACF;AACF;AAEA,SAAS,mBACP,MAC0C;CAC1C,QAAQ,MAAM,YAAY,GAA1B;EACE,KAAK,YACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,WACH,OAAO;EACT,KAAK,UACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,SACE;CACJ;AACF;AAMA,SAAS,iBAAiB,UAA4C;CACpE,OAAO;EACL,aAAa,SAAS;EACtB,kBAAkB,SAAS,QAAQ,EAAE,SAAS,SAAS,MAAM,IAAI,KAAA;EACjE,cAAc,SAAS,QACnB,EAAE,gBAAgB,SAAS,MAAM,IACjC,KAAA;EACJ,UAAU,gBAAgB,SAAS,cAAc;EACjD,UAAU,gBAAgB,SAAS,eAAe;EAClD,aAAa,SAAS,WAAW,EAAE,OAAO,SAAS,SAAS,IAAI,KAAA;CAClE;AACF;AAEA,SAAS,iBAAiB,KAAoC;CAC5D,OAAO;EACL,YAAY,IAAI;EAChB,UAAU;EACV,0BAAU,IAAI,KAAK;EACnB,MAAM,IAAI;EACV,OAAO,IAAI,kBAAkB;EAC7B,OAAO,IAAI,cAAc;EACzB,gBAAgB,gBAAgB,IAAI,QAAQ;EAC5C,SAAS,IAAI;EACb,UAAU,IAAI,aAAa;EAC3B,KAAK;CACP;AACF;AAEA,SAAS,gBAAgB,KAAkC;CACzD,MAAM,UAAU,IAAI,WAAW;CAC/B,MAAM,cAAc,IAAI,YAAY;CAEpC,OAAO;EACL,YAAY,IAAI;EAChB,UAAU;EACV,0BAAU,IAAI,KAAK;EACnB,eAAe,IAAI,aAAa;EAChC,oBAAoB,IAAI,aAAa,SAAS;EAC9C,WAAW,IAAI,KAAK,IAAI,OAAO;EAC/B,SAAS,IAAI,KAAK,IAAI,OAAO;EAC7B,UAAU,eAAe,IAAI,cAAc,YAAY;EACvD,WAAW,IAAI,cAAc,YAAY;EACzC;EACA,YAAY,cAAc;EAC1B;EACA,QAAQ,iBAAiB,SAAS,aAAa,IAAI,OAAO;EAC1D,UAAU,IAAI,aAAa,SAAS;EACpC,KAAK;CACP;AACF;AAEA,SAAS,iBACP,SACA,OACA,SAC2B;CAC3B,IAAI,YAAY,GAAG,OAAO;CAC1B,IAAI,UAAU,OAAO,OAAO;CAC5B,IAAI,IAAI,KAAK,OAAO,oBAAI,IAAI,KAAK,GAAG,OAAO;CAC3C,OAAO;AACT;AAEA,SAAS,eAAe,QAAsC;CAC5D,OAAO;EACL,aAAa,OAAO;EACpB,kBAAkB,OAAO,QAAQ,EAAE,SAAS,OAAO,MAAM,IAAI,KAAA;EAC7D,cAAc,OAAO,QAAQ,EAAE,gBAAgB,OAAO,MAAM,IAAI,KAAA;EAChE,UAAU,gBAAgB,OAAO,OAAO;EACxC,eAAe,OAAO;EACtB,aAAa,OAAO,WAAW,EAAE,OAAO,OAAO,SAAS,IAAI,KAAA;CAC9D;AACF;AAEA,SAAS,eAAe,KAAgC;CACtD,OAAO;EACL,YAAY,IAAI;EAChB,UAAU;EACV,0BAAU,IAAI,KAAK;EACnB,MAAM,IAAI;EACV,OAAO,IAAI,kBAAkB;EAC7B,OAAO,IAAI,cAAc;EACzB,SAAS,gBAAgB,IAAI,QAAQ;EACrC,SAAS,IAAI;EACb,UAAU,IAAI,aAAa;EAC3B,KAAK;CACP;AACF;AAEA,SAAS,aAAa,MAAgC;CACpD,OAAO;EACL,WAAW,EAAE,OAAO,KAAK,oBAAoB,KAAK,SAAS;EAC3D,WAAW,KAAK;EAChB,SAAS,gBAAgB,KAAK,QAAQ;EACtC,SAAS,gBAAgB,KAAK,OAAO;EACrC,MAAM,KAAK,UAAU,KAAK,MAAM,SAAS;GACvC,SAAS,MAAM;GACf,aAAa,KAAK;GAClB,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK;GAC5C,YAAY;GACZ,+BAA+B,EAC7B,YAAY,KAAK,cAAc,EAAE,OAAO,KAAK,YAAY,IAAI,KAAA,EAC/D;EACF,EAAE;EACF,aAAa,KAAK,WAAW,EAAE,OAAO,KAAK,SAAS,IAAI,KAAA;CAC1D;AACF;AAEA,SAAS,aAAa,KAA4B;CAChD,MAAM,UAAU,IAAI,WAAW;CAC/B,MAAM,cAAc,IAAI,YAAY;CAEpC,OAAO;EACL,YAAY,IAAI;EAChB,UAAU;EACV,0BAAU,IAAI,KAAK;EACnB,YAAY,IAAI;EAChB,kBAAkB,IAAI,WAAW,SAAS;EAC1C,UAAU,IAAI,KAAK,IAAI,OAAO;EAC9B,SAAS,IAAI,KAAK,IAAI,OAAO;EAC7B,UAAU,eAAe,IAAI,cAAc,YAAY;EACvD,WAAW,IAAI,cAAc,YAAY;EACzC;EACA,YAAY,cAAc;EAC1B;EACA,QAAQ,cAAc,SAAS,aAAa,IAAI,OAAO;EACvD,UAAU,IAAI,aAAa,SAAS;EACpC,KAAK;CACP;AACF;AAEA,SAAS,cACP,SACA,OACA,SACwB;CACxB,IAAI,YAAY,GAAG,OAAO;CAC1B,IAAI,IAAI,KAAK,OAAO,oBAAI,IAAI,KAAK,GAAG,OAAO;CAC3C,OAAO;AACT;AAEA,SAAS,gBAAgB,KAAkC;CACzD,OAAO;EACL,YAAY,IAAI;EAChB,UAAU;EACV,0BAAU,IAAI,KAAK;EACnB,QAAQ,IAAI,YAAY;EACxB,UAAU,IAAI,aAAa,SAAS;EACpC,QAAQ,IAAI,KAAK,IAAI,OAAO;EAC5B,QAAQ,IAAI,kBAAkB;EAC9B,eAAe,IAAI;EACnB,oBAAoB,IAAI,MAAM,QAAQ,MAAM,EAAE,SAAS,CAAC,CAAC,SACtD,MAAM,EAAE,WAAW,KAAK,MAAM,EAAE,KAAK,KAAK,CAAC,CAC9C;EACA,QAAQ;EACR,KAAK;CACP;AACF;AAEA,SAAS,gBAAgB,SAA2C;CAClE,IAAI,CAAC,SAAS,OAAO,KAAA;CACrB,OAAO;EACL,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,MAAM,QAAQ;EACd,wBAAwB,QAAQ;EAChC,YAAY,QAAQ;EACpB,SAAS,QAAQ;CACnB;AACF;AAEA,SAAS,gBAAgB,KAAuC;CAC9D,IAAI,CAAC,KAAK,OAAO,KAAA;CACjB,OAAO;EACL,SAAS,IAAI;EACb,SAAS,IAAI;EACb,MAAM,IAAI;EACV,OAAO,IAAI;EACX,YAAY,IAAI;EAChB,SAAS,IAAI;CACf;AACF"}
|