@happyvertical/smrt-commerce 0.57.3 → 0.57.5

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.
Files changed (168) hide show
  1. package/AGENTS.md +20 -0
  2. package/README.md +130 -0
  3. package/agents/accounting-snapshot-mapper.md +11 -0
  4. package/agents/contract-billing-schedules.md +67 -0
  5. package/agents/contract-money.md +81 -0
  6. package/agents/customer-funds.md +96 -0
  7. package/agents/historical-sales.md +150 -0
  8. package/agents/money-calculator.md +36 -0
  9. package/agents/money-model.md +6 -3
  10. package/agents/observed-purchase-prices.md +37 -0
  11. package/agents/ordinary-accounting.md +72 -0
  12. package/agents/payment-allocations.md +59 -0
  13. package/agents/received-sales-contract-money.md +38 -0
  14. package/dist/accounting-snapshot.d.ts +8 -1
  15. package/dist/accounting-snapshot.d.ts.map +1 -1
  16. package/dist/accounting-steps-internal.d.ts +49 -0
  17. package/dist/accounting-steps-internal.d.ts.map +1 -0
  18. package/dist/allocation-integrity.d.ts.map +1 -1
  19. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js → ContractLineItemCollection-D5hBzrct.js} +6 -6
  20. package/dist/chunks/{ContractLineItemCollection-BZcrlrrY.js.map → ContractLineItemCollection-D5hBzrct.js.map} +1 -1
  21. package/dist/chunks/DocumentTaxCollection-C6cI5U89.js +4395 -0
  22. package/dist/chunks/DocumentTaxCollection-C6cI5U89.js.map +1 -0
  23. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js +170 -0
  24. package/dist/chunks/HistoricalCustomerFundsCollections-B5x8gTW3.js.map +1 -0
  25. package/dist/chunks/{InvoiceCollection-cinzAqt6.js → InvoiceCollection-BolwughC.js} +133 -18
  26. package/dist/chunks/InvoiceCollection-BolwughC.js.map +1 -0
  27. package/dist/chunks/{TaxCodeCollection-DaBOPG9c.js → TaxCodeCollection-CW-tWjkU.js} +3 -4
  28. package/dist/chunks/TaxCodeCollection-CW-tWjkU.js.map +1 -0
  29. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js → TaxComponentCollection-BiJ9aAe8.js} +3 -3
  30. package/dist/chunks/{TaxComponentCollection-C4zxnyVu.js.map → TaxComponentCollection-BiJ9aAe8.js.map} +1 -1
  31. package/dist/chunks/{allocation-integrity-WmWyXhtG.js → allocation-integrity-CH-i-hsY.js} +7 -7
  32. package/dist/chunks/{allocation-integrity-WmWyXhtG.js.map → allocation-integrity-CH-i-hsY.js.map} +1 -1
  33. package/dist/chunks/{contract-money-EuToOghh.js → contract-money-BMsq4cpL.js} +45 -12
  34. package/dist/chunks/contract-money-BMsq4cpL.js.map +1 -0
  35. package/dist/chunks/customer-funds-internal-BQzoJXK5.js +24 -0
  36. package/dist/chunks/customer-funds-internal-BQzoJXK5.js.map +1 -0
  37. package/dist/chunks/{detect-CY9ufaFb.js → detect-DAE-_NAk.js} +5 -2
  38. package/dist/chunks/{detect-CY9ufaFb.js.map → detect-DAE-_NAk.js.map} +1 -1
  39. package/dist/chunks/historical-commerce-internal-C9ButfuH.js +18 -0
  40. package/dist/chunks/historical-commerce-internal-C9ButfuH.js.map +1 -0
  41. package/dist/chunks/{invoice-posting-C2i5dOVZ.js → invoice-posting-IXic4UEP.js} +5 -5
  42. package/dist/chunks/invoice-posting-IXic4UEP.js.map +1 -0
  43. package/dist/chunks/retention-accounting-c7kY7gFU.js +2738 -0
  44. package/dist/chunks/retention-accounting-c7kY7gFU.js.map +1 -0
  45. package/dist/chunks/retention-accounting-internal-DNxLLVvK.js +30 -0
  46. package/dist/chunks/retention-accounting-internal-DNxLLVvK.js.map +1 -0
  47. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js → tenant-money-barrier-DEVLrpaB.js} +5 -5
  48. package/dist/chunks/{tenant-money-barrier-6TlqUeVj.js.map → tenant-money-barrier-DEVLrpaB.js.map} +1 -1
  49. package/dist/chunks/types-Bbm0Xflc.js.map +1 -1
  50. package/dist/collections/DocumentTaxCollection.d.ts +4 -1
  51. package/dist/collections/DocumentTaxCollection.d.ts.map +1 -1
  52. package/dist/collections/HistoricalCustomerFundsCollections.d.ts +10 -0
  53. package/dist/collections/HistoricalCustomerFundsCollections.d.ts.map +1 -0
  54. package/dist/collections/HistoricalSalesLineCollection.d.ts +6 -0
  55. package/dist/collections/HistoricalSalesLineCollection.d.ts.map +1 -0
  56. package/dist/collections/PaymentAllocationCollection.d.ts +2 -6
  57. package/dist/collections/PaymentAllocationCollection.d.ts.map +1 -1
  58. package/dist/collections/PurchasePriceObservationCollection.d.ts +6 -0
  59. package/dist/collections/PurchasePriceObservationCollection.d.ts.map +1 -0
  60. package/dist/collections/index.d.ts +1 -0
  61. package/dist/collections/index.d.ts.map +1 -1
  62. package/dist/contract-billing-schedule.d.ts +83 -0
  63. package/dist/contract-billing-schedule.d.ts.map +1 -0
  64. package/dist/contract-money.d.ts +2 -0
  65. package/dist/contract-money.d.ts.map +1 -1
  66. package/dist/customer-funds-internal.d.ts +6 -0
  67. package/dist/customer-funds-internal.d.ts.map +1 -0
  68. package/dist/customer-funds.d.ts +108 -0
  69. package/dist/customer-funds.d.ts.map +1 -0
  70. package/dist/document-money.d.ts +11 -0
  71. package/dist/document-money.d.ts.map +1 -1
  72. package/dist/historical-commerce-internal.d.ts +3 -0
  73. package/dist/historical-commerce-internal.d.ts.map +1 -0
  74. package/dist/historical-customer-funds-types.d.ts +113 -0
  75. package/dist/historical-customer-funds-types.d.ts.map +1 -0
  76. package/dist/historical-customer-funds.d.ts +23 -0
  77. package/dist/historical-customer-funds.d.ts.map +1 -0
  78. package/dist/historical-funds-internal.d.ts +5 -0
  79. package/dist/historical-funds-internal.d.ts.map +1 -0
  80. package/dist/historical-sales-money.d.ts +22 -0
  81. package/dist/historical-sales-money.d.ts.map +1 -0
  82. package/dist/historical-sales-reports.d.ts +31 -0
  83. package/dist/historical-sales-reports.d.ts.map +1 -0
  84. package/dist/historical-sales-types.d.ts +106 -0
  85. package/dist/historical-sales-types.d.ts.map +1 -0
  86. package/dist/historical-sales-validation.d.ts +12 -0
  87. package/dist/historical-sales-validation.d.ts.map +1 -0
  88. package/dist/index.d.ts +22 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +1668 -1643
  91. package/dist/index.js.map +1 -1
  92. package/dist/invoice-accounting-sync.d.ts +0 -1
  93. package/dist/invoice-accounting-sync.d.ts.map +1 -1
  94. package/dist/invoice-mcp.d.ts.map +1 -1
  95. package/dist/invoice-posting.d.ts.map +1 -1
  96. package/dist/invoice-retention.d.ts +16 -0
  97. package/dist/invoice-retention.d.ts.map +1 -0
  98. package/dist/invoices.d.ts +3 -0
  99. package/dist/invoices.d.ts.map +1 -1
  100. package/dist/invoices.js +2 -2
  101. package/dist/manifest.json +7626 -4446
  102. package/dist/models/Contract.d.ts +14 -0
  103. package/dist/models/Contract.d.ts.map +1 -1
  104. package/dist/models/DocumentTax.d.ts +2 -0
  105. package/dist/models/DocumentTax.d.ts.map +1 -1
  106. package/dist/models/HistoricalCustomerFunds.d.ts +36 -0
  107. package/dist/models/HistoricalCustomerFunds.d.ts.map +1 -0
  108. package/dist/models/HistoricalCustomerFundsAllocation.d.ts +32 -0
  109. package/dist/models/HistoricalCustomerFundsAllocation.d.ts.map +1 -0
  110. package/dist/models/HistoricalSalesLine.d.ts +29 -0
  111. package/dist/models/HistoricalSalesLine.d.ts.map +1 -0
  112. package/dist/models/Invoice.d.ts +12 -1
  113. package/dist/models/Invoice.d.ts.map +1 -1
  114. package/dist/models/Payment.d.ts +9 -1
  115. package/dist/models/Payment.d.ts.map +1 -1
  116. package/dist/models/PaymentAllocation.d.ts +3 -1
  117. package/dist/models/PaymentAllocation.d.ts.map +1 -1
  118. package/dist/models/PaymentIntent.d.ts.map +1 -1
  119. package/dist/models/Payout.d.ts.map +1 -1
  120. package/dist/models/PurchasePriceObservation.d.ts +15 -0
  121. package/dist/models/PurchasePriceObservation.d.ts.map +1 -0
  122. package/dist/models/TaxCode.d.ts +1 -1
  123. package/dist/models/TaxCode.d.ts.map +1 -1
  124. package/dist/models/index.d.ts +1 -0
  125. package/dist/models/index.d.ts.map +1 -1
  126. package/dist/money.d.ts +5 -1
  127. package/dist/money.d.ts.map +1 -1
  128. package/dist/money.js +62 -15
  129. package/dist/money.js.map +1 -1
  130. package/dist/observed-purchase-price-internal.d.ts +3 -0
  131. package/dist/observed-purchase-price-internal.d.ts.map +1 -0
  132. package/dist/observed-purchase-price.d.ts +71 -0
  133. package/dist/observed-purchase-price.d.ts.map +1 -0
  134. package/dist/ordinary-accounting-internal.d.ts +3 -0
  135. package/dist/ordinary-accounting-internal.d.ts.map +1 -0
  136. package/dist/ordinary-accounting.d.ts +104 -0
  137. package/dist/ordinary-accounting.d.ts.map +1 -0
  138. package/dist/received-purchase-money.d.ts +87 -0
  139. package/dist/received-purchase-money.d.ts.map +1 -0
  140. package/dist/recipes.d.ts +4 -1
  141. package/dist/recipes.d.ts.map +1 -1
  142. package/dist/retention-accounting-internal.d.ts +3 -0
  143. package/dist/retention-accounting-internal.d.ts.map +1 -0
  144. package/dist/retention-accounting.d.ts +143 -0
  145. package/dist/retention-accounting.d.ts.map +1 -0
  146. package/dist/retention-money.d.ts +43 -0
  147. package/dist/retention-money.d.ts.map +1 -0
  148. package/dist/smrt-knowledge.json +1872 -113
  149. package/dist/tax/cookbook.d.ts.map +1 -1
  150. package/dist/tax-summary.d.ts +1 -0
  151. package/dist/tax-summary.d.ts.map +1 -1
  152. package/dist/types/index.d.ts +20 -1
  153. package/dist/types/index.d.ts.map +1 -1
  154. package/package.json +16 -16
  155. package/dist/chunks/CustomerCollection-BIPH2ZUx.js +0 -99
  156. package/dist/chunks/CustomerCollection-BIPH2ZUx.js.map +0 -1
  157. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js +0 -1666
  158. package/dist/chunks/DocumentTaxCollection-DDzlywMW.js.map +0 -1
  159. package/dist/chunks/InvoiceCollection-cinzAqt6.js.map +0 -1
  160. package/dist/chunks/TaxCodeCollection-DaBOPG9c.js.map +0 -1
  161. package/dist/chunks/VendorCollection-D6ZcUYy8.js +0 -100
  162. package/dist/chunks/VendorCollection-D6ZcUYy8.js.map +0 -1
  163. package/dist/chunks/calculations-C9daQLsh.js +0 -82
  164. package/dist/chunks/calculations-C9daQLsh.js.map +0 -1
  165. package/dist/chunks/contract-money-EuToOghh.js.map +0 -1
  166. package/dist/chunks/document-money-DV5t4vlK.js +0 -1186
  167. package/dist/chunks/document-money-DV5t4vlK.js.map +0 -1
  168. package/dist/chunks/invoice-posting-C2i5dOVZ.js.map +0 -1
package/dist/money.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"money.js","names":["tax"],"sources":["../src/money.ts"],"sourcesContent":["/** Exact, transport-neutral commercial document money calculation. */\n\nimport { ISO_4217_MINOR_UNITS } from '@happyvertical/smrt-ui/currency';\nimport {\n allocateSignedRationals,\n roundSignedRational,\n} from './money-rational.js';\n\n/** Throw unless every named model value is a finite integer minor-unit amount. */\nexport function assertIntegerMinorUnits(\n context: string,\n label: string,\n entries: ReadonlyArray<readonly [string, number]>,\n): void {\n for (const [field, value] of entries) {\n if (!Number.isFinite(value) || !Number.isInteger(value)) {\n throw new Error(\n `${context} ${label}: ${field} must be an integer number of minor ` +\n `units (cents, satoshis) — got ${value}. Money is exact: $19.99 is ` +\n '1999, not 19.99.',\n );\n }\n }\n}\n\nexport type LineAmountType = 'exclusive' | 'inclusive' | 'none';\nexport type TaxRoundingScope = 'line' | 'document';\nexport type TaxCodeKind = 'taxable' | 'zero-rated' | 'exempt' | 'out-of-scope';\nexport type TaxCodeAppliesTo = 'sales' | 'purchases' | 'both';\n\nexport type MoneyValidationCode =\n | 'DISCOUNT_BOTH_FORMS'\n | 'DISCOUNT_EXCEEDS_GROSS'\n | 'DISCOUNT_SIGN'\n | 'PERCENT_OUT_OF_RANGE'\n | 'COMPOUND_UNSUPPORTED'\n | 'INVALID_MONEY_INPUT'\n | 'TAX_CODE_DUPLICATE_COMPONENT'\n | 'TAX_CODE_KIND'\n | 'TAX_CODE_NON_TAXABLE_COMPONENTS'\n | 'TAX_CODE_NOT_FOUND'\n | 'TAX_CODE_TAXABLE_EMPTY'\n | 'TAX_COMPONENT_RATE_CONFLICT'\n | 'TAX_CODE_INACTIVE'\n | 'TAX_CODE_SCOPE'\n | 'UNSAFE_MONEY'\n | 'FROZEN_DOCUMENT'\n | 'CURRENCY_MISMATCH'\n | 'ACCOUNTING_SYNC_IN_PROGRESS'\n | 'ACCOUNTING_SYNC_RECONCILIATION_REQUIRED'\n | 'ACCOUNTING_SYNC_UNSUPPORTED'\n | 'CREDIT_EXCEEDS_LINE'\n | 'CREDIT_TARGET_NOT_ISSUED';\n\n/** Stable validation error shared by model, editor, and transport adapters. */\nexport class MoneyValidationError extends Error {\n override readonly name = 'MoneyValidationError';\n /** Explicit marker consumed by public transports that preserve typed errors. */\n readonly publicMessage: string;\n\n constructor(\n readonly code: MoneyValidationCode,\n message: string,\n ) {\n super(message);\n this.publicMessage = message;\n }\n}\n\nexport interface TaxComponentInput {\n taxComponentId: string;\n /** Exact percent: \"7\" means 7%; at most six fractional digits. */\n percent: string;\n compound: boolean;\n}\n\nexport interface MoneyTaxCodeInput {\n id: string;\n kind: TaxCodeKind;\n components: readonly TaxComponentInput[];\n}\n\nexport interface ResolvableTaxCodeInput extends MoneyTaxCodeInput {\n active: boolean;\n appliesTo: TaxCodeAppliesTo;\n}\n\nexport type MoneyDiscountInput =\n | { kind: 'none' }\n | { kind: 'percent'; rate: string }\n | { kind: 'amount'; minor: number };\n\nexport interface MoneyLineInput {\n id: string;\n /** Nonnegative decimal quantity with at most six fractional digits. */\n quantity: number;\n /** Signed safe integer minor units. */\n unitPrice: number;\n discount: MoneyDiscountInput;\n /** Explicit tax-exclusive basis for credit-note amount allocations. */\n netAmountMinor?: number;\n /** Null means no code resolved; `none` pricing requires an out-of-scope code. */\n taxCode: MoneyTaxCodeInput | null;\n}\n\nexport interface MoneyLineResult {\n id: string;\n grossMinor: number;\n discountMinor: number;\n amountMinor: number;\n components: { taxComponentId: string; taxMinor: number }[];\n taxMinor: number;\n netMinor: number;\n}\n\nexport interface MoneyDocumentTaxResult {\n /** Null records an unassigned line without inventing a persisted tax-code ID. */\n taxCodeId: string | null;\n taxComponentId: string | null;\n taxableMinor: number;\n taxMinor: number;\n}\n\nexport interface MoneyDocumentResult {\n lines: MoneyLineResult[];\n subtotalMinor: number;\n discountTotalMinor: number;\n taxMinor: number;\n totalMinor: number;\n taxes: MoneyDocumentTaxResult[];\n}\n\nexport type TaxCodeResolutionSource =\n | 'line'\n | 'exempt-customer'\n | 'product'\n | 'customer'\n | 'app'\n | 'none';\n\nexport interface ResolveLineTaxCodeInput {\n lineAmountType: LineAmountType;\n lineOverride?: string | null;\n}\n\nexport interface ResolveLineTaxCodeContext {\n direction: 'sales' | 'purchases';\n codes: Readonly<Record<string, ResolvableTaxCodeInput>>;\n customerTaxExempt: boolean;\n exemptCodeId?: string | null;\n productCodeId?: string | null;\n partyCodeId?: string | null;\n appDefaultCodeId?: string | null;\n outOfScopeCodeId?: string | null;\n}\n\nexport interface ResolvedLineTaxCode {\n taxCode: ResolvableTaxCodeInput | null;\n source: TaxCodeResolutionSource;\n}\n\nconst PERCENT_SCALE = 1_000_000n;\nconst PERCENT_DENOMINATOR = 100n * PERCENT_SCALE;\nconst MAX_SAFE_MONEY = BigInt(Number.MAX_SAFE_INTEGER);\nconst IDENTIFIER = /^\\S(?:.*\\S)?$/;\n\nfunction validationError(code: MoneyValidationCode, message: string): never {\n throw new MoneyValidationError(code, message);\n}\n\nfunction assertIdentifier(value: string, label: string): void {\n if (typeof value !== 'string' || !IDENTIFIER.test(value))\n validationError(\n 'INVALID_MONEY_INPUT',\n `${label} must be a nonempty string`,\n );\n}\n\nfunction safeMoney(value: bigint): number {\n if (value > MAX_SAFE_MONEY || value < -MAX_SAFE_MONEY)\n validationError('UNSAFE_MONEY', 'Money exceeds safe integer minor units');\n return Number(value);\n}\n\nfunction money(value: number): bigint {\n if (!Number.isSafeInteger(value))\n validationError('UNSAFE_MONEY', 'Money must be safe integer minor units');\n return BigInt(value);\n}\n\ninterface ExactDecimal {\n coefficient: bigint;\n scale: bigint;\n}\n\nfunction numberDecimal(value: number, precision: number): ExactDecimal {\n if (!Number.isFinite(value) || value < 0 || value > Number.MAX_SAFE_INTEGER)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Quantity is outside the supported range',\n );\n const [mantissa, exponentText = '0'] = value.toString().split('e');\n const [whole, fraction = ''] = mantissa.split('.');\n const places = fraction.length - Number(exponentText);\n if (places > precision)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Quantity exceeds the supported decimal precision',\n );\n const coefficient = BigInt(whole + fraction);\n return places < 0\n ? { coefficient: coefficient * 10n ** BigInt(-places), scale: 1n }\n : { coefficient, scale: 10n ** BigInt(places) };\n}\n\nfunction percentUnits(value: string): bigint {\n if (\n typeof value !== 'string' ||\n !/^(?:0|[1-9]\\d{0,2})(?:\\.\\d{1,6})?$/.test(value)\n )\n validationError(\n 'PERCENT_OUT_OF_RANGE',\n 'Percent must be an exact decimal from 0 through 100 with at most six fractional digits',\n );\n const [whole, fraction = ''] = value.split('.');\n const units = BigInt(whole) * PERCENT_SCALE + BigInt(fraction.padEnd(6, '0'));\n if (units > PERCENT_DENOMINATOR)\n validationError('PERCENT_OUT_OF_RANGE', 'Percent exceeds 100');\n return units;\n}\n\nfunction validateTaxCode(\n code: MoneyTaxCodeInput,\n rates: Map<string, bigint>,\n): { taxComponentId: string; rate: bigint }[] {\n if (!code || typeof code !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax code must be an object');\n assertIdentifier(code.id, 'Tax code ID');\n if (\n code.kind !== 'taxable' &&\n code.kind !== 'zero-rated' &&\n code.kind !== 'exempt' &&\n code.kind !== 'out-of-scope'\n )\n validationError('TAX_CODE_KIND', 'Unknown tax code kind');\n if (!Array.isArray(code.components))\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax code components must be an array',\n );\n if (code.kind === 'taxable' && code.components.length === 0)\n validationError(\n 'TAX_CODE_TAXABLE_EMPTY',\n 'Taxable codes require at least one component',\n );\n if (code.kind !== 'taxable' && code.components.length !== 0)\n validationError(\n 'TAX_CODE_NON_TAXABLE_COMPONENTS',\n 'Non-taxable codes cannot contain components',\n );\n const seen = new Set<string>();\n return code.components.map((component) => {\n if (!component || typeof component !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax component must be an object');\n assertIdentifier(component.taxComponentId, 'Tax component ID');\n if (seen.has(component.taxComponentId))\n validationError(\n 'TAX_CODE_DUPLICATE_COMPONENT',\n 'Duplicate tax component within code',\n );\n seen.add(component.taxComponentId);\n if (typeof component.compound !== 'boolean')\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax component compound must be boolean',\n );\n if (component.compound)\n validationError(\n 'COMPOUND_UNSUPPORTED',\n 'Compound tax components are not supported',\n );\n const rate = percentUnits(component.percent);\n const existing = rates.get(component.taxComponentId);\n if (existing !== undefined && existing !== rate)\n validationError(\n 'TAX_COMPONENT_RATE_CONFLICT',\n 'Shared tax component has conflicting percentages',\n );\n rates.set(component.taxComponentId, rate);\n return { taxComponentId: component.taxComponentId, rate };\n });\n}\n\nfunction discountFor(gross: bigint, discount: MoneyDiscountInput): bigint {\n if (!discount || typeof discount !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Discount must be a tagged object');\n const runtime = discount as MoneyDiscountInput & {\n rate?: unknown;\n minor?: unknown;\n };\n if (runtime.rate !== undefined && runtime.minor !== undefined)\n validationError(\n 'DISCOUNT_BOTH_FORMS',\n 'A discount cannot include both percent and amount forms',\n );\n let result: bigint;\n if (discount.kind === 'none') {\n if (runtime.rate !== undefined || runtime.minor !== undefined)\n validationError(\n 'DISCOUNT_BOTH_FORMS',\n 'A none discount cannot include percent or amount values',\n );\n result = 0n;\n } else if (discount.kind === 'percent') {\n result = roundSignedRational(\n gross * percentUnits(discount.rate),\n PERCENT_DENOMINATOR,\n );\n } else if (discount.kind === 'amount') {\n result = money(discount.minor);\n } else {\n validationError('INVALID_MONEY_INPUT', 'Unknown discount kind');\n }\n if (result !== 0n && gross !== 0n && result < 0n !== gross < 0n)\n validationError(\n 'DISCOUNT_SIGN',\n 'Discount amount must carry the sign of gross',\n );\n if (gross === 0n && result !== 0n)\n validationError('DISCOUNT_SIGN', 'A zero gross cannot carry a discount');\n const magnitude = (value: bigint) => (value < 0n ? -value : value);\n if (magnitude(result) > magnitude(gross))\n validationError('DISCOUNT_EXCEEDS_GROSS', 'Discount cannot exceed gross');\n return result;\n}\n\nfunction validateDocumentInput(input: {\n currency: string;\n lineAmountType: LineAmountType;\n roundingScope: TaxRoundingScope;\n lines: readonly MoneyLineInput[];\n}): void {\n if (!input || typeof input !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Money input must be an object');\n if (\n typeof input.currency !== 'string' ||\n !/^[A-Z]{3}$/.test(input.currency) ||\n !ISO_4217_MINOR_UNITS.has(input.currency) ||\n ISO_4217_MINOR_UNITS.get(input.currency) === null\n )\n validationError(\n 'CURRENCY_MISMATCH',\n 'Currency must be a supported uppercase ISO 4217 code with minor units',\n );\n if (\n input.lineAmountType !== 'exclusive' &&\n input.lineAmountType !== 'inclusive' &&\n input.lineAmountType !== 'none'\n )\n validationError('INVALID_MONEY_INPUT', 'Unknown line amount type');\n if (input.roundingScope !== 'line' && input.roundingScope !== 'document')\n validationError('INVALID_MONEY_INPUT', 'Unknown tax rounding scope');\n if (!Array.isArray(input.lines))\n validationError('INVALID_MONEY_INPUT', 'Lines must be an array');\n}\n\n/** Calculate exact line amounts, per-component tax, and document totals. */\nexport function calculateMoneyDocument(input: {\n currency: string;\n lineAmountType: LineAmountType;\n roundingScope: TaxRoundingScope;\n lines: readonly MoneyLineInput[];\n}): MoneyDocumentResult {\n validateDocumentInput(input);\n const ids = new Set<string>();\n const rates = new Map<string, bigint>();\n const working = input.lines.map((line) => {\n if (!line || typeof line !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Money line must be an object');\n assertIdentifier(line.id, 'Line ID');\n if (ids.has(line.id))\n validationError('INVALID_MONEY_INPUT', 'Duplicate money line ID');\n ids.add(line.id);\n const explicitNet =\n line.netAmountMinor === undefined ? null : money(line.netAmountMinor);\n const quantity = numberDecimal(line.quantity, 6);\n const gross =\n explicitNet ??\n roundSignedRational(\n quantity.coefficient * money(line.unitPrice),\n quantity.scale,\n );\n safeMoney(gross);\n const discount =\n explicitNet === null ? discountFor(gross, line.discount) : 0n;\n const amount = gross - discount;\n safeMoney(amount);\n if (input.lineAmountType === 'none' && !line.taxCode)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'None pricing requires an out-of-scope tax code',\n );\n if (\n input.lineAmountType === 'none' &&\n line.taxCode?.kind !== 'out-of-scope'\n )\n validationError(\n 'TAX_CODE_KIND',\n 'None pricing requires an out-of-scope tax code',\n );\n const components = line.taxCode ? validateTaxCode(line.taxCode, rates) : [];\n const totalRate = components.reduce(\n (sum, component) => sum + component.rate,\n 0n,\n );\n const denominator =\n explicitNet === null && input.lineAmountType === 'inclusive'\n ? PERCENT_DENOMINATOR + totalRate\n : PERCENT_DENOMINATOR;\n return {\n input: line,\n gross,\n discount,\n amount,\n explicitNet,\n exact:\n input.lineAmountType === 'none'\n ? []\n : components.map((component) => ({\n taxComponentId: component.taxComponentId,\n numerator: amount * component.rate,\n denominator,\n })),\n taxes: new Map<string, bigint>(),\n };\n });\n\n if (input.roundingScope === 'line') {\n for (const line of working)\n for (const component of line.exact)\n line.taxes.set(\n component.taxComponentId,\n roundSignedRational(component.numerator, component.denominator),\n );\n } else {\n for (const componentId of [...rates.keys()].sort()) {\n const eligible = working.flatMap((line) => {\n const exact = line.exact.find(\n (component) => component.taxComponentId === componentId,\n );\n return exact ? [{ line, exact }] : [];\n });\n const allocated = allocateSignedRationals(\n eligible.map(({ line, exact }) => ({\n id: line.input.id,\n numerator: exact.numerator,\n denominator: exact.denominator,\n })),\n );\n for (const allocation of allocated.allocations)\n eligible\n .find(({ line }) => line.input.id === allocation.id)\n ?.line.taxes.set(componentId, allocation.value);\n }\n }\n\n const lines = working.map((line): MoneyLineResult => {\n const components = line.exact.map((component) => ({\n taxComponentId: component.taxComponentId,\n taxMinor: safeMoney(line.taxes.get(component.taxComponentId) ?? 0n),\n }));\n const tax = components.reduce(\n (sum, component) => sum + BigInt(component.taxMinor),\n 0n,\n );\n const net =\n line.explicitNet ??\n (input.lineAmountType === 'inclusive' ? line.amount - tax : line.amount);\n const amount =\n line.explicitNet !== null && input.lineAmountType === 'inclusive'\n ? net + tax\n : line.amount;\n return {\n id: line.input.id,\n grossMinor: safeMoney(line.gross),\n discountMinor: safeMoney(line.discount),\n amountMinor: safeMoney(amount),\n components,\n taxMinor: safeMoney(tax),\n netMinor: safeMoney(net),\n };\n });\n\n const taxRows = new Map<string, MoneyDocumentTaxResult>();\n for (let index = 0; index < working.length; index++) {\n const source = working[index].input;\n const result = lines[index];\n if (\n !source.taxCode ||\n source.taxCode.components.length === 0 ||\n input.lineAmountType === 'none'\n ) {\n const key = `${source.taxCode?.id ?? ''}\\u0000`;\n const row = taxRows.get(key) ?? {\n taxCodeId: source.taxCode?.id ?? null,\n taxComponentId: null,\n taxableMinor: 0,\n taxMinor: 0,\n };\n row.taxableMinor = safeMoney(\n BigInt(row.taxableMinor) + BigInt(result.netMinor),\n );\n taxRows.set(key, row);\n continue;\n }\n for (const component of result.components) {\n if (!source.taxCode)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax component requires a tax code',\n );\n const key = `${source.taxCode.id}\\u0000${component.taxComponentId}`;\n const row = taxRows.get(key) ?? {\n taxCodeId: source.taxCode.id,\n taxComponentId: component.taxComponentId,\n taxableMinor: 0,\n taxMinor: 0,\n };\n row.taxableMinor = safeMoney(\n BigInt(row.taxableMinor) + BigInt(result.netMinor),\n );\n row.taxMinor = safeMoney(\n BigInt(row.taxMinor) + BigInt(component.taxMinor),\n );\n taxRows.set(key, row);\n }\n }\n const taxes = [...taxRows.values()].sort((left, right) => {\n const leftCode = left.taxCodeId ?? '';\n const rightCode = right.taxCodeId ?? '';\n if (leftCode !== rightCode) return leftCode < rightCode ? -1 : 1;\n const leftComponent = left.taxComponentId ?? '';\n const rightComponent = right.taxComponentId ?? '';\n return leftComponent < rightComponent\n ? -1\n : leftComponent > rightComponent\n ? 1\n : 0;\n });\n const subtotal = lines.reduce((sum, line) => sum + BigInt(line.netMinor), 0n);\n const discountTotal = lines.reduce(\n (sum, line) => sum + BigInt(line.discountMinor),\n 0n,\n );\n const tax = lines.reduce((sum, line) => sum + BigInt(line.taxMinor), 0n);\n return {\n lines,\n subtotalMinor: safeMoney(subtotal),\n discountTotalMinor: safeMoney(discountTotal),\n taxMinor: safeMoney(tax),\n totalMinor: safeMoney(subtotal + tax),\n taxes,\n };\n}\n\nfunction selectedCode(\n id: string | null | undefined,\n source: TaxCodeResolutionSource,\n context: ResolveLineTaxCodeContext,\n): ResolvedLineTaxCode | null {\n if (!id) return null;\n const taxCode = context.codes[id];\n if (!taxCode)\n validationError('TAX_CODE_NOT_FOUND', `Unknown tax code: ${id}`);\n if (typeof taxCode.active !== 'boolean')\n validationError('INVALID_MONEY_INPUT', `Tax code ${id} has invalid state`);\n if (!taxCode.active)\n validationError('TAX_CODE_INACTIVE', `Tax code ${id} is inactive`);\n if (\n taxCode.appliesTo !== 'sales' &&\n taxCode.appliesTo !== 'purchases' &&\n taxCode.appliesTo !== 'both'\n )\n validationError(\n 'INVALID_MONEY_INPUT',\n `Tax code ${id} has invalid applicability`,\n );\n if (taxCode.appliesTo !== 'both' && taxCode.appliesTo !== context.direction)\n validationError(\n 'TAX_CODE_SCOPE',\n `Tax code ${id} does not apply to ${context.direction}`,\n );\n return { taxCode, source };\n}\n\n/** Resolve a line tax code from already-loaded values, without model or I/O access. */\nexport function resolveLineTaxCode(\n line: ResolveLineTaxCodeInput,\n context: ResolveLineTaxCodeContext,\n): ResolvedLineTaxCode {\n if (\n !line ||\n typeof line !== 'object' ||\n !context ||\n typeof context !== 'object'\n )\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax-code resolution inputs must be objects',\n );\n if (!context.codes || typeof context.codes !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax-code map must be an object');\n if (\n line.lineAmountType !== 'exclusive' &&\n line.lineAmountType !== 'inclusive' &&\n line.lineAmountType !== 'none'\n )\n validationError('INVALID_MONEY_INPUT', 'Unknown line amount type');\n if (context.direction !== 'sales' && context.direction !== 'purchases')\n validationError('INVALID_MONEY_INPUT', 'Unknown tax-code direction');\n if (line.lineAmountType === 'none') {\n if (!context.outOfScopeCodeId)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'None mode requires an out-of-scope tax code',\n );\n const resolved = selectedCode(context.outOfScopeCodeId, 'none', context);\n if (resolved?.taxCode?.kind !== 'out-of-scope')\n validationError(\n 'TAX_CODE_KIND',\n 'None mode requires an out-of-scope tax code',\n );\n return resolved;\n }\n if (context.customerTaxExempt && !line.lineOverride) {\n if (!context.exemptCodeId)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'An exempt customer requires an exempt tax code',\n );\n const exempt = selectedCode(\n context.exemptCodeId,\n 'exempt-customer',\n context,\n );\n if (exempt?.taxCode?.kind !== 'exempt')\n validationError(\n 'TAX_CODE_KIND',\n 'Customer exemption requires an exempt tax code',\n );\n return exempt;\n }\n const candidates: readonly [\n string | null | undefined,\n TaxCodeResolutionSource,\n ][] = [\n [line.lineOverride, 'line'],\n [context.productCodeId, 'product'],\n [context.partyCodeId, 'customer'],\n [context.appDefaultCodeId, 'app'],\n ];\n for (const [id, source] of candidates) {\n const resolved = selectedCode(id, source, context);\n if (resolved) return resolved;\n }\n return { taxCode: null, source: 'none' };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"money.js","names":["tax"],"sources":["../src/money.ts"],"sourcesContent":["/** Exact, transport-neutral commercial document money calculation. */\n\nimport { ISO_4217_MINOR_UNITS } from '@happyvertical/smrt-ui/currency';\nimport {\n allocateSignedRationals,\n roundSignedRational,\n} from './money-rational.js';\n\n/** Throw unless every named model value is a finite integer minor-unit amount. */\nexport function assertIntegerMinorUnits(\n context: string,\n label: string,\n entries: ReadonlyArray<readonly [string, number]>,\n): void {\n for (const [field, value] of entries) {\n if (!Number.isFinite(value) || !Number.isInteger(value)) {\n throw new Error(\n `${context} ${label}: ${field} must be an integer number of minor ` +\n `units (cents, satoshis) — got ${value}. Money is exact: $19.99 is ` +\n '1999, not 19.99.',\n );\n }\n }\n}\n\nexport type LineAmountType = 'exclusive' | 'inclusive' | 'none';\nexport type TaxRoundingScope = 'line' | 'document';\nexport type TaxCodeKind = 'taxable' | 'zero-rated' | 'exempt' | 'out-of-scope';\nexport type TaxCodeAppliesTo = 'sales' | 'purchases' | 'both';\n\nexport type MoneyValidationCode =\n | 'DISCOUNT_BOTH_FORMS'\n | 'DISCOUNT_EXCEEDS_GROSS'\n | 'DISCOUNT_SIGN'\n | 'PERCENT_OUT_OF_RANGE'\n | 'COMPOUND_UNSUPPORTED'\n | 'TAX_COMPONENT_DEPENDENCY_CYCLE'\n | 'INVALID_MONEY_INPUT'\n | 'TAX_CODE_DUPLICATE_COMPONENT'\n | 'TAX_CODE_KIND'\n | 'TAX_CODE_NON_TAXABLE_COMPONENTS'\n | 'TAX_CODE_NOT_FOUND'\n | 'TAX_CODE_TAXABLE_EMPTY'\n | 'TAX_COMPONENT_RATE_CONFLICT'\n | 'TAX_CODE_INACTIVE'\n | 'TAX_CODE_SCOPE'\n | 'UNSAFE_MONEY'\n | 'FROZEN_DOCUMENT'\n | 'CURRENCY_MISMATCH'\n | 'ACCOUNTING_SYNC_IN_PROGRESS'\n | 'ACCOUNTING_SYNC_RECONCILIATION_REQUIRED'\n | 'ACCOUNTING_SYNC_UNSUPPORTED'\n | 'CREDIT_EXCEEDS_LINE'\n | 'CREDIT_TARGET_NOT_ISSUED';\n\n/** Stable validation error shared by model, editor, and transport adapters. */\nexport class MoneyValidationError extends Error {\n override readonly name = 'MoneyValidationError';\n /** Explicit marker consumed by public transports that preserve typed errors. */\n readonly publicMessage: string;\n\n constructor(\n readonly code: MoneyValidationCode,\n message: string,\n ) {\n super(message);\n this.publicMessage = message;\n }\n}\n\nexport interface TaxComponentInput {\n taxComponentId: string;\n /** Exact percent: \"7\" means 7%; at most six fractional digits. */\n percent: string;\n compound: boolean;\n}\n\nexport interface MoneyTaxCodeInput {\n id: string;\n kind: TaxCodeKind;\n components: readonly TaxComponentInput[];\n}\n\nexport interface ResolvableTaxCodeInput extends MoneyTaxCodeInput {\n active: boolean;\n appliesTo: TaxCodeAppliesTo;\n}\n\nexport type MoneyDiscountInput =\n | { kind: 'none' }\n | { kind: 'percent'; rate: string }\n | { kind: 'amount'; minor: number };\n\nexport interface MoneyLineInput {\n id: string;\n /** Nonnegative decimal quantity with at most six fractional digits. */\n quantity: number;\n /** Signed safe integer minor units. */\n unitPrice: number;\n discount: MoneyDiscountInput;\n /** Explicit tax-exclusive basis for credit-note amount allocations. */\n netAmountMinor?: number;\n /** Null means no code resolved; `none` pricing requires an out-of-scope code. */\n taxCode: MoneyTaxCodeInput | null;\n}\n\nexport interface MoneyLineResult {\n id: string;\n grossMinor: number;\n discountMinor: number;\n amountMinor: number;\n components: {\n taxComponentId: string;\n taxMinor: number;\n compound?: boolean;\n taxableMinor?: number;\n }[];\n taxMinor: number;\n netMinor: number;\n}\n\nexport interface MoneyDocumentTaxResult {\n /** Null records an unassigned line without inventing a persisted tax-code ID. */\n taxCodeId: string | null;\n taxComponentId: string | null;\n taxableMinor: number;\n /** Net basis separately from a compound component's actual taxable basis. */\n netMinor?: number;\n taxMinor: number;\n}\n\nexport interface MoneyDocumentResult {\n lines: MoneyLineResult[];\n subtotalMinor: number;\n discountTotalMinor: number;\n taxMinor: number;\n totalMinor: number;\n taxes: MoneyDocumentTaxResult[];\n}\n\nexport type TaxCodeResolutionSource =\n | 'line'\n | 'exempt-customer'\n | 'product'\n | 'customer'\n | 'app'\n | 'none';\n\nexport interface ResolveLineTaxCodeInput {\n lineAmountType: LineAmountType;\n lineOverride?: string | null;\n}\n\nexport interface ResolveLineTaxCodeContext {\n direction: 'sales' | 'purchases';\n codes: Readonly<Record<string, ResolvableTaxCodeInput>>;\n customerTaxExempt: boolean;\n exemptCodeId?: string | null;\n productCodeId?: string | null;\n partyCodeId?: string | null;\n appDefaultCodeId?: string | null;\n outOfScopeCodeId?: string | null;\n}\n\nexport interface ResolvedLineTaxCode {\n taxCode: ResolvableTaxCodeInput | null;\n source: TaxCodeResolutionSource;\n}\n\nconst PERCENT_SCALE = 1_000_000n;\nconst PERCENT_DENOMINATOR = 100n * PERCENT_SCALE;\nconst MAX_SAFE_MONEY = BigInt(Number.MAX_SAFE_INTEGER);\nconst IDENTIFIER = /^\\S(?:.*\\S)?$/;\n\nfunction validationError(code: MoneyValidationCode, message: string): never {\n throw new MoneyValidationError(code, message);\n}\n\nfunction assertIdentifier(value: string, label: string): void {\n if (typeof value !== 'string' || !IDENTIFIER.test(value))\n validationError(\n 'INVALID_MONEY_INPUT',\n `${label} must be a nonempty string`,\n );\n}\n\nfunction safeMoney(value: bigint): number {\n if (value > MAX_SAFE_MONEY || value < -MAX_SAFE_MONEY)\n validationError('UNSAFE_MONEY', 'Money exceeds safe integer minor units');\n return Number(value);\n}\n\nfunction money(value: number): bigint {\n if (!Number.isSafeInteger(value))\n validationError('UNSAFE_MONEY', 'Money must be safe integer minor units');\n return BigInt(value);\n}\n\ninterface ExactDecimal {\n coefficient: bigint;\n scale: bigint;\n}\n\nfunction numberDecimal(value: number, precision: number): ExactDecimal {\n if (!Number.isFinite(value) || value < 0 || value > Number.MAX_SAFE_INTEGER)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Quantity is outside the supported range',\n );\n const [mantissa, exponentText = '0'] = value.toString().split('e');\n const [whole, fraction = ''] = mantissa.split('.');\n const places = fraction.length - Number(exponentText);\n if (places > precision)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Quantity exceeds the supported decimal precision',\n );\n const coefficient = BigInt(whole + fraction);\n return places < 0\n ? { coefficient: coefficient * 10n ** BigInt(-places), scale: 1n }\n : { coefficient, scale: 10n ** BigInt(places) };\n}\n\nfunction percentUnits(value: string): bigint {\n if (\n typeof value !== 'string' ||\n !/^(?:0|[1-9]\\d{0,2})(?:\\.\\d{1,6})?$/.test(value)\n )\n validationError(\n 'PERCENT_OUT_OF_RANGE',\n 'Percent must be an exact decimal from 0 through 100 with at most six fractional digits',\n );\n const [whole, fraction = ''] = value.split('.');\n const units = BigInt(whole) * PERCENT_SCALE + BigInt(fraction.padEnd(6, '0'));\n if (units > PERCENT_DENOMINATOR)\n validationError('PERCENT_OUT_OF_RANGE', 'Percent exceeds 100');\n return units;\n}\n\nfunction validateTaxCode(\n code: MoneyTaxCodeInput,\n rates: Map<string, bigint>,\n): { taxComponentId: string; rate: bigint; compound: boolean }[] {\n if (!code || typeof code !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax code must be an object');\n assertIdentifier(code.id, 'Tax code ID');\n if (\n code.kind !== 'taxable' &&\n code.kind !== 'zero-rated' &&\n code.kind !== 'exempt' &&\n code.kind !== 'out-of-scope'\n )\n validationError('TAX_CODE_KIND', 'Unknown tax code kind');\n if (!Array.isArray(code.components))\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax code components must be an array',\n );\n if (code.kind === 'taxable' && code.components.length === 0)\n validationError(\n 'TAX_CODE_TAXABLE_EMPTY',\n 'Taxable codes require at least one component',\n );\n if (code.kind !== 'taxable' && code.components.length !== 0)\n validationError(\n 'TAX_CODE_NON_TAXABLE_COMPONENTS',\n 'Non-taxable codes cannot contain components',\n );\n const seen = new Set<string>();\n return code.components.map((component) => {\n if (!component || typeof component !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax component must be an object');\n assertIdentifier(component.taxComponentId, 'Tax component ID');\n if (seen.has(component.taxComponentId))\n validationError(\n 'TAX_CODE_DUPLICATE_COMPONENT',\n 'Duplicate tax component within code',\n );\n seen.add(component.taxComponentId);\n if (typeof component.compound !== 'boolean')\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax component compound must be boolean',\n );\n const rate = percentUnits(component.percent);\n const existing = rates.get(component.taxComponentId);\n if (existing !== undefined && existing !== rate)\n validationError(\n 'TAX_COMPONENT_RATE_CONFLICT',\n 'Shared tax component has conflicting percentages',\n );\n rates.set(component.taxComponentId, rate);\n return {\n taxComponentId: component.taxComponentId,\n rate,\n compound: component.compound,\n };\n });\n}\n\nfunction discountFor(gross: bigint, discount: MoneyDiscountInput): bigint {\n if (!discount || typeof discount !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Discount must be a tagged object');\n const runtime = discount as MoneyDiscountInput & {\n rate?: unknown;\n minor?: unknown;\n };\n if (runtime.rate !== undefined && runtime.minor !== undefined)\n validationError(\n 'DISCOUNT_BOTH_FORMS',\n 'A discount cannot include both percent and amount forms',\n );\n let result: bigint;\n if (discount.kind === 'none') {\n if (runtime.rate !== undefined || runtime.minor !== undefined)\n validationError(\n 'DISCOUNT_BOTH_FORMS',\n 'A none discount cannot include percent or amount values',\n );\n result = 0n;\n } else if (discount.kind === 'percent') {\n result = roundSignedRational(\n gross * percentUnits(discount.rate),\n PERCENT_DENOMINATOR,\n );\n } else if (discount.kind === 'amount') {\n result = money(discount.minor);\n } else {\n validationError('INVALID_MONEY_INPUT', 'Unknown discount kind');\n }\n if (result !== 0n && gross !== 0n && result < 0n !== gross < 0n)\n validationError(\n 'DISCOUNT_SIGN',\n 'Discount amount must carry the sign of gross',\n );\n if (gross === 0n && result !== 0n)\n validationError('DISCOUNT_SIGN', 'A zero gross cannot carry a discount');\n const magnitude = (value: bigint) => (value < 0n ? -value : value);\n if (magnitude(result) > magnitude(gross))\n validationError('DISCOUNT_EXCEEDS_GROSS', 'Discount cannot exceed gross');\n return result;\n}\n\nfunction validateDocumentInput(input: {\n currency: string;\n lineAmountType: LineAmountType;\n roundingScope: TaxRoundingScope;\n lines: readonly MoneyLineInput[];\n}): void {\n if (!input || typeof input !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Money input must be an object');\n if (\n typeof input.currency !== 'string' ||\n !/^[A-Z]{3}$/.test(input.currency) ||\n !ISO_4217_MINOR_UNITS.has(input.currency) ||\n ISO_4217_MINOR_UNITS.get(input.currency) === null\n )\n validationError(\n 'CURRENCY_MISMATCH',\n 'Currency must be a supported uppercase ISO 4217 code with minor units',\n );\n if (\n input.lineAmountType !== 'exclusive' &&\n input.lineAmountType !== 'inclusive' &&\n input.lineAmountType !== 'none'\n )\n validationError('INVALID_MONEY_INPUT', 'Unknown line amount type');\n if (input.roundingScope !== 'line' && input.roundingScope !== 'document')\n validationError('INVALID_MONEY_INPUT', 'Unknown tax rounding scope');\n if (!Array.isArray(input.lines))\n validationError('INVALID_MONEY_INPUT', 'Lines must be an array');\n}\n\n/** Calculate exact line amounts, per-component tax, and document totals. */\nexport function calculateMoneyDocument(input: {\n currency: string;\n lineAmountType: LineAmountType;\n roundingScope: TaxRoundingScope;\n lines: readonly MoneyLineInput[];\n}): MoneyDocumentResult {\n validateDocumentInput(input);\n const ids = new Set<string>();\n const rates = new Map<string, bigint>();\n const working = input.lines.map((line) => {\n if (!line || typeof line !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Money line must be an object');\n assertIdentifier(line.id, 'Line ID');\n if (ids.has(line.id))\n validationError('INVALID_MONEY_INPUT', 'Duplicate money line ID');\n ids.add(line.id);\n const explicitNet =\n line.netAmountMinor === undefined ? null : money(line.netAmountMinor);\n const quantity = numberDecimal(line.quantity, 6);\n const gross =\n explicitNet ??\n roundSignedRational(\n quantity.coefficient * money(line.unitPrice),\n quantity.scale,\n );\n safeMoney(gross);\n const discount =\n explicitNet === null ? discountFor(gross, line.discount) : 0n;\n const amount = gross - discount;\n safeMoney(amount);\n if (input.lineAmountType === 'none' && !line.taxCode)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'None pricing requires an out-of-scope tax code',\n );\n if (\n input.lineAmountType === 'none' &&\n line.taxCode?.kind !== 'out-of-scope'\n )\n validationError(\n 'TAX_CODE_KIND',\n 'None pricing requires an out-of-scope tax code',\n );\n const components = line.taxCode ? validateTaxCode(line.taxCode, rates) : [];\n // Inclusive extraction uses exact ordered factors; exclusive calculation\n // below uses previously rounded/allocated taxes, not these exact factors.\n let totalNumerator = 1n;\n let totalDenominator = 1n;\n const factors = components.map((component) => {\n const numerator =\n component.rate *\n (component.compound ? totalNumerator : totalDenominator);\n const denominator = PERCENT_DENOMINATOR * totalDenominator;\n totalNumerator = totalNumerator * PERCENT_DENOMINATOR + numerator;\n totalDenominator = denominator;\n return { ...component, numerator, denominator };\n });\n const inclusive =\n explicitNet === null && input.lineAmountType === 'inclusive';\n return {\n input: line,\n gross,\n discount,\n amount,\n explicitNet,\n inclusive,\n exact:\n input.lineAmountType === 'none'\n ? []\n : factors.map((component, index) => ({\n ...component,\n priorIds: component.compound\n ? components\n .slice(0, index)\n .map((prior) => prior.taxComponentId)\n : [],\n numerator: amount * component.numerator * totalDenominator,\n denominator: component.denominator * totalNumerator,\n })),\n taxes: new Map<string, bigint>(),\n bases: new Map<string, bigint>(),\n };\n });\n\n const dependencies = new Map(\n [...rates.keys()].map((id) => [id, new Set<string>()]),\n );\n for (const line of working)\n for (const component of line.exact)\n for (const prior of component.priorIds)\n dependencies.get(component.taxComponentId)?.add(prior);\n const order: string[] = [];\n while (dependencies.size) {\n const ready = [...dependencies]\n .filter(([, prior]) => prior.size === 0)\n .map(([id]) => id)\n .sort();\n if (!ready.length)\n validationError(\n 'TAX_COMPONENT_DEPENDENCY_CYCLE',\n 'Tax codes impose contradictory compound component order',\n );\n for (const id of ready) {\n order.push(id);\n dependencies.delete(id);\n for (const prior of dependencies.values()) prior.delete(id);\n }\n }\n const exactTax = (\n line: (typeof working)[number],\n component: (typeof working)[number]['exact'][number],\n ) => {\n if (line.inclusive) return component;\n const basis =\n line.amount +\n component.priorIds.reduce(\n (sum, id) => sum + (line.taxes.get(id) ?? 0n),\n 0n,\n );\n safeMoney(basis);\n line.bases.set(component.taxComponentId, basis);\n return {\n numerator: basis * component.rate,\n denominator: PERCENT_DENOMINATOR,\n };\n };\n if (input.roundingScope === 'line') {\n for (const line of working)\n for (const component of line.exact) {\n const exact = exactTax(line, component);\n line.taxes.set(\n component.taxComponentId,\n roundSignedRational(exact.numerator, exact.denominator),\n );\n }\n } else {\n for (const componentId of order) {\n const eligible = working.flatMap((line) => {\n const component = line.exact.find(\n (item) => item.taxComponentId === componentId,\n );\n return component ? [{ line, exact: exactTax(line, component) }] : [];\n });\n const allocated = allocateSignedRationals(\n eligible.map(({ line, exact }) => ({\n id: line.input.id,\n numerator: exact.numerator,\n denominator: exact.denominator,\n })),\n );\n for (const allocation of allocated.allocations)\n eligible\n .find(({ line }) => line.input.id === allocation.id)\n ?.line.taxes.set(componentId, allocation.value);\n }\n }\n\n const lines = working.map((line): MoneyLineResult => {\n const components = line.exact.map((component) => ({\n taxComponentId: component.taxComponentId,\n taxMinor: safeMoney(line.taxes.get(component.taxComponentId) ?? 0n),\n }));\n const tax = components.reduce(\n (sum, component) => sum + BigInt(component.taxMinor),\n 0n,\n );\n const net =\n line.explicitNet ??\n (input.lineAmountType === 'inclusive' ? line.amount - tax : line.amount);\n for (let index = 0; index < components.length; index++) {\n const source = line.exact[index];\n if (source.compound)\n Object.assign(components[index], {\n compound: true,\n taxableMinor: safeMoney(\n line.inclusive\n ? net +\n source.priorIds.reduce(\n (sum, id) => sum + (line.taxes.get(id) ?? 0n),\n 0n,\n )\n : (line.bases.get(source.taxComponentId) ?? net),\n ),\n });\n }\n const amount =\n line.explicitNet !== null && input.lineAmountType === 'inclusive'\n ? net + tax\n : line.amount;\n return {\n id: line.input.id,\n grossMinor: safeMoney(line.gross),\n discountMinor: safeMoney(line.discount),\n amountMinor: safeMoney(amount),\n components,\n taxMinor: safeMoney(tax),\n netMinor: safeMoney(net),\n };\n });\n\n const taxRows = new Map<string, MoneyDocumentTaxResult>();\n for (let index = 0; index < working.length; index++) {\n const source = working[index].input;\n const result = lines[index];\n if (\n !source.taxCode ||\n source.taxCode.components.length === 0 ||\n input.lineAmountType === 'none'\n ) {\n const key = `${source.taxCode?.id ?? ''}\\u0000`;\n const row = taxRows.get(key) ?? {\n taxCodeId: source.taxCode?.id ?? null,\n taxComponentId: null,\n taxableMinor: 0,\n taxMinor: 0,\n };\n row.taxableMinor = safeMoney(\n BigInt(row.taxableMinor) + BigInt(result.netMinor),\n );\n taxRows.set(key, row);\n continue;\n }\n for (const component of result.components) {\n if (!source.taxCode)\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax component requires a tax code',\n );\n const key = `${source.taxCode.id}\\u0000${component.taxComponentId}`;\n const row = taxRows.get(key) ?? {\n taxCodeId: source.taxCode.id,\n taxComponentId: component.taxComponentId,\n taxableMinor: 0,\n taxMinor: 0,\n };\n row.taxableMinor = safeMoney(\n BigInt(row.taxableMinor) +\n BigInt(component.taxableMinor ?? result.netMinor),\n );\n if (component.compound)\n row.netMinor = safeMoney(\n BigInt(row.netMinor ?? 0) + BigInt(result.netMinor),\n );\n row.taxMinor = safeMoney(\n BigInt(row.taxMinor) + BigInt(component.taxMinor),\n );\n taxRows.set(key, row);\n }\n }\n const taxes = [...taxRows.values()].sort((left, right) => {\n const leftCode = left.taxCodeId ?? '';\n const rightCode = right.taxCodeId ?? '';\n if (leftCode !== rightCode) return leftCode < rightCode ? -1 : 1;\n const leftComponent = left.taxComponentId ?? '';\n const rightComponent = right.taxComponentId ?? '';\n return leftComponent < rightComponent\n ? -1\n : leftComponent > rightComponent\n ? 1\n : 0;\n });\n const subtotal = lines.reduce((sum, line) => sum + BigInt(line.netMinor), 0n);\n const discountTotal = lines.reduce(\n (sum, line) => sum + BigInt(line.discountMinor),\n 0n,\n );\n const tax = lines.reduce((sum, line) => sum + BigInt(line.taxMinor), 0n);\n return {\n lines,\n subtotalMinor: safeMoney(subtotal),\n discountTotalMinor: safeMoney(discountTotal),\n taxMinor: safeMoney(tax),\n totalMinor: safeMoney(subtotal + tax),\n taxes,\n };\n}\n\nfunction selectedCode(\n id: string | null | undefined,\n source: TaxCodeResolutionSource,\n context: ResolveLineTaxCodeContext,\n): ResolvedLineTaxCode | null {\n if (!id) return null;\n const taxCode = context.codes[id];\n if (!taxCode)\n validationError('TAX_CODE_NOT_FOUND', `Unknown tax code: ${id}`);\n if (typeof taxCode.active !== 'boolean')\n validationError('INVALID_MONEY_INPUT', `Tax code ${id} has invalid state`);\n if (!taxCode.active)\n validationError('TAX_CODE_INACTIVE', `Tax code ${id} is inactive`);\n if (\n taxCode.appliesTo !== 'sales' &&\n taxCode.appliesTo !== 'purchases' &&\n taxCode.appliesTo !== 'both'\n )\n validationError(\n 'INVALID_MONEY_INPUT',\n `Tax code ${id} has invalid applicability`,\n );\n if (taxCode.appliesTo !== 'both' && taxCode.appliesTo !== context.direction)\n validationError(\n 'TAX_CODE_SCOPE',\n `Tax code ${id} does not apply to ${context.direction}`,\n );\n return { taxCode, source };\n}\n\n/** Resolve a line tax code from already-loaded values, without model or I/O access. */\nexport function resolveLineTaxCode(\n line: ResolveLineTaxCodeInput,\n context: ResolveLineTaxCodeContext,\n): ResolvedLineTaxCode {\n if (\n !line ||\n typeof line !== 'object' ||\n !context ||\n typeof context !== 'object'\n )\n validationError(\n 'INVALID_MONEY_INPUT',\n 'Tax-code resolution inputs must be objects',\n );\n if (!context.codes || typeof context.codes !== 'object')\n validationError('INVALID_MONEY_INPUT', 'Tax-code map must be an object');\n if (\n line.lineAmountType !== 'exclusive' &&\n line.lineAmountType !== 'inclusive' &&\n line.lineAmountType !== 'none'\n )\n validationError('INVALID_MONEY_INPUT', 'Unknown line amount type');\n if (context.direction !== 'sales' && context.direction !== 'purchases')\n validationError('INVALID_MONEY_INPUT', 'Unknown tax-code direction');\n if (line.lineAmountType === 'none') {\n if (!context.outOfScopeCodeId)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'None mode requires an out-of-scope tax code',\n );\n const resolved = selectedCode(context.outOfScopeCodeId, 'none', context);\n if (resolved?.taxCode?.kind !== 'out-of-scope')\n validationError(\n 'TAX_CODE_KIND',\n 'None mode requires an out-of-scope tax code',\n );\n return resolved;\n }\n if (context.customerTaxExempt && !line.lineOverride) {\n if (!context.exemptCodeId)\n validationError(\n 'TAX_CODE_NOT_FOUND',\n 'An exempt customer requires an exempt tax code',\n );\n const exempt = selectedCode(\n context.exemptCodeId,\n 'exempt-customer',\n context,\n );\n if (exempt?.taxCode?.kind !== 'exempt')\n validationError(\n 'TAX_CODE_KIND',\n 'Customer exemption requires an exempt tax code',\n );\n return exempt;\n }\n const candidates: readonly [\n string | null | undefined,\n TaxCodeResolutionSource,\n ][] = [\n [line.lineOverride, 'line'],\n [context.productCodeId, 'product'],\n [context.partyCodeId, 'customer'],\n [context.appDefaultCodeId, 'app'],\n ];\n for (const [id, source] of candidates) {\n const resolved = selectedCode(id, source, context);\n if (resolved) return resolved;\n }\n return { taxCode: null, source: 'none' };\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Internal capability; not exported by the public package. */
2
+ export declare const OBSERVED_PURCHASE_WRITE: unique symbol;
3
+ //# sourceMappingURL=observed-purchase-price-internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observed-purchase-price-internal.d.ts","sourceRoot":"","sources":["../src/observed-purchase-price-internal.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,eAAO,MAAM,uBAAuB,eAA2C,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
2
+ import { type ReceivedPurchaseMoneyFacts } from './received-purchase-money.js';
3
+ /** Null means absent from source evidence. No missing value is inferred as zero. */
4
+ export interface ObservedPurchaseAmounts {
5
+ netMinor: number | null;
6
+ taxMinor: number | null;
7
+ grossMinor: number | null;
8
+ }
9
+ export interface ObservedPurchaseLine extends ObservedPurchaseAmounts {
10
+ sourceKey: string;
11
+ description: string;
12
+ quantityText?: string;
13
+ unitRateText?: string;
14
+ }
15
+ export interface ObservedPurchasePriceFacts extends ObservedPurchaseAmounts {
16
+ currency: string;
17
+ detail: {
18
+ kind: 'header-only';
19
+ } | {
20
+ kind: 'lines';
21
+ lines: ObservedPurchaseLine[];
22
+ };
23
+ }
24
+ export interface PurchasePriceObservationSnapshot {
25
+ version: 1;
26
+ requestId: string;
27
+ sourceNamespace: string;
28
+ sourceKey: string;
29
+ kind: 'supplier-quote' | 'purchase-order';
30
+ vendorId: string;
31
+ /** Source status is retained text, never current approval or acceptance. */
32
+ sourceStatus: string;
33
+ effectiveOn: string;
34
+ evidenceRef: string;
35
+ facts: ObservedPurchasePriceFacts;
36
+ }
37
+ export interface PurchasePriceCompletion {
38
+ requestId: string;
39
+ reviewEvidenceRef: string;
40
+ contractId: string;
41
+ facts: ReceivedPurchaseMoneyFacts;
42
+ }
43
+ export interface PurchasePriceObservationView {
44
+ id: string;
45
+ snapshot: PurchasePriceObservationSnapshot;
46
+ completion: PurchasePriceCompletion | null;
47
+ /** Complete, usable aggregates exist only on the explicitly completed Contract. */
48
+ monetaryAggregate: null;
49
+ }
50
+ export declare function validateObservedPurchasePriceFacts(raw: unknown): ObservedPurchasePriceFacts;
51
+ /** Host authorizes import/recording; source approval never becomes current contract acceptance. */
52
+ export declare function recordPurchasePriceObservation(input: {
53
+ db: DatabaseInterface;
54
+ tenantId: string;
55
+ snapshot: PurchasePriceObservationSnapshot;
56
+ }): Promise<PurchasePriceObservationView>;
57
+ export declare function readPurchasePriceObservation(input: {
58
+ db: DatabaseInterface;
59
+ tenantId: string;
60
+ id: string;
61
+ }): Promise<PurchasePriceObservationView>;
62
+ /** Explicit reviewed completion creates a separate draft; no source status implies approval. */
63
+ export declare function completePurchasePriceObservation(input: {
64
+ db: DatabaseInterface;
65
+ tenantId: string;
66
+ id: string;
67
+ requestId: string;
68
+ reviewEvidenceRef: string;
69
+ facts: ReceivedPurchaseMoneyFacts;
70
+ }): Promise<PurchasePriceObservationView>;
71
+ //# sourceMappingURL=observed-purchase-price.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observed-purchase-price.d.ts","sourceRoot":"","sources":["../src/observed-purchase-price.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAS7E,OAAO,EAEL,KAAK,0BAA0B,EAGhC,MAAM,8BAA8B,CAAC;AAGtC,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AACD,MAAM,WAAW,oBAAqB,SAAQ,uBAAuB;IACnE,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AACD,MAAM,WAAW,0BAA2B,SAAQ,uBAAuB;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EACF;QAAE,IAAI,EAAE,aAAa,CAAA;KAAE,GACvB;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,oBAAoB,EAAE,CAAA;KAAE,CAAC;CACtD;AACD,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,CAAC,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,gBAAgB,GAAG,gBAAgB,CAAC;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,0BAA0B,CAAC;CACnC;AACD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,0BAA0B,CAAC;CACnC;AACD,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,gCAAgC,CAAC;IAC3C,UAAU,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC3C,mFAAmF;IACnF,iBAAiB,EAAE,IAAI,CAAC;CACzB;AA2CD,wBAAgB,kCAAkC,CAChD,GAAG,EAAE,OAAO,GACX,0BAA0B,CAgD5B;AAwED,mGAAmG;AACnG,wBAAsB,8BAA8B,CAAC,KAAK,EAAE;IAC1D,EAAE,EAAE,iBAAiB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,gCAAgC,CAAC;CAC5C,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAmCxC;AACD,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,EAAE,EAAE,iBAAiB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;CACZ,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAQxC;AAQD,gGAAgG;AAChG,wBAAsB,gCAAgC,CAAC,KAAK,EAAE;IAC5D,EAAE,EAAE,iBAAiB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,0BAA0B,CAAC;CACnC,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAoGxC"}
@@ -0,0 +1,3 @@
1
+ export declare function withOrdinaryAccountingAuthority<T>(tenantId: string, invoiceId: string, operation: () => Promise<T>): Promise<T>;
2
+ export declare function hasOrdinaryAccountingAuthority(tenantId: string | null | undefined, invoiceId: string | null | undefined): boolean;
3
+ //# sourceMappingURL=ordinary-accounting-internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordinary-accounting-internal.d.ts","sourceRoot":"","sources":["../src/ordinary-accounting-internal.ts"],"names":[],"mappings":"AAOA,wBAAgB,+BAA+B,CAAC,CAAC,EAC/C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAEZ;AACD,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,OAAO,CAOT"}
@@ -0,0 +1,104 @@
1
+ import { type AccountingProvider, type CreditMemoInput, type QuickBooksOrdinaryReceivableMapping } from '@happyvertical/accounting';
2
+ import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
3
+ import { type AccountingStep, type AccountingStepReconciliation } from './accounting-steps-internal.js';
4
+ import { type QuickBooksFrozenInvoiceMapping, type ReconcileFrozenInvoiceAccountingInput } from './invoice-accounting-sync.js';
5
+ import type { Invoice } from './models/Invoice.js';
6
+ type Provider = Pick<AccountingProvider, 'type' | 'invoices' | 'creditMemos' | 'receivableTransfers'>;
7
+ interface Scope {
8
+ db: DatabaseInterface;
9
+ tenantId: string;
10
+ invoiceId: string;
11
+ provider: Provider;
12
+ }
13
+ interface RefundRecording {
14
+ paymentId: string;
15
+ creditId: string;
16
+ requestId: string;
17
+ evidenceRef: string;
18
+ effectiveOn: string;
19
+ amountMinor: number;
20
+ paymentFingerprint: string;
21
+ committed: boolean;
22
+ }
23
+ interface CreditAdjustment {
24
+ creditId: string;
25
+ moneySnapshotId: string;
26
+ requestId: string;
27
+ evidenceRef: string;
28
+ effectiveOn: string;
29
+ grossMinor: number;
30
+ appliedMinor: number;
31
+ mapping: QuickBooksFrozenInvoiceMapping;
32
+ committed: boolean;
33
+ }
34
+ export interface OrdinaryInvoiceAccountingState {
35
+ version: 1;
36
+ kind: 'ordinary';
37
+ invoiceId: string;
38
+ moneySnapshotId: string;
39
+ externalInvoiceId: string | null;
40
+ invoiceMapping: QuickBooksFrozenInvoiceMapping;
41
+ requestId: string;
42
+ evidenceRef: string;
43
+ currency: string;
44
+ grossMinor: number;
45
+ mapping: QuickBooksOrdinaryReceivableMapping;
46
+ status: 'pending' | 'ready';
47
+ steps: AccountingStep[];
48
+ credits: CreditAdjustment[];
49
+ refunds: RefundRecording[];
50
+ }
51
+ export declare function readOrdinaryInvoiceAccountingState(invoice: Invoice): OrdinaryInvoiceAccountingState | null;
52
+ export interface SyncOrdinaryInvoiceToAccountingInput extends Scope {
53
+ requestId: string;
54
+ evidenceRef: string;
55
+ mapping: QuickBooksOrdinaryReceivableMapping;
56
+ invoiceMapping: QuickBooksFrozenInvoiceMapping;
57
+ }
58
+ /** Retain exact reviewed mapping before the first possible remote invoice write. */
59
+ export declare function syncOrdinaryInvoiceToAccounting(input: SyncOrdinaryInvoiceToAccountingInput): Promise<OrdinaryInvoiceAccountingState>;
60
+ export declare function reconcileOrdinaryBaseInvoice(input: ReconcileFrozenInvoiceAccountingInput & {
61
+ provider: Provider;
62
+ }): Promise<import("./invoice-accounting-sync.js").FrozenAccountingSyncResult | import("./invoice-accounting-sync.js").FrozenAccountingReconciliationReady>;
63
+ export interface ReconcileOrdinaryAccountingStepInput extends Scope, AccountingStepReconciliation {
64
+ }
65
+ export declare function reconcileOrdinaryAccountingStep(input: ReconcileOrdinaryAccountingStepInput): Promise<OrdinaryInvoiceAccountingState>;
66
+ export interface SyncOrdinaryCreditToAccountingInput extends Scope {
67
+ creditInvoiceId: string;
68
+ creditMapping: QuickBooksFrozenInvoiceMapping;
69
+ requestId: string;
70
+ evidenceRef: string;
71
+ effectiveOn: string;
72
+ }
73
+ /** Apply the reserved ordinary credit amount to its original due balance. */
74
+ export declare function syncOrdinaryCreditToAccounting(input: SyncOrdinaryCreditToAccountingInput): Promise<OrdinaryInvoiceAccountingState>;
75
+ export interface SyncOrdinaryRefundToAccountingInput extends Scope {
76
+ paymentId: string;
77
+ creditInvoiceId: string;
78
+ requestId: string;
79
+ evidenceRef: string;
80
+ effectiveOn: string;
81
+ }
82
+ /** Record an already settled local refund and consume its existing remote credit. No bank I/O. */
83
+ export declare function syncOrdinaryRefundToAccounting(input: SyncOrdinaryRefundToAccountingInput): Promise<OrdinaryInvoiceAccountingState>;
84
+ export interface ReconcileOrdinaryCreditAccountingInput extends Scope {
85
+ creditInvoiceId: string;
86
+ requestId: string;
87
+ attemptId: string;
88
+ confirmInterruptedOwnerStopped?: true;
89
+ outcome: ReconcileFrozenInvoiceAccountingInput['outcome'];
90
+ }
91
+ /** Resolve an interrupted credit-memo export before its ordinary applications resume. */
92
+ export declare function reconcileOrdinaryCreditAccounting(input: ReconcileOrdinaryCreditAccountingInput): Promise<import("./invoice-accounting-sync.js").FrozenAccountingSyncResult | import("./invoice-accounting-sync.js").FrozenAccountingReconciliationReady>;
93
+ export interface OrdinaryCreditReviewScope {
94
+ db: DatabaseInterface;
95
+ tenantId: string;
96
+ invoiceId: string;
97
+ creditInvoiceId: string;
98
+ }
99
+ export declare function loadOrdinaryCreditAccountingSnapshot(input: OrdinaryCreditReviewScope): Promise<import("./invoice-accounting-sync.js").FrozenInvoiceAccountingSnapshot>;
100
+ export declare function toOrdinaryCreditAccountingInput(input: OrdinaryCreditReviewScope & {
101
+ mapping: QuickBooksFrozenInvoiceMapping;
102
+ }): Promise<CreditMemoInput>;
103
+ export {};
104
+ //# sourceMappingURL=ordinary-accounting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ordinary-accounting.d.ts","sourceRoot":"","sources":["../src/ordinary-accounting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ /** Exact monetary evidence received from a supplier, independent of calculated pricing. */
2
+ import type { DatabaseInterface } from '@happyvertical/smrt-core/migrations';
3
+ import { type Contract } from './models/Contract.js';
4
+ import { type TaxCodeKind } from './money.js';
5
+ /** A supplier tax component. Null explicitly retains an unknown fact. */
6
+ export interface ReceivedPurchaseTaxComponent {
7
+ sourceKey: string;
8
+ label: string;
9
+ amountMinor: number;
10
+ classification: TaxCodeKind | null;
11
+ /** Explicit report identity/basis; omission retains unknown, never implies a rate. */
12
+ taxCodeId?: string | null;
13
+ taxComponentId?: string | null;
14
+ taxableMinor?: number | null;
15
+ /** Explicit net allocation when supplier taxable basis includes prior taxes. */
16
+ netMinor?: number | null;
17
+ recoverableMinor: number | null;
18
+ }
19
+ /** Complete source line money; optional source decimal text is evidence, not a calculator input. */
20
+ export interface ReceivedPurchaseMoneyLine {
21
+ sourceKey: string;
22
+ description: string;
23
+ netMinor: number;
24
+ taxMinor: number;
25
+ grossMinor: number;
26
+ quantityText?: string;
27
+ unitRateText?: string;
28
+ }
29
+ /** Monetary evidence without a fabricated rate, quantity, or line allocation. */
30
+ export interface ReceivedPurchaseMoneyFacts {
31
+ currency: string;
32
+ netMinor: number;
33
+ taxMinor: number;
34
+ grossMinor: number;
35
+ taxComponents: ReceivedPurchaseTaxComponent[] | null;
36
+ detail: {
37
+ kind: 'header-only';
38
+ } | {
39
+ kind: 'lines';
40
+ lines: ReceivedPurchaseMoneyLine[];
41
+ };
42
+ }
43
+ /** Immutable request and supplier evidence identity retained with the amounts. */
44
+ export interface ReceivedPurchaseMoneySnapshot {
45
+ version: 1;
46
+ requestId: string;
47
+ evidenceRef: string;
48
+ facts: ReceivedPurchaseMoneyFacts;
49
+ sourceQuote: ReceivedPurchaseQuoteSource | null;
50
+ }
51
+ export interface ReceivedPurchaseQuoteSource {
52
+ contractId: string;
53
+ relationship: 'copy' | 'negotiated';
54
+ }
55
+ /** Public command input. The host authorizes the human before calling this command. */
56
+ export interface RecordReceivedPurchaseMoneyInput {
57
+ db: DatabaseInterface;
58
+ tenantId: string;
59
+ contractId: string;
60
+ requestId: string;
61
+ evidenceRef: string;
62
+ facts: ReceivedPurchaseMoneyFacts;
63
+ sourceQuote?: ReceivedPurchaseQuoteSource;
64
+ }
65
+ /** Complete received sales agreement evidence; recording is not revenue/tax recognition. */
66
+ export type ReceivedSalesContractMoneyFacts = ReceivedPurchaseMoneyFacts;
67
+ export type ReceivedSalesContractMoneySnapshot = ReceivedPurchaseMoneySnapshot;
68
+ export type RecordReceivedSalesContractMoneyInput = Omit<RecordReceivedPurchaseMoneyInput, 'sourceQuote'>;
69
+ /** Record supplied complete facts on one empty draft Order/Agreement. */
70
+ export declare function recordReceivedSalesContractMoney(input: RecordReceivedSalesContractMoneyInput): Promise<ReceivedSalesContractMoneySnapshot>;
71
+ /** Read exact sales agreement evidence without calculating or recognizing an invoice. */
72
+ export declare function getReceivedSalesContractMoney(contract: Contract): ReceivedSalesContractMoneySnapshot | null;
73
+ /** Validate and canonicalize exact received money, retaining unknowns as null. */
74
+ export declare function validateReceivedPurchaseMoneyFacts(value: unknown): ReceivedPurchaseMoneyFacts;
75
+ /** Read validated received evidence; calculated contracts return null. */
76
+ export declare function getReceivedPurchaseMoney(contract: Pick<Contract, 'moneyAuthority' | 'receivedPurchaseMoneyJson'>): ReceivedPurchaseMoneySnapshot | null;
77
+ /** Record immutable source facts on one empty draft SupplierQuote or PurchaseOrder, retry safely. */
78
+ export declare function recordReceivedPurchaseMoney(input: RecordReceivedPurchaseMoneyInput): Promise<ReceivedPurchaseMoneySnapshot>;
79
+ /** A received order cannot silently disappear from tax reporting when facts are unknown. */
80
+ export declare class ReceivedPurchaseTaxClassificationRequired extends Error {
81
+ readonly contractId: string;
82
+ readonly code = "RECEIVED_PURCHASE_TAX_CLASSIFICATION_REQUIRED";
83
+ constructor(contractId: string);
84
+ }
85
+ /** @internal Project explicitly classified source facts without inventing DocumentTax rates. */
86
+ export declare function receivedPurchaseReportFacts(contract: Contract): import('./collections/DocumentTaxCollection.js').DocumentTaxReportFact[];
87
+ //# sourceMappingURL=received-purchase-money.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"received-purchase-money.d.ts","sourceRoot":"","sources":["../src/received-purchase-money.ts"],"names":[],"mappings":"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"}
package/dist/recipes.d.ts CHANGED
@@ -382,6 +382,9 @@ export declare class InvoicingRecipe extends SmrtRecipe {
382
382
  static options: {
383
383
  readonly Invoice: {
384
384
  readonly fields: {
385
+ readonly historicalSourceKeyHash: {
386
+ readonly visibility: "hidden";
387
+ };
385
388
  readonly providerTaxAmount: {
386
389
  readonly visibility: "hidden";
387
390
  };
@@ -567,7 +570,7 @@ export declare class AgreementsRecipe extends SmrtRecipe {
567
570
  icon: string;
568
571
  description: string;
569
572
  };
570
- static models: (typeof Contract | typeof ContractLineItem)[];
573
+ static models: (typeof ContractLineItem | typeof Contract)[];
571
574
  static nav: {
572
575
  label: string;
573
576
  model: typeof Contract;
@@ -1 +1 @@
1
- {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recipes.d.ts","sourceRoot":"","sources":["../src/recipes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function withRetentionAccountingAuthority<T>(tenantId: string, invoiceId: string, operation: () => Promise<T>): Promise<T>;
2
+ export declare function hasRetentionAccountingAuthority(tenantId: string | null | undefined, invoiceId: string | null | undefined): boolean;
3
+ //# sourceMappingURL=retention-accounting-internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retention-accounting-internal.d.ts","sourceRoot":"","sources":["../src/retention-accounting-internal.ts"],"names":[],"mappings":"AAOA,wBAAgB,gCAAgC,CAAC,CAAC,EAChD,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAEZ;AACD,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACnC,OAAO,CAOT"}