@happyvertical/accounting 0.103.6 → 0.103.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { n as QuickBooksWriteError } from "./errors-BHWEFjkq.js";
2
- import { r as validateQuickBooksInvoiceRequest, t as mapInvoiceToQBO } from "./invoice-request-CnemKZt9.js";
2
+ import { a as validateQuickBooksCreditMemoRequest, n as mapInvoiceToQBO, o as validateQuickBooksInvoiceRequest, t as mapCreditMemoToQBO } from "./invoice-request-s7E51rMr.js";
3
3
  import { createHmac } from "node:crypto";
4
4
  //#region src/providers/quickbooks/index.ts
5
5
  /**
@@ -40,6 +40,7 @@ var QuickBooksProvider = class {
40
40
  tokenExpiresAt = null;
41
41
  customers;
42
42
  invoices;
43
+ creditMemos;
43
44
  vendors;
44
45
  bills;
45
46
  payments;
@@ -53,6 +54,7 @@ var QuickBooksProvider = class {
53
54
  };
54
55
  this.customers = new QuickBooksCustomerOperations(this);
55
56
  this.invoices = new QuickBooksInvoiceOperations(this);
57
+ this.creditMemos = new QuickBooksCreditMemoOperations(this);
56
58
  this.vendors = new QuickBooksVendorOperations(this);
57
59
  this.bills = new QuickBooksBillOperations(this);
58
60
  this.payments = new QuickBooksPaymentOperations(this);
@@ -112,16 +114,17 @@ var QuickBooksProvider = class {
112
114
  /**
113
115
  * Make an authenticated request to the QBO API with timeout and retry support
114
116
  */
115
- async request(method, endpoint, body, invoiceRequest) {
117
+ async request(method, endpoint, body, createRequest) {
116
118
  const serializedBody = body === void 0 ? void 0 : JSON.stringify(body);
117
119
  const realmId = this.realmId;
118
120
  const environment = this.options.environment === "production" ? "production" : "sandbox";
119
- if (invoiceRequest) {
120
- if (method !== "POST" || endpoint !== "invoice") throw new Error("QuickBooks request identity is only supported for invoice creation");
121
- validateQuickBooksInvoiceRequest(invoiceRequest, realmId, environment, serializedBody);
121
+ if (createRequest) {
122
+ if (method !== "POST" || !["invoice", "creditmemo"].includes(endpoint)) throw new Error("QuickBooks request identity is only supported for invoice or credit memo creation");
123
+ if (endpoint === "invoice") validateQuickBooksInvoiceRequest(createRequest, realmId, environment, serializedBody);
124
+ else validateQuickBooksCreditMemoRequest(createRequest, realmId, environment, serializedBody);
122
125
  }
123
- const requestId = invoiceRequest?.requestId;
124
- const payloadHash = invoiceRequest?.payloadHash;
126
+ const requestId = createRequest?.requestId;
127
+ const payloadHash = createRequest?.payloadHash;
125
128
  const url = new URL(`${this.baseUrl}/v3/company/${realmId}/${endpoint}`);
126
129
  if (requestId) url.searchParams.set("requestid", requestId);
127
130
  const timeout = this.options.timeout ?? 3e4;
@@ -131,6 +134,7 @@ var QuickBooksProvider = class {
131
134
  "Vendor",
132
135
  "Bill",
133
136
  "Invoice",
137
+ "CreditMemo",
134
138
  "Payment"
135
139
  ].find((entity) => entity.toLowerCase() === endpoint.split(/[/?]/, 1)[0]);
136
140
  const accessToken = await this.ensureAccessToken();
@@ -292,6 +296,38 @@ var QuickBooksInvoiceOperations = class {
292
296
  });
293
297
  }
294
298
  };
299
+ var QuickBooksCreditMemoOperations = class {
300
+ provider;
301
+ constructor(provider) {
302
+ this.provider = provider;
303
+ }
304
+ async push(creditMemo) {
305
+ if (creditMemo.externalId && creditMemo.quickbooksCreditMemoRequest) throw new Error("QuickBooks credit memo request identity cannot be used for updates");
306
+ const mapped = mapCreditMemoToQBO(creditMemo);
307
+ if (creditMemo.quickbooksCreditMemoRequest && creditMemo.quickbooksCreditMemoRequest.creditedInvoiceExternalId !== creditMemo.creditedInvoiceExternalId) throw new Error("QuickBooks credit memo request linkage mismatch; reconcile the original request");
308
+ return {
309
+ action: "created",
310
+ externalId: (await this.provider.request("POST", "creditmemo", mapped, creditMemo.quickbooksCreditMemoRequest)).CreditMemo.Id,
311
+ syncedAt: /* @__PURE__ */ new Date()
312
+ };
313
+ }
314
+ async sync(creditMemo) {
315
+ if (!creditMemo.externalId) return this.push(creditMemo);
316
+ if (creditMemo.quickbooksCreditMemoRequest) throw new Error("QuickBooks credit memo request identity cannot be used for updates");
317
+ const mapped = mapCreditMemoToQBO(creditMemo);
318
+ const existing = await this.provider.request("GET", `creditmemo/${creditMemo.externalId}`);
319
+ await this.provider.request("POST", "creditmemo", {
320
+ ...mapped,
321
+ Id: creditMemo.externalId,
322
+ SyncToken: existing.CreditMemo.SyncToken
323
+ });
324
+ return {
325
+ action: "updated",
326
+ externalId: creditMemo.externalId,
327
+ syncedAt: /* @__PURE__ */ new Date()
328
+ };
329
+ }
330
+ };
295
331
  var QuickBooksVendorOperations = class {
296
332
  provider;
297
333
  constructor(provider) {
@@ -734,4 +770,4 @@ function mapQBOToAddress(qbo) {
734
770
  //#endregion
735
771
  export { QuickBooksProvider };
736
772
 
737
- //# sourceMappingURL=quickbooks-jX3_uKoz.js.map
773
+ //# sourceMappingURL=quickbooks-BgH78wY7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quickbooks-BgH78wY7.js","names":[],"sources":["../../src/providers/quickbooks/index.ts"],"sourcesContent":["/**\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\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 // 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 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?: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest,\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 (method !== 'POST' || !['invoice', 'creditmemo'].includes(endpoint)) {\n throw new Error(\n 'QuickBooks request identity is only supported for invoice or credit memo creation',\n );\n }\n 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 ].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 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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"}
package/dist/index.d.ts CHANGED
@@ -29,10 +29,10 @@
29
29
  * const report = await provider.audit.reconcileInvoices(localInvoices);
30
30
  * ```
31
31
  */
32
- import type { AccountingOptions, AccountingProvider, QuickBooksOptions, StripeOptions } from './types.js';
32
+ import type { AccountingOptions, AccountingProvider, CreditMemoOperations, QuickBooksOptions, StripeOptions } from './types.js';
33
33
  export type { QuickBooksOAuthErrorCode } from './errors.js';
34
34
  export { QuickBooksOAuthError, QuickBooksWriteError, StripeApiError, } from './errors.js';
35
- export { prepareQuickBooksInvoiceRequest } from './providers/quickbooks/invoice-request.js';
35
+ export { prepareQuickBooksCreditMemoRequest, prepareQuickBooksInvoiceRequest, } from './providers/quickbooks/invoice-request.js';
36
36
  export { createQuickBooksOAuthClient } from './providers/quickbooks/oauth.js';
37
37
  export * from './types.js';
38
38
  /**
@@ -43,6 +43,11 @@ export declare function isQuickBooksOptions(options: AccountingOptions): options
43
43
  * Type guard for Stripe options
44
44
  */
45
45
  export declare function isStripeOptions(options: AccountingOptions): options is StripeOptions;
46
+ /**
47
+ * Return the provider's credit-memo capability or fail explicitly before a
48
+ * caller attempts a write against a provider that does not implement it.
49
+ */
50
+ export declare function requireCreditMemoOperations(provider: Pick<AccountingProvider, 'type' | 'creditMemos'>): CreditMemoOperations;
46
51
  /**
47
52
  * Create an accounting provider instance
48
53
  *
@@ -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,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,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
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,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"}
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as QuickBooksWriteError, r as StripeApiError, t as QuickBooksOAuthError } from "./chunks/errors-BHWEFjkq.js";
2
- import { n as prepareQuickBooksInvoiceRequest } from "./chunks/invoice-request-CnemKZt9.js";
2
+ import { i as prepareQuickBooksInvoiceRequest, r as prepareQuickBooksCreditMemoRequest } from "./chunks/invoice-request-s7E51rMr.js";
3
3
  import { loadEnvConfig } from "@happyvertical/utils";
4
4
  import { createHash, timingSafeEqual } from "node:crypto";
5
5
  //#region src/providers/quickbooks/oauth.ts
@@ -185,6 +185,14 @@ function isStripeOptions(options) {
185
185
  return options.type === "stripe";
186
186
  }
187
187
  /**
188
+ * Return the provider's credit-memo capability or fail explicitly before a
189
+ * caller attempts a write against a provider that does not implement it.
190
+ */
191
+ function requireCreditMemoOperations(provider) {
192
+ if (!provider.creditMemos) throw new Error(`Accounting provider '${provider.type}' does not support credit memos`);
193
+ return provider.creditMemos;
194
+ }
195
+ /**
188
196
  * Create an accounting provider instance
189
197
  *
190
198
  * Factory function that creates a provider-specific implementation
@@ -229,7 +237,7 @@ async function getAccountingProvider(userOptions) {
229
237
  switch (options.type) {
230
238
  case "quickbooks": {
231
239
  if (!isQuickBooksOptions(options)) throw new Error("Invalid QuickBooks options");
232
- const { QuickBooksProvider } = await import("./chunks/quickbooks-jX3_uKoz.js");
240
+ const { QuickBooksProvider } = await import("./chunks/quickbooks-BgH78wY7.js");
233
241
  return new QuickBooksProvider(options);
234
242
  }
235
243
  case "stripe": {
@@ -245,6 +253,6 @@ async function getAccountingProvider(userOptions) {
245
253
  /** @internal */
246
254
  var PACKAGE_VERSION_INITIALIZED = true;
247
255
  //#endregion
248
- export { PACKAGE_VERSION_INITIALIZED, QuickBooksOAuthError, QuickBooksWriteError, StripeApiError, createQuickBooksOAuthClient, getAccountingProvider, isQuickBooksOptions, isStripeOptions, prepareQuickBooksInvoiceRequest };
256
+ export { PACKAGE_VERSION_INITIALIZED, QuickBooksOAuthError, QuickBooksWriteError, StripeApiError, createQuickBooksOAuthClient, getAccountingProvider, isQuickBooksOptions, isStripeOptions, prepareQuickBooksCreditMemoRequest, prepareQuickBooksInvoiceRequest, requireCreditMemoOperations };
249
257
 
250
258
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/providers/quickbooks/oauth.ts","../src/index.ts"],"sourcesContent":["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 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 { prepareQuickBooksInvoiceRequest } 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 * 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"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/providers/quickbooks/oauth.ts","../src/index.ts"],"sourcesContent":["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 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"],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
  * Implements the AccountingProvider interface for QuickBooks Online.
5
5
  * Uses the Intuit OAuth2 library for authentication and the QBO API for operations.
6
6
  */
7
- import type { AccountingProvider, AuditOperations, BillOperations, CustomerOperations, InvoiceOperations, PaymentOperations, QuickBooksInvoiceRequest, QuickBooksOptions, VendorOperations, WebhookOperations } from '../../types.js';
7
+ import type { AccountingProvider, AuditOperations, BillOperations, CreditMemoOperations, CustomerOperations, InvoiceOperations, PaymentOperations, QuickBooksCreditMemoRequest, QuickBooksInvoiceRequest, QuickBooksOptions, VendorOperations, WebhookOperations } from '../../types.js';
8
8
  /**
9
9
  * QuickBooks Online accounting provider
10
10
  */
@@ -15,6 +15,7 @@ export declare class QuickBooksProvider implements AccountingProvider {
15
15
  private tokenExpiresAt;
16
16
  readonly customers: CustomerOperations;
17
17
  readonly invoices: InvoiceOperations;
18
+ readonly creditMemos: CreditMemoOperations;
18
19
  readonly vendors: VendorOperations;
19
20
  readonly bills: BillOperations;
20
21
  readonly payments: PaymentOperations;
@@ -40,7 +41,7 @@ export declare class QuickBooksProvider implements AccountingProvider {
40
41
  /**
41
42
  * Make an authenticated request to the QBO API with timeout and retry support
42
43
  */
43
- request<T>(method: 'GET' | 'POST' | 'DELETE', endpoint: string, body?: unknown, invoiceRequest?: QuickBooksInvoiceRequest): Promise<T>;
44
+ request<T>(method: 'GET' | 'POST' | 'DELETE', endpoint: string, body?: unknown, createRequest?: QuickBooksInvoiceRequest | QuickBooksCreditMemoRequest): Promise<T>;
44
45
  /**
45
46
  * Execute a QBO query with pagination support
46
47
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,kBAAkB,EAIlB,eAAe,EAGf,cAAc,EAEd,kBAAkB,EAUlB,iBAAiB,EAGjB,iBAAiB,EACjB,wBAAwB,EACxB,iBAAiB,EAIjB,gBAAgB,EAEhB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AA+CxB;;GAEG;AACH,qBAAa,kBAAmB,YAAW,kBAAkB;IAC3D,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IAEtC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAqB;IAE3C,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAEzB,OAAO,EAAE,iBAAiB;IAiBtC;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAIpB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAyB1C;;OAEG;YACW,kBAAkB;IAgChC;;OAEG;IACG,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,EACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,EACd,cAAc,CAAC,EAAE,wBAAwB,GACxC,OAAO,CAAC,CAAC,CAAC;IA2Gb;;OAEG;IACG,QAAQ,CAAC,CAAC,EACd,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,EACpB,UAAU,SAAO,GAChB,OAAO,CAAC,CAAC,EAAE,CAAC;CA6BhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,kBAAkB,EAIlB,eAAe,EAGf,cAAc,EAEd,oBAAoB,EAEpB,kBAAkB,EAUlB,iBAAiB,EAGjB,iBAAiB,EACjB,2BAA2B,EAC3B,wBAAwB,EACxB,iBAAiB,EAIjB,gBAAgB,EAEhB,iBAAiB,EAClB,MAAM,gBAAgB,CAAC;AAiDxB;;GAEG;AACH,qBAAa,kBAAmB,YAAW,kBAAkB;IAC3D,QAAQ,CAAC,IAAI,EAAG,YAAY,CAAU;IAEtC,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,cAAc,CAAqB;IAE3C,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;gBAEzB,OAAO,EAAE,iBAAiB;IAkBtC;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAIpB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAyB1C;;OAEG;YACW,kBAAkB;IAgChC;;OAEG;IACG,OAAO,CAAC,CAAC,EACb,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,EACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,wBAAwB,GAAG,2BAA2B,GACrE,OAAO,CAAC,CAAC,CAAC;IAoHb;;OAEG;IACG,QAAQ,CAAC,CAAC,EACd,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,MAAM,EACpB,UAAU,SAAO,GAChB,OAAO,CAAC,CAAC,EAAE,CAAC;CA6BhB"}
@@ -1,32 +1,66 @@
1
- import type { InvoiceInput, QuickBooksInvoiceRequest } from '../../types.js';
1
+ import type { CreditMemoInput, InvoiceInput, QuickBooksCreditMemoRequest, QuickBooksInvoiceRequest } from '../../types.js';
2
+ interface QuickBooksSalesLine {
3
+ LineNum: number;
4
+ Description: string;
5
+ Amount: number;
6
+ DetailType: 'SalesItemLineDetail';
7
+ SalesItemLineDetail: {
8
+ Qty: number;
9
+ UnitPrice: number;
10
+ ItemRef?: {
11
+ value: string;
12
+ };
13
+ TaxCodeRef?: {
14
+ value: string;
15
+ };
16
+ TaxInclusiveAmt?: number;
17
+ };
18
+ }
19
+ interface QuickBooksTaxLine {
20
+ Amount: number;
21
+ DetailType: 'TaxLineDetail';
22
+ TaxLineDetail: {
23
+ TaxRateRef: {
24
+ value: string;
25
+ };
26
+ TaxPercent: number;
27
+ PercentBased: true;
28
+ };
29
+ }
2
30
  /** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */
3
31
  export declare function prepareQuickBooksInvoiceRequest(invoice: InvoiceInput, identity: Omit<QuickBooksInvoiceRequest, 'payloadHash'>): QuickBooksInvoiceRequest;
32
+ /** Prepare once, persist before sending, and reuse unchanged. Performs no I/O. */
33
+ export declare function prepareQuickBooksCreditMemoRequest(creditMemo: CreditMemoInput, identity: Omit<QuickBooksCreditMemoRequest, 'payloadHash' | 'creditedInvoiceExternalId'>): QuickBooksCreditMemoRequest;
4
34
  export declare function validateQuickBooksInvoiceRequest(request: QuickBooksInvoiceRequest, realmId: string, environment: 'sandbox' | 'production', payload: string | undefined): void;
5
- export declare function mapInvoiceToQBO(invoice: InvoiceInput): {
35
+ export declare function validateQuickBooksCreditMemoRequest(request: QuickBooksCreditMemoRequest, realmId: string, environment: 'sandbox' | 'production', payload: string | undefined): void;
36
+ declare function basePayload(input: Pick<InvoiceInput, 'customerId' | 'customerExternalId' | 'issueDate' | 'subtotal' | 'taxAmount' | 'totalAmount' | 'currency' | 'memo' | 'lineItems' | 'quickbooksMapping'>, number: string, dueDate?: Date): {
37
+ Line: QuickBooksSalesLine[];
38
+ GlobalTaxCalculation: "TaxExcluded" | "TaxInclusive" | "NotApplicable" | undefined;
39
+ TxnTaxDetail: {
40
+ TaxLine?: QuickBooksTaxLine[] | undefined;
41
+ TotalTax: number;
42
+ } | undefined;
43
+ CurrencyRef: {
44
+ value: string;
45
+ } | undefined;
46
+ CustomerMemo: {
47
+ value: string;
48
+ } | undefined;
49
+ DueDate?: string | undefined;
6
50
  CustomerRef: {
7
51
  value: string;
8
52
  };
9
53
  DocNumber: string;
10
54
  TxnDate: string;
55
+ };
56
+ export declare function mapInvoiceToQBO(invoice: InvoiceInput): ReturnType<typeof basePayload> & {
11
57
  DueDate: string;
12
- Line: {
13
- LineNum: number;
14
- Description: string;
15
- Amount: number;
16
- DetailType: "SalesItemLineDetail";
17
- SalesItemLineDetail: {
18
- Qty: number;
19
- UnitPrice: number;
20
- ItemRef: {
21
- value: string;
22
- } | undefined;
23
- TaxCodeRef: {
24
- value: string;
25
- } | undefined;
26
- };
27
- }[];
28
- GlobalTaxCalculation: "TaxExcluded" | "NotApplicable" | undefined;
58
+ };
59
+ export declare function mapCreditMemoToQBO(creditMemo: CreditMemoInput): {
60
+ Line: QuickBooksSalesLine[];
61
+ GlobalTaxCalculation: "TaxExcluded" | "TaxInclusive" | "NotApplicable" | undefined;
29
62
  TxnTaxDetail: {
63
+ TaxLine?: QuickBooksTaxLine[] | undefined;
30
64
  TotalTax: number;
31
65
  } | undefined;
32
66
  CurrencyRef: {
@@ -35,5 +69,12 @@ export declare function mapInvoiceToQBO(invoice: InvoiceInput): {
35
69
  CustomerMemo: {
36
70
  value: string;
37
71
  } | undefined;
72
+ DueDate?: string | undefined;
73
+ CustomerRef: {
74
+ value: string;
75
+ };
76
+ DocNumber: string;
77
+ TxnDate: string;
38
78
  };
79
+ export {};
39
80
  //# sourceMappingURL=invoice-request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"invoice-request.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/invoice-request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAG7E,kFAAkF;AAClF,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,IAAI,CAAC,wBAAwB,EAAE,aAAa,CAAC,GACtD,wBAAwB,CAY1B;AAMD,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,wBAAwB,EACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,IAAI,CA4BN;AASD,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiJpD"}
1
+ {"version":3,"file":"invoice-request.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/invoice-request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EAEZ,2BAA2B,EAC3B,wBAAwB,EACzB,MAAM,gBAAgB,CAAC;AAYxB,UAAU,mBAAmB;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,qBAAqB,CAAC;IAClC,mBAAmB,EAAE;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC5B,UAAU,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,eAAe,CAAC;IAC5B,aAAa,EAAE;QACb,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,IAAI,CAAC;KACpB,CAAC;CACH;AAcD,kFAAkF;AAClF,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,IAAI,CAAC,wBAAwB,EAAE,aAAa,CAAC,GACtD,wBAAwB,CAI1B;AAED,kFAAkF;AAClF,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,eAAe,EAC3B,QAAQ,EAAE,IAAI,CACZ,2BAA2B,EAC3B,aAAa,GAAG,2BAA2B,CAC5C,GACA,2BAA2B,CAa7B;AA8CD,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,wBAAwB,EACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,IAAI,CAEN;AAED,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,2BAA2B,EACpC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,SAAS,GAAG,YAAY,EACrC,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,IAAI,CAEN;AAqqBD,iBAAS,WAAW,CAClB,KAAK,EAAE,IAAI,CACT,YAAY,EACV,YAAY,GACZ,oBAAoB,GACpB,WAAW,GACX,UAAU,GACV,WAAW,GACX,aAAa,GACb,UAAU,GACV,MAAM,GACN,WAAW,GACX,mBAAmB,CACtB,EACD,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,IAAI;;;;;;;;;;;;;;;;;;;EAmBf;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAa9C,UAAU,CAAC,OAAO,WAAW,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAC1D;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe;;;;;;;;;;;;;;;;;;;EAU7D"}
@@ -1,3 +1,9 @@
1
+ /** ISO minor-unit factor, or undefined when the code is unknown or omitted. */
2
+ export declare function currencyMinorUnitFactor(currency: string | undefined): number | undefined;
3
+ /** True only for a finite amount exactly representable on the ISO minor-unit grid. */
4
+ export declare function isCurrencyMinorUnit(amount: number, currency: string | undefined): boolean;
5
+ /** Round a finite major-unit amount half-up to a known ISO currency grid. */
6
+ export declare function roundCurrencyAmount(amount: number, currency: string | undefined): number | undefined;
1
7
  /** Admit only the exact half-up minor-unit result; never rewrite caller money. */
2
8
  export declare function matchesCurrencyRoundedLineAmount(quantity: number, unitPrice: number, amount: number, currency: string | undefined): boolean;
3
9
  //# sourceMappingURL=line-amount.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"line-amount.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/line-amount.ts"],"names":[],"mappings":"AAkCA,kFAAkF;AAClF,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAiBT"}
1
+ {"version":3,"file":"line-amount.d.ts","sourceRoot":"","sources":["../../../src/providers/quickbooks/line-amount.ts"],"names":[],"mappings":"AAoBA,+EAA+E;AAC/E,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAIpB;AAED,sFAAsF;AACtF,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAQT;AAED,6EAA6E;AAC7E,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,MAAM,GAAG,SAAS,CAapB;AAgBD,kFAAkF;AAClF,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAiBT"}