@mj-biz-apps/orders-core-entities-server 0.0.1 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/LICENSE +183 -0
  2. package/README.md +141 -2
  3. package/dist/AccountingBridge.d.ts +65 -0
  4. package/dist/AccountingBridge.d.ts.map +1 -0
  5. package/dist/AccountingBridge.js +102 -0
  6. package/dist/AccountingBridge.js.map +1 -0
  7. package/dist/AdvanceOrderStateOperation.d.ts +80 -0
  8. package/dist/AdvanceOrderStateOperation.d.ts.map +1 -0
  9. package/dist/AdvanceOrderStateOperation.js +267 -0
  10. package/dist/AdvanceOrderStateOperation.js.map +1 -0
  11. package/dist/ApplyAccountCreditOperation.d.ts +97 -0
  12. package/dist/ApplyAccountCreditOperation.d.ts.map +1 -0
  13. package/dist/ApplyAccountCreditOperation.js +275 -0
  14. package/dist/ApplyAccountCreditOperation.js.map +1 -0
  15. package/dist/BaseDeliveryChannel.d.ts +106 -0
  16. package/dist/BaseDeliveryChannel.d.ts.map +1 -0
  17. package/dist/BaseDeliveryChannel.js +36 -0
  18. package/dist/BaseDeliveryChannel.js.map +1 -0
  19. package/dist/BasePaymentProvider.d.ts +239 -0
  20. package/dist/BasePaymentProvider.d.ts.map +1 -0
  21. package/dist/BasePaymentProvider.js +91 -0
  22. package/dist/BasePaymentProvider.js.map +1 -0
  23. package/dist/BundleBehavior.d.ts +139 -0
  24. package/dist/BundleBehavior.d.ts.map +1 -0
  25. package/dist/BundleBehavior.js +173 -0
  26. package/dist/BundleBehavior.js.map +1 -0
  27. package/dist/BundleEngine.d.ts +60 -0
  28. package/dist/BundleEngine.d.ts.map +1 -0
  29. package/dist/BundleEngine.js +197 -0
  30. package/dist/BundleEngine.js.map +1 -0
  31. package/dist/CancelSubscriptionOperation.d.ts +98 -0
  32. package/dist/CancelSubscriptionOperation.d.ts.map +1 -0
  33. package/dist/CancelSubscriptionOperation.js +317 -0
  34. package/dist/CancelSubscriptionOperation.js.map +1 -0
  35. package/dist/CapturePaymentOperation.d.ts +62 -0
  36. package/dist/CapturePaymentOperation.d.ts.map +1 -0
  37. package/dist/CapturePaymentOperation.js +463 -0
  38. package/dist/CapturePaymentOperation.js.map +1 -0
  39. package/dist/CheckEntitlementOperation.d.ts +27 -0
  40. package/dist/CheckEntitlementOperation.d.ts.map +1 -0
  41. package/dist/CheckEntitlementOperation.js +45 -0
  42. package/dist/CheckEntitlementOperation.js.map +1 -0
  43. package/dist/CheckoutSessionService.d.ts +258 -0
  44. package/dist/CheckoutSessionService.d.ts.map +1 -0
  45. package/dist/CheckoutSessionService.js +1557 -0
  46. package/dist/CheckoutSessionService.js.map +1 -0
  47. package/dist/DeliveryBehavior.d.ts +121 -0
  48. package/dist/DeliveryBehavior.d.ts.map +1 -0
  49. package/dist/DeliveryBehavior.js +145 -0
  50. package/dist/DeliveryBehavior.js.map +1 -0
  51. package/dist/DeliveryRecipientResolver.d.ts +38 -0
  52. package/dist/DeliveryRecipientResolver.d.ts.map +1 -0
  53. package/dist/DeliveryRecipientResolver.js +93 -0
  54. package/dist/DeliveryRecipientResolver.js.map +1 -0
  55. package/dist/DeliveryResolver.d.ts +14 -0
  56. package/dist/DeliveryResolver.d.ts.map +1 -0
  57. package/dist/DeliveryResolver.js +45 -0
  58. package/dist/DeliveryResolver.js.map +1 -0
  59. package/dist/EmailDeliveryChannel.d.ts +31 -0
  60. package/dist/EmailDeliveryChannel.d.ts.map +1 -0
  61. package/dist/EmailDeliveryChannel.js +158 -0
  62. package/dist/EmailDeliveryChannel.js.map +1 -0
  63. package/dist/EntitlementBehavior.d.ts +235 -0
  64. package/dist/EntitlementBehavior.d.ts.map +1 -0
  65. package/dist/EntitlementBehavior.js +330 -0
  66. package/dist/EntitlementBehavior.js.map +1 -0
  67. package/dist/EntitlementEngine.d.ts +97 -0
  68. package/dist/EntitlementEngine.d.ts.map +1 -0
  69. package/dist/EntitlementEngine.js +338 -0
  70. package/dist/EntitlementEngine.js.map +1 -0
  71. package/dist/EntitlementGrantClaimDriver.d.ts +42 -0
  72. package/dist/EntitlementGrantClaimDriver.d.ts.map +1 -0
  73. package/dist/EntitlementGrantClaimDriver.js +158 -0
  74. package/dist/EntitlementGrantClaimDriver.js.map +1 -0
  75. package/dist/EntitlementRead.d.ts +82 -0
  76. package/dist/EntitlementRead.d.ts.map +1 -0
  77. package/dist/EntitlementRead.js +368 -0
  78. package/dist/EntitlementRead.js.map +1 -0
  79. package/dist/FulfillOrderLinesOperation.d.ts +34 -0
  80. package/dist/FulfillOrderLinesOperation.d.ts.map +1 -0
  81. package/dist/FulfillOrderLinesOperation.js +208 -0
  82. package/dist/FulfillOrderLinesOperation.js.map +1 -0
  83. package/dist/FulfillmentBehavior.d.ts +101 -0
  84. package/dist/FulfillmentBehavior.d.ts.map +1 -0
  85. package/dist/FulfillmentBehavior.js +145 -0
  86. package/dist/FulfillmentBehavior.js.map +1 -0
  87. package/dist/GLAccountResolver.d.ts +123 -0
  88. package/dist/GLAccountResolver.d.ts.map +1 -0
  89. package/dist/GLAccountResolver.js +175 -0
  90. package/dist/GLAccountResolver.js.map +1 -0
  91. package/dist/GetFulfillmentQueueOperation.d.ts +35 -0
  92. package/dist/GetFulfillmentQueueOperation.d.ts.map +1 -0
  93. package/dist/GetFulfillmentQueueOperation.js +221 -0
  94. package/dist/GetFulfillmentQueueOperation.js.map +1 -0
  95. package/dist/GetOverdueWorklistOperation.d.ts +41 -0
  96. package/dist/GetOverdueWorklistOperation.d.ts.map +1 -0
  97. package/dist/GetOverdueWorklistOperation.js +210 -0
  98. package/dist/GetOverdueWorklistOperation.js.map +1 -0
  99. package/dist/GiftCardBehavior.d.ts +97 -0
  100. package/dist/GiftCardBehavior.d.ts.map +1 -0
  101. package/dist/GiftCardBehavior.js +121 -0
  102. package/dist/GiftCardBehavior.js.map +1 -0
  103. package/dist/GiftCardEngine.d.ts +59 -0
  104. package/dist/GiftCardEngine.d.ts.map +1 -0
  105. package/dist/GiftCardEngine.js +197 -0
  106. package/dist/GiftCardEngine.js.map +1 -0
  107. package/dist/GuestOrderClaimDriver.d.ts +36 -0
  108. package/dist/GuestOrderClaimDriver.d.ts.map +1 -0
  109. package/dist/GuestOrderClaimDriver.js +161 -0
  110. package/dist/GuestOrderClaimDriver.js.map +1 -0
  111. package/dist/InvoiceBehavior.d.ts +394 -0
  112. package/dist/InvoiceBehavior.d.ts.map +1 -0
  113. package/dist/InvoiceBehavior.js +496 -0
  114. package/dist/InvoiceBehavior.js.map +1 -0
  115. package/dist/InvoiceBuilder.d.ts +48 -0
  116. package/dist/InvoiceBuilder.d.ts.map +1 -0
  117. package/dist/InvoiceBuilder.js +352 -0
  118. package/dist/InvoiceBuilder.js.map +1 -0
  119. package/dist/InvoiceDisplay.d.ts +96 -0
  120. package/dist/InvoiceDisplay.d.ts.map +1 -0
  121. package/dist/InvoiceDisplay.js +121 -0
  122. package/dist/InvoiceDisplay.js.map +1 -0
  123. package/dist/ListEntitlementsOperation.d.ts +21 -0
  124. package/dist/ListEntitlementsOperation.d.ts.map +1 -0
  125. package/dist/ListEntitlementsOperation.js +39 -0
  126. package/dist/ListEntitlementsOperation.js.map +1 -0
  127. package/dist/ManualPaymentProvider.d.ts +19 -0
  128. package/dist/ManualPaymentProvider.d.ts.map +1 -0
  129. package/dist/ManualPaymentProvider.js +92 -0
  130. package/dist/ManualPaymentProvider.js.map +1 -0
  131. package/dist/OrderEntityServer.d.ts +542 -0
  132. package/dist/OrderEntityServer.d.ts.map +1 -0
  133. package/dist/OrderEntityServer.js +2100 -0
  134. package/dist/OrderEntityServer.js.map +1 -0
  135. package/dist/OrderJournalEntryFactory.d.ts +140 -0
  136. package/dist/OrderJournalEntryFactory.d.ts.map +1 -0
  137. package/dist/OrderJournalEntryFactory.js +466 -0
  138. package/dist/OrderJournalEntryFactory.js.map +1 -0
  139. package/dist/OrderLineEntityServer.d.ts +90 -0
  140. package/dist/OrderLineEntityServer.d.ts.map +1 -0
  141. package/dist/OrderLineEntityServer.js +260 -0
  142. package/dist/OrderLineEntityServer.js.map +1 -0
  143. package/dist/OrdersSettings.d.ts +36 -0
  144. package/dist/OrdersSettings.d.ts.map +1 -0
  145. package/dist/OrdersSettings.js +147 -0
  146. package/dist/OrdersSettings.js.map +1 -0
  147. package/dist/PaymentAllocationFactory.d.ts +128 -0
  148. package/dist/PaymentAllocationFactory.d.ts.map +1 -0
  149. package/dist/PaymentAllocationFactory.js +235 -0
  150. package/dist/PaymentAllocationFactory.js.map +1 -0
  151. package/dist/PaymentHeaderEntityServer.d.ts +180 -0
  152. package/dist/PaymentHeaderEntityServer.d.ts.map +1 -0
  153. package/dist/PaymentHeaderEntityServer.js +656 -0
  154. package/dist/PaymentHeaderEntityServer.js.map +1 -0
  155. package/dist/PaymentIntentService.d.ts +101 -0
  156. package/dist/PaymentIntentService.d.ts.map +1 -0
  157. package/dist/PaymentIntentService.js +150 -0
  158. package/dist/PaymentIntentService.js.map +1 -0
  159. package/dist/PaymentJournalEntryFactory.d.ts +99 -0
  160. package/dist/PaymentJournalEntryFactory.d.ts.map +1 -0
  161. package/dist/PaymentJournalEntryFactory.js +127 -0
  162. package/dist/PaymentJournalEntryFactory.js.map +1 -0
  163. package/dist/PaymentLineEntityServer.d.ts +73 -0
  164. package/dist/PaymentLineEntityServer.d.ts.map +1 -0
  165. package/dist/PaymentLineEntityServer.js +303 -0
  166. package/dist/PaymentLineEntityServer.js.map +1 -0
  167. package/dist/PaymentProviderBehavior.d.ts +222 -0
  168. package/dist/PaymentProviderBehavior.d.ts.map +1 -0
  169. package/dist/PaymentProviderBehavior.js +368 -0
  170. package/dist/PaymentProviderBehavior.js.map +1 -0
  171. package/dist/PaymentProviderResolver.d.ts +84 -0
  172. package/dist/PaymentProviderResolver.d.ts.map +1 -0
  173. package/dist/PaymentProviderResolver.js +220 -0
  174. package/dist/PaymentProviderResolver.js.map +1 -0
  175. package/dist/PaymentReversalFactory.d.ts +107 -0
  176. package/dist/PaymentReversalFactory.d.ts.map +1 -0
  177. package/dist/PaymentReversalFactory.js +174 -0
  178. package/dist/PaymentReversalFactory.js.map +1 -0
  179. package/dist/PaymentSettlement.d.ts +56 -0
  180. package/dist/PaymentSettlement.d.ts.map +1 -0
  181. package/dist/PaymentSettlement.js +243 -0
  182. package/dist/PaymentSettlement.js.map +1 -0
  183. package/dist/PaymentTermsBehavior.d.ts +109 -0
  184. package/dist/PaymentTermsBehavior.d.ts.map +1 -0
  185. package/dist/PaymentTermsBehavior.js +172 -0
  186. package/dist/PaymentTermsBehavior.js.map +1 -0
  187. package/dist/PaymentWebhookHandler.d.ts +103 -0
  188. package/dist/PaymentWebhookHandler.d.ts.map +1 -0
  189. package/dist/PaymentWebhookHandler.js +246 -0
  190. package/dist/PaymentWebhookHandler.js.map +1 -0
  191. package/dist/PreviewPriceOperation.d.ts +62 -0
  192. package/dist/PreviewPriceOperation.d.ts.map +1 -0
  193. package/dist/PreviewPriceOperation.js +161 -0
  194. package/dist/PreviewPriceOperation.js.map +1 -0
  195. package/dist/PriceOrderOperation.d.ts +93 -0
  196. package/dist/PriceOrderOperation.d.ts.map +1 -0
  197. package/dist/PriceOrderOperation.js +146 -0
  198. package/dist/PriceOrderOperation.js.map +1 -0
  199. package/dist/ProductPriceEntityServer.d.ts +34 -0
  200. package/dist/ProductPriceEntityServer.d.ts.map +1 -0
  201. package/dist/ProductPriceEntityServer.js +97 -0
  202. package/dist/ProductPriceEntityServer.js.map +1 -0
  203. package/dist/RefundPaymentOperation.d.ts +61 -0
  204. package/dist/RefundPaymentOperation.d.ts.map +1 -0
  205. package/dist/RefundPaymentOperation.js +177 -0
  206. package/dist/RefundPaymentOperation.js.map +1 -0
  207. package/dist/RevenueRecognition.d.ts +76 -0
  208. package/dist/RevenueRecognition.d.ts.map +1 -0
  209. package/dist/RevenueRecognition.js +133 -0
  210. package/dist/RevenueRecognition.js.map +1 -0
  211. package/dist/ReversalBehavior.d.ts +82 -0
  212. package/dist/ReversalBehavior.d.ts.map +1 -0
  213. package/dist/ReversalBehavior.js +100 -0
  214. package/dist/ReversalBehavior.js.map +1 -0
  215. package/dist/ReversalResolver.d.ts +37 -0
  216. package/dist/ReversalResolver.d.ts.map +1 -0
  217. package/dist/ReversalResolver.js +96 -0
  218. package/dist/ReversalResolver.js.map +1 -0
  219. package/dist/SpawnRenewalsOperation.d.ts +109 -0
  220. package/dist/SpawnRenewalsOperation.d.ts.map +1 -0
  221. package/dist/SpawnRenewalsOperation.js +295 -0
  222. package/dist/SpawnRenewalsOperation.js.map +1 -0
  223. package/dist/StoredValuePaymentProvider.d.ts +52 -0
  224. package/dist/StoredValuePaymentProvider.d.ts.map +1 -0
  225. package/dist/StoredValuePaymentProvider.js +205 -0
  226. package/dist/StoredValuePaymentProvider.js.map +1 -0
  227. package/dist/StripeACHPaymentProvider.d.ts +50 -0
  228. package/dist/StripeACHPaymentProvider.d.ts.map +1 -0
  229. package/dist/StripeACHPaymentProvider.js +211 -0
  230. package/dist/StripeACHPaymentProvider.js.map +1 -0
  231. package/dist/StripePaymentProvider.d.ts +83 -0
  232. package/dist/StripePaymentProvider.d.ts.map +1 -0
  233. package/dist/StripePaymentProvider.js +442 -0
  234. package/dist/StripePaymentProvider.js.map +1 -0
  235. package/dist/SubscriptionBehavior.d.ts +197 -0
  236. package/dist/SubscriptionBehavior.d.ts.map +1 -0
  237. package/dist/SubscriptionBehavior.js +415 -0
  238. package/dist/SubscriptionBehavior.js.map +1 -0
  239. package/dist/checkoutCaptureAlert.d.ts +16 -0
  240. package/dist/checkoutCaptureAlert.d.ts.map +1 -0
  241. package/dist/checkoutCaptureAlert.js +55 -0
  242. package/dist/checkoutCaptureAlert.js.map +1 -0
  243. package/dist/checkoutCaptureRetry.d.ts +27 -0
  244. package/dist/checkoutCaptureRetry.d.ts.map +1 -0
  245. package/dist/checkoutCaptureRetry.js +50 -0
  246. package/dist/checkoutCaptureRetry.js.map +1 -0
  247. package/dist/claimDriverHelpers.d.ts +15 -0
  248. package/dist/claimDriverHelpers.d.ts.map +1 -0
  249. package/dist/claimDriverHelpers.js +34 -0
  250. package/dist/claimDriverHelpers.js.map +1 -0
  251. package/dist/entity-names.d.ts +15 -0
  252. package/dist/entity-names.d.ts.map +1 -0
  253. package/dist/entity-names.js +15 -0
  254. package/dist/entity-names.js.map +1 -0
  255. package/dist/identityClaimContracts.d.ts +118 -0
  256. package/dist/identityClaimContracts.d.ts.map +1 -0
  257. package/dist/identityClaimContracts.js +58 -0
  258. package/dist/identityClaimContracts.js.map +1 -0
  259. package/dist/index.d.ts +126 -0
  260. package/dist/index.d.ts.map +1 -0
  261. package/dist/index.js +115 -0
  262. package/dist/index.js.map +1 -0
  263. package/dist/sql-guards.d.ts +78 -0
  264. package/dist/sql-guards.d.ts.map +1 -0
  265. package/dist/sql-guards.js +115 -0
  266. package/dist/sql-guards.js.map +1 -0
  267. package/package.json +50 -5
@@ -0,0 +1,466 @@
1
+ /**
2
+ * OrderJournalEntryFactory — turns an order's lines into balanced journal-entry drafts.
3
+ *
4
+ * Plan D10: ONE BOOKING JE PER ORDER LINE, always — even multiple lines of the same company. The
5
+ * "order-level journal entry" is a UI aggregation of the line JEs, never a row.
6
+ *
7
+ * Plan D11 — the booking entry per line:
8
+ *
9
+ * Dr Accounts Receivable net (+ tax when the tax build lands)
10
+ * Dr Sales Discounts discount (contra; omitted when 0)
11
+ * Cr Sales gross (recognized at booking)
12
+ * Cr Deferred Revenue gross (deferred — released per the schedule)
13
+ *
14
+ * where net is the LINE'S OWN stored LineTotalNet — the authority, not a recomputation —
15
+ * discount = (rate-gross × DiscountPct) + DiscountAmount, and gross = net + discount.
16
+ * Both discount fields are applied because the line applies both.
17
+ * The entry balances by construction: net + discount = gross.
18
+ *
19
+ * Plan D14/D43 — RECOGNITION. The product's `RevenueRecognitionType` names a pluggable driver
20
+ * (see ./RevenueRecognition.ts) that returns a schedule of dates and amounts. For a DEFERRED type
21
+ * we emit one REAL FORWARD-DATED entry per schedule slice:
22
+ *
23
+ * Dr Deferred Revenue slice
24
+ * Cr Sales slice (EffectiveDate = the recognition date)
25
+ *
26
+ * No materializer, no wake-up job — the ledger holds the future. A 12-month subscription books one
27
+ * AR/Deferred entry plus twelve dated release entries, all inside the same booking transaction.
28
+ * An UpFront line skips the deferral round-trip entirely and credits Sales directly.
29
+ *
30
+ * Plan D31 — DIMENSIONS. Each line's `OrderLineDimension` tags ride onto every JE line the line
31
+ * produces, so departmental/segment reporting survives into the ledger and through batch
32
+ * summarization. Where a resolved GL account link REQUIRES a dimension the line hasn't tagged, we
33
+ * fail loudly rather than book an entry that can't be reported on.
34
+ *
35
+ * NEGATIVE QUANTITIES are the reversal mechanism (plan D16) — they flow through the same
36
+ * arithmetic and mirror every entry, so returns and credit memos need no special path.
37
+ *
38
+ * CONNECTS TO:
39
+ * RESOLVER: GLAccountResolver (./GLAccountResolver.ts) — role → account, with the company guard
40
+ * DRIVERS: RevenueRecognitionDriver (./RevenueRecognition.ts) — the schedule
41
+ * CALLER: OrderEntityServer.Save (./OrderEntityServer.ts) — owns the transaction
42
+ */
43
+ import { RunView } from '@memberjunction/core';
44
+ import { MJGlobal } from '@memberjunction/global';
45
+ import { GL_ROLE, GLAccountResolutionError } from './GLAccountResolver.js';
46
+ import { RevenueRecognitionDriver } from './RevenueRecognition.js';
47
+ import { GIFT_CARD_PRODUCT_TYPE_CODE } from './GiftCardBehavior.js';
48
+ /**
49
+ * Swap every line's debit and credit side. This is what "reversing" means in double-entry: the
50
+ * original `Dr AR / Cr Deferred Revenue` becomes `Dr Deferred Revenue / Cr AR`, at the same
51
+ * positive amount. Returns the input untouched when `reverse` is false, so callers can apply it
52
+ * unconditionally.
53
+ */
54
+ function mirrorIf(reverse, lines) {
55
+ if (!reverse)
56
+ return lines;
57
+ return lines.map((l) => ({
58
+ ...l,
59
+ DebitAmount: l.CreditAmount,
60
+ CreditAmount: l.DebitAmount,
61
+ }));
62
+ }
63
+ function money(value) {
64
+ return Math.round((value + Number.EPSILON) * 100) / 100;
65
+ }
66
+ function isoDate(d) {
67
+ return new Date(d).toISOString().slice(0, 10);
68
+ }
69
+ export class OrderJournalEntryFactory {
70
+ constructor(_resolver, _orderLineEntityID, _subscriptionTermEntityID, _chargeTypeEntityID, _provider, _contextUser) {
71
+ this._resolver = _resolver;
72
+ this._orderLineEntityID = _orderLineEntityID;
73
+ this._subscriptionTermEntityID = _subscriptionTermEntityID;
74
+ this._chargeTypeEntityID = _chargeTypeEntityID;
75
+ this._provider = _provider;
76
+ this._contextUser = _contextUser;
77
+ }
78
+ /**
79
+ * Build every draft the order needs: one booking entry per line, plus the forward-dated
80
+ * recognition entries for deferred lines. Throws on the first line that cannot be resolved —
81
+ * booking is all-or-none, so partial results have no value.
82
+ */
83
+ async BuildDrafts(order, lines,
84
+ /**
85
+ * Terms created for subscription lines during this confirm, keyed by OrderLineID (D46).
86
+ * Recognition entries anchor to the TERM — the release is caused by time passing over that
87
+ * coverage period. The booking entry stays on the line: that is caused by the sale.
88
+ */
89
+ termsByLine,
90
+ /** Months per recognition slice, per line, from the subscription type's cadence (D45). */
91
+ recognitionMonthsByLine) {
92
+ if (lines.length === 0) {
93
+ throw new Error(`Order ${order.OrderNumber} has no lines to book.`);
94
+ }
95
+ const products = await this.loadProducts(lines.map((l) => l.ProductID));
96
+ const giftCardTypeIDs = await this.loadGiftCardTypeIDs();
97
+ const revRecTypes = await this.loadRevRecTypes();
98
+ const dimensions = await this.loadLineDimensions(lines.map((l) => l.ID));
99
+ const effectiveDate = this.effectiveDateOf(order);
100
+ const asOf = new Date(effectiveDate);
101
+ const drafts = [];
102
+ for (const line of lines) {
103
+ drafts.push(...(await this.buildLineDrafts(order, line, products, revRecTypes, dimensions, effectiveDate, asOf, giftCardTypeIDs, termsByLine?.get(line.ID), recognitionMonthsByLine?.get(line.ID))));
104
+ }
105
+ return drafts;
106
+ }
107
+ async buildLineDrafts(order, line, products, revRecTypes, dimensions, effectiveDate, asOf, giftCardTypeIDs, term, recognitionMonths) {
108
+ const product = products.get(line.ProductID);
109
+ if (!product) {
110
+ throw new Error(`Order line ${line.ID} references product ${line.ProductID}, which was not found.`);
111
+ }
112
+ const revRec = revRecTypes.get(product.RevenueRecognitionTypeID);
113
+ if (!revRec) {
114
+ throw new Error(`Product '${product.Name}' has no valid revenue recognition type — cannot determine ` +
115
+ `whether its revenue is earned at booking or over time.`);
116
+ }
117
+ // The line's company is the denormalized stamp of the product's company (plan D6).
118
+ const companyID = line.CompanyID ?? product.CompanyID;
119
+ const lineDims = dimensions.get(line.ID) ?? [];
120
+ // REVERSALS ARE MIRRORED, NOT NEGATED (D16). A negative quantity means "unwind this much of
121
+ // that purchase" — and the correct double-entry for unwinding is the SAME accounts with the
122
+ // debit and credit sides swapped, at a positive amount. Feeding a negative amount through
123
+ // instead produces `Dr AR -593.52`, which accounting rightly refuses: a ledger line with a
124
+ // negative debit is not a thing. So every amount below is computed on the ABSOLUTE quantity
125
+ // and the finished lines are flipped once, at the end, when the line reverses.
126
+ const isReversal = line.Quantity < 0;
127
+ // THE LINE IS THE AUTHORITY ON ITS OWN MONEY, and by booking time it has been
128
+ // computed and stored. This used to re-derive gross as quantity × UnitPrice —
129
+ // a fourth copy of a formula that is only correct for PerUnit pricing. On a
130
+ // Flat rule the unit price is a DERIVED rate that cannot always represent the
131
+ // total, so the entry mirrored the wrong figure: a flat 100 at quantity 3
132
+ // booked 99.99, at quantity 7 booked 100.03. The entry still BALANCED, which
133
+ // is exactly the failure this file's own header warns about — AR merely
134
+ // differs from the line total and nothing downstream reports it.
135
+ //
136
+ // Anchoring net to the stored LineTotalNet and deriving gross as net + discount
137
+ // keeps `net + discount = gross` true by construction, and makes the entry agree
138
+ // with the line by definition rather than by two computations happening to
139
+ // match. The rate is still used for the DISCOUNT split, which is the only part
140
+ // the line does not store separately.
141
+ const grossFromRate = money(Math.abs(line.Quantity) * line.UnitPrice);
142
+ // BOTH discount fields, and in the same order OrderLineEntityServer applies them (D70).
143
+ // The journal entry must mirror the line's arithmetic exactly — if the two disagree, the
144
+ // entry still BALANCES (AR simply differs from the line total) and nothing downstream
145
+ // reports it, which is the failure mode this whole area keeps producing.
146
+ const pctDiscount = money(grossFromRate * (line.DiscountPct ?? 0));
147
+ const amountDiscount = money(Math.min(Math.max(0, grossFromRate - pctDiscount), line.DiscountAmount ?? 0));
148
+ const discount = money(pctDiscount + amountDiscount);
149
+ const net = money(Math.abs(Number(line.LineTotalNet ?? 0)));
150
+ const gross = money(net + discount);
151
+ const tax = money(Math.abs(line.LineTax ?? 0));
152
+ const charges = money(Math.abs(line.ChargeAmount ?? 0));
153
+ const resolve = (role) => this._resolver.Resolve(role, product.ID, product.ProductCategoryID, companyID, asOf, product.ProductTypeID);
154
+ const arAccount = await resolve(GL_ROLE.AccountsReceivable);
155
+ const salesAccount = await resolve(GL_ROLE.Sales);
156
+ // SELLING A GIFT CARD EARNS NOTHING (D44). Money has come in and goods are owed, so the
157
+ // credit is a LIABILITY. Recognising here and again when the card is spent is the classic
158
+ // gift-card double-count, and it hides well: both entries balance, the order reconciles,
159
+ // and only the revenue figure is wrong.
160
+ //
161
+ // It also means NO revenue-recognition schedule. A deferred type releases on dates; a gift
162
+ // card releases when somebody spends it, which is an event on a different order entirely.
163
+ const isGiftCard = giftCardTypeIDs.has(product.ProductTypeID);
164
+ let bookingCreditAccount;
165
+ let creditLabel;
166
+ if (isGiftCard) {
167
+ try {
168
+ bookingCreditAccount = await resolve(GL_ROLE.GiftCardLiability);
169
+ creditLabel = 'Gift card liability';
170
+ }
171
+ catch {
172
+ // Same tolerance as Processing Fee: a role accounting has not seeded must not take
173
+ // the sale down. Deferred Revenue is the same SHAPE of obligation, so the entry stays
174
+ // correct and balanced — just coarser than a dedicated card liability. Reported
175
+ // rather than swallowed, because the difference matters at year end.
176
+ bookingCreditAccount = await resolve(GL_ROLE.DeferredRevenue);
177
+ creditLabel = 'Gift card liability (in Deferred Revenue)';
178
+ console.warn(`Order line ${line.ID}: no 'Gift Card Liability' GL account is linked for company ` +
179
+ `${companyID}, so the card's liability was booked to Deferred Revenue instead. ` +
180
+ `The entry balances and no revenue is overstated, but the two obligations are ` +
181
+ `now indistinguishable on the balance sheet. Link a Gift Card Liability account.`);
182
+ }
183
+ }
184
+ else if (revRec.IsDeferred) {
185
+ // Deferred types park the credit in Deferred Revenue until the schedule releases it.
186
+ bookingCreditAccount = await resolve(GL_ROLE.DeferredRevenue);
187
+ creditLabel = 'Deferred revenue';
188
+ }
189
+ else {
190
+ bookingCreditAccount = salesAccount;
191
+ creditLabel = 'Sales';
192
+ }
193
+ let discountAccount = null;
194
+ if (discount !== 0) {
195
+ try {
196
+ discountAccount = await resolve(GL_ROLE.SalesDiscounts);
197
+ }
198
+ catch {
199
+ discountAccount = null; // plan D11 — net into the revenue credit instead
200
+ }
201
+ }
202
+ // ── the booking entry (D10/D11) ──
203
+ const bookingLines = [
204
+ {
205
+ GLAccountID: arAccount,
206
+ DebitAmount: money(net + tax + charges),
207
+ Description: `AR — ${product.Name}`,
208
+ Dimensions: lineDims,
209
+ },
210
+ {
211
+ GLAccountID: bookingCreditAccount,
212
+ CreditAmount: discountAccount ? gross : net,
213
+ Description: `${creditLabel} — ${product.Name}`,
214
+ Dimensions: lineDims,
215
+ },
216
+ ];
217
+ if (discountAccount) {
218
+ bookingLines.push({
219
+ GLAccountID: discountAccount,
220
+ DebitAmount: discount,
221
+ Description: `Discount — ${product.Name}`,
222
+ Dimensions: lineDims,
223
+ });
224
+ }
225
+ // ── CHARGE AND TAX CREDITS (D71) ──
226
+ // AR is debited for net + tax + charges, so every one of those needs a matching credit or
227
+ // the entry does not balance. Tax has been in the AR debit since booking was written and had
228
+ // no credit at all — it simply had never been non-zero, which is the kind of latent break
229
+ // that only surfaces the day the feature is used.
230
+ //
231
+ // Each charge credits an account resolved from its CHARGE TYPE, so shipping revenue and a
232
+ // tax liability go to different places without this factory knowing what either means. The
233
+ // role name is a lookup key, not a claim about the account's nature — a tax charge links to
234
+ // a liability account through the same mechanism.
235
+ const chargeCredits = await this.chargeCreditsFor(line, companyID, asOf);
236
+ for (const c of chargeCredits) {
237
+ bookingLines.push({
238
+ GLAccountID: c.GLAccountID,
239
+ CreditAmount: c.Amount,
240
+ Description: `${c.Label} — ${product.Name}`,
241
+ Dimensions: lineDims,
242
+ });
243
+ }
244
+ // Drop zero-amount lines. A fully-discounted line — a comped ticket, a 100%-off promotion —
245
+ // has net 0, and accounting rightly refuses a JE line for nothing (MALFORMED_DRAFT). The
246
+ // entry itself is still real and still balances: Dr Sales Discounts / Cr Sales for the
247
+ // discount. Without this a free item cannot be ordered at all, which is a legitimate thing
248
+ // to sell.
249
+ const bookingEntryLines = mirrorIf(isReversal, bookingLines.filter((l) => money(l.DebitAmount ?? 0) !== 0 || money(l.CreditAmount ?? 0) !== 0));
250
+ // NOTHING TO BOOK is a legitimate outcome, not a failure. A fully-comped line — 100% off, or
251
+ // a free item — nets to zero, and when the discount has no contra account it nets into the
252
+ // sales credit too, leaving an entry with no non-zero side. Double-entry needs two lines, so
253
+ // emitting one here would refuse the whole order for a line that has no ledger impact at all.
254
+ // The line still exists, still shows on the invoice, and still recognizes nothing.
255
+ const hasBooking = bookingEntryLines.length >= 2;
256
+ if (hasBooking) {
257
+ this.assertBalanced(bookingEntryLines, order, line, 'booking');
258
+ }
259
+ const out = hasBooking
260
+ ? [
261
+ {
262
+ OrderLineID: line.ID,
263
+ IsBooking: true,
264
+ Draft: {
265
+ EffectiveDate: effectiveDate,
266
+ EntryType: 'OrderBooking',
267
+ Description: `Order ${order.OrderNumber} line ${line.LineNumber} — ` +
268
+ `${isReversal ? 'REVERSAL of ' : ''}${product.Name}`,
269
+ LinkedEntityID: this._orderLineEntityID,
270
+ LinkedRecordID: line.ID,
271
+ Lines: bookingEntryLines,
272
+ },
273
+ },
274
+ ]
275
+ : [];
276
+ // ── the forward-dated releases (D14/D43) ──
277
+ if (revRec.IsDeferred && !isGiftCard) {
278
+ // A subscription line's coverage window comes from its TERM (which applied anchoring,
279
+ // deferral and proration); a non-subscription deferred line uses the line's own dates.
280
+ const schedule = this.driverFor(revRec).BuildSchedule({
281
+ Amount: term ? term.Amount : net,
282
+ BookingDate: new Date(effectiveDate),
283
+ ServicePeriodStart: term ? term.StartDate : (line.ServicePeriodStart ? new Date(line.ServicePeriodStart) : null),
284
+ ServicePeriodEnd: term ? term.EndDate : (line.ServicePeriodEnd ? new Date(line.ServicePeriodEnd) : null),
285
+ ProductName: product.Name,
286
+ PeriodMonths: recognitionMonths,
287
+ });
288
+ for (const entry of schedule.Entries) {
289
+ const releaseLines = [
290
+ {
291
+ GLAccountID: bookingCreditAccount,
292
+ DebitAmount: entry.Amount,
293
+ Description: `Release deferred — ${product.Name}`,
294
+ Dimensions: lineDims,
295
+ },
296
+ {
297
+ GLAccountID: salesAccount,
298
+ CreditAmount: entry.Amount,
299
+ Description: `Revenue — ${product.Name}`,
300
+ Dimensions: lineDims,
301
+ },
302
+ ];
303
+ const releaseEntryLines = mirrorIf(isReversal, releaseLines);
304
+ this.assertBalanced(releaseEntryLines, order, line, 'recognition');
305
+ out.push({
306
+ OrderLineID: line.ID,
307
+ IsBooking: false,
308
+ SubscriptionTermID: term?.ID,
309
+ RecognitionEntry: entry,
310
+ Draft: {
311
+ EffectiveDate: isoDate(entry.RecognitionDate),
312
+ EntryType: 'RevenueRecognition',
313
+ Description: `Order ${order.OrderNumber} line ${line.LineNumber} — ` +
314
+ `${isReversal ? 'unrecognize' : 'recognize'} ${product.Name}`,
315
+ // D46: anchor to the TERM when there is one; otherwise the line (event
316
+ // products are deferred but have no subscription and therefore no term).
317
+ LinkedEntityID: term ? this._subscriptionTermEntityID : this._orderLineEntityID,
318
+ LinkedRecordID: term ? term.ID : line.ID,
319
+ Lines: releaseEntryLines,
320
+ },
321
+ });
322
+ }
323
+ }
324
+ return out;
325
+ }
326
+ /** Resolve the driver through MJ's ClassFactory so subclasses registered on the same key win. */
327
+ driverFor(revRec) {
328
+ const driver = MJGlobal.Instance.ClassFactory.CreateInstance(RevenueRecognitionDriver, revRec.DriverClass);
329
+ if (!driver) {
330
+ throw new Error(`Revenue recognition type '${revRec.Code}' names driver '${revRec.DriverClass}', which is ` +
331
+ `not registered. Register a RevenueRecognitionDriver subclass under that key.`);
332
+ }
333
+ return driver;
334
+ }
335
+ /**
336
+ * Rounding at several independent places can drift a cent. Catch it here with a message that
337
+ * names the order line, rather than at the DB trigger, which cannot.
338
+ */
339
+ assertBalanced(lines, order, line, kind) {
340
+ const debits = money(lines.reduce((s, l) => s + (l.DebitAmount ?? 0), 0));
341
+ const credits = money(lines.reduce((s, l) => s + (l.CreditAmount ?? 0), 0));
342
+ if (debits !== credits) {
343
+ throw new Error(`The ${kind} entry for order ${order.OrderNumber} line ${line.LineNumber} does not balance: ` +
344
+ `debits ${debits} vs credits ${credits}. No entries were booked.`);
345
+ }
346
+ }
347
+ /** `OrderDate` is the accounting date (backdating is allowed and unguarded — D25). */
348
+ effectiveDateOf(order) {
349
+ return isoDate(order.OrderDate ? new Date(order.OrderDate) : new Date());
350
+ }
351
+ async loadProducts(productIDs) {
352
+ const inList = [...new Set(productIDs)].map((id) => `'${id}'`).join(',');
353
+ const rv = new RunView(this._provider);
354
+ const result = await rv.RunView({
355
+ EntityName: 'MJ_BizApps_Orders: Products',
356
+ ExtraFilter: `ID IN (${inList})`,
357
+ Fields: ['ID', 'CompanyID', 'ProductCategoryID', 'ProductTypeID', 'RevenueRecognitionTypeID', 'Name'],
358
+ ResultType: 'simple',
359
+ }, this._contextUser);
360
+ return new Map((result?.Results ?? []).map((p) => [p.ID, p]));
361
+ }
362
+ /**
363
+ * ProductType IDs whose Code marks them a gift card.
364
+ *
365
+ * Resolved by CODE rather than by a hardcoded ID because product types are per-deployment data,
366
+ * not seeded metadata with stable keys. One query for the whole draft build, not one per line.
367
+ */
368
+ async loadGiftCardTypeIDs() {
369
+ const rv = new RunView(this._provider);
370
+ const result = await rv.RunView({
371
+ EntityName: 'MJ_BizApps_Orders: Product Types',
372
+ ExtraFilter: `Code = '${GIFT_CARD_PRODUCT_TYPE_CODE}'`,
373
+ Fields: ['ID'],
374
+ ResultType: 'simple',
375
+ }, this._contextUser);
376
+ return new Set((result?.Results ?? []).map((r) => r.ID));
377
+ }
378
+ async loadRevRecTypes() {
379
+ const rv = new RunView(this._provider);
380
+ const result = await rv.RunView({
381
+ EntityName: 'MJ_BizApps_Orders: Revenue Recognition Types',
382
+ Fields: ['ID', 'Code', 'DriverClass', 'IsDeferred'],
383
+ ResultType: 'simple',
384
+ }, this._contextUser);
385
+ return new Map((result?.Results ?? []).map((t) => [t.ID, t]));
386
+ }
387
+ /** Plan D31 — the line's dimension tags ride onto every JE line it produces. */
388
+ async loadLineDimensions(lineIDs) {
389
+ const inList = lineIDs.map((id) => `'${id}'`).join(',');
390
+ const rv = new RunView(this._provider);
391
+ const result = await rv.RunView({
392
+ EntityName: 'MJ_BizApps_Orders: Order Line Dimensions',
393
+ ExtraFilter: `OrderLineID IN (${inList})`,
394
+ Fields: ['OrderLineID', 'DimensionID', 'DimensionValueID'],
395
+ ResultType: 'simple',
396
+ }, this._contextUser);
397
+ const map = new Map();
398
+ for (const row of result?.Results ?? []) {
399
+ const list = map.get(row.OrderLineID) ?? [];
400
+ list.push({ DimensionID: row.DimensionID, DimensionValueID: row.DimensionValueID });
401
+ map.set(row.OrderLineID, list);
402
+ }
403
+ return map;
404
+ }
405
+ /**
406
+ * The credit side of every charge allocated to this line, grouped by charge type (D71).
407
+ *
408
+ * Read from `OrderChargeAllocation`, which exists by the time booking runs because charges are
409
+ * written with the lines. Each charge type resolves its own GL account, so shipping revenue and
410
+ * a tax liability land in different places without this factory needing to know which is which.
411
+ *
412
+ * An unresolvable account is a HARD FAILURE, per the plan: a charge with nowhere to go must not
413
+ * book, because the entry would balance only by omitting it and the customer would be billed for
414
+ * something the ledger never recorded.
415
+ */
416
+ async chargeCreditsFor(line, companyID, asOf) {
417
+ const total = money(Math.abs(line.LineTax ?? 0)) + money(Math.abs(line.ChargeAmount ?? 0));
418
+ if (total === 0)
419
+ return [];
420
+ const rv = new RunView(this._provider);
421
+ const res = await rv.RunView({
422
+ EntityName: 'MJ_BizApps_Orders: Order Charge Allocations',
423
+ ExtraFilter: `OrderLineID = '${line.ID}'`,
424
+ ResultType: 'simple',
425
+ BypassCache: true,
426
+ }, this._contextUser);
427
+ const allocations = res?.Results ?? [];
428
+ if (!allocations.length)
429
+ return [];
430
+ // The allocation says WHICH CHARGE and HOW MUCH, but not what KIND of charge — the type
431
+ // lives on OrderCharge. RunView does not join, so the parent rows are read separately and
432
+ // matched in memory.
433
+ const chargeRes = await rv.RunView({
434
+ EntityName: 'MJ_BizApps_Orders: Order Charges',
435
+ ExtraFilter: `ID IN (${[...new Set(allocations.map((a) => `'${a.OrderChargeID}'`))].join(',')})`,
436
+ ResultType: 'simple',
437
+ BypassCache: true,
438
+ }, this._contextUser);
439
+ const chargeByID = new Map((chargeRes?.Results ?? []).map((c) => [String(c.ID).toLowerCase(), c]));
440
+ // One credit per charge TYPE, not per allocation row — several tax layers on one line each
441
+ // have their own account, but two shipping charges share theirs.
442
+ const byType = new Map();
443
+ for (const a of allocations) {
444
+ const parent = chargeByID.get(String(a.OrderChargeID).toLowerCase());
445
+ if (!parent?.ChargeTypeID)
446
+ continue;
447
+ const cur = byType.get(parent.ChargeTypeID) ?? { Amount: 0, Label: parent.ChargeType ?? 'Charge' };
448
+ cur.Amount = money(cur.Amount + Math.abs(Number(a.Amount ?? 0)));
449
+ byType.set(parent.ChargeTypeID, cur);
450
+ }
451
+ const out = [];
452
+ for (const [chargeTypeID, info] of byType) {
453
+ if (info.Amount === 0)
454
+ continue;
455
+ const account = await this._resolver.ResolveForRecord(GL_ROLE.Sales, this._chargeTypeEntityID, chargeTypeID, companyID, asOf);
456
+ if (!account) {
457
+ throw new GLAccountResolutionError(GL_ROLE.Sales, line.ProductID, `Charge '${info.Label}' has no GL account linked for company ${companyID}. Link one to the ` +
458
+ `charge type before booking — a charge with nowhere to go would be billed to the customer ` +
459
+ `and never recorded in the ledger.`);
460
+ }
461
+ out.push({ GLAccountID: account, Amount: info.Amount, Label: info.Label });
462
+ }
463
+ return out;
464
+ }
465
+ }
466
+ //# sourceMappingURL=OrderJournalEntryFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderJournalEntryFactory.js","sourceRoot":"","sources":["../src/OrderJournalEntryFactory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * OrderLineEntityServer — line-level invariants and engine-materialized totals.
3
+ *
4
+ * Two jobs, both of which must happen server-side because the journal entry is derived from them:
5
+ *
6
+ * 1. STAMP THE COMPANY (plan D6). `OrderLine.CompanyID` is a denormalized copy of the
7
+ * product's company, captured at save time so the line records who owned the product at
8
+ * transaction time even if product ownership later moves. It is derived, never authored —
9
+ * whatever a caller passes is overwritten.
10
+ *
11
+ * 2. COMPUTE THE TOTALS. `LineTotalNet` / `LineTotalGross` are engine-materialized and never
12
+ * user-entered:
13
+ * LineTotalNet = (Quantity × UnitPrice × (1 − DiscountPct)) − DiscountAmount
14
+ * LineTotalGross = LineTotalNet + LineTax + ChargeAmount
15
+ *
16
+ * DiscountPct and DiscountAmount are both applied, in that order, because they mean different
17
+ * things: a percentage is a negotiated concession on the line, an amount is an allocated share
18
+ * of a promotion (D70). The net is clamped TOWARD ZERO, in whichever direction the line runs —
19
+ * a discount larger than the line is a configuration mistake and must not turn a sale into a
20
+ * credit, but a reversal line (D16) is legitimately negative and must not be flattened to zero.
21
+ * The rule lives in `PricingBehavior.NetAfterDiscount`, shared with the charge/tax base, because
22
+ * it was written twice and both copies had the same bug.
23
+ * The journal entry is built from the same arithmetic, so a client-supplied total can never
24
+ * disagree with what was booked.
25
+ *
26
+ * The DB trigger (51003) freezes these columns once the parent order is Confirmed, so this runs
27
+ * meaningfully only while the order is still open.
28
+ *
29
+ * CONNECTS TO:
30
+ * FACTORY: OrderJournalEntryFactory (./OrderJournalEntryFactory.ts) — mirrors this arithmetic
31
+ */
32
+ import { EntitySaveOptions, ValidationResult } from '@memberjunction/core';
33
+ import { OrderLineEntity } from '@mj-biz-apps/orders-entities';
34
+ export declare class OrderLineEntityServer extends OrderLineEntity {
35
+ /**
36
+ * The exact extended amount the price rule computed, when a rule priced this line.
37
+ *
38
+ * TRANSIENT — not a column, and deliberately so. It is the pricing pass handing
39
+ * this line the figure it already computed exactly, rather than the line
40
+ * re-deriving it from a unit rate that cannot always represent it (see
41
+ * {@link LineGross}). Persisting it would add a column whose only job is to
42
+ * restate `LineTotalNet` before discount, and a second stored number that can
43
+ * disagree with the first is the thing worth avoiding.
44
+ *
45
+ * Null means "no rule priced this" — a hand-typed unit price, where the unit
46
+ * rate genuinely IS the authority — and the classic quantity × price applies.
47
+ */
48
+ ResolvedExtendedAmount: number | null;
49
+ /**
50
+ * `BaseEntity` skips `ValidateAsync` unless a subclass opts in, so without this the checks
51
+ * below never run when a line is saved on its own. The order's own `ValidateAsync` loops over
52
+ * its lines and would have covered the confirm path — except that one was skipped for the same
53
+ * reason, so in practice nothing here was enforced anywhere. See the note on
54
+ * `OrderEntityServer.DefaultSkipAsyncValidation`.
55
+ */
56
+ get DefaultSkipAsyncValidation(): boolean;
57
+ ValidateAsync(): Promise<ValidationResult>;
58
+ /** Set by OrderEntityServer when saving lines as part of an order graph save/booking. */
59
+ BypassBookedCheck: boolean;
60
+ /**
61
+ * A new line saved on its own (not through the order graph) still has to
62
+ * refuse a booked parent. Header.Validate covers the graph path; this
63
+ * covers the standalone path.
64
+ */
65
+ private refuseNewLineOnBookedOrder;
66
+ /**
67
+ * Populate the fields this line DERIVES rather than accepts, so it is valid before anything
68
+ * validates it.
69
+ *
70
+ * Public because the ORDER now has to call it. `Lines` is a related-record collection, and
71
+ * MJ validates every companion from the PARENT's save — deliberately, so a cross-record
72
+ * invariant sees the whole graph before the first row lands. But that runs before any child's
73
+ * own `Save()`, and `CompanyID` is stamped here, inside this class's `Save()`. The result was
74
+ * that every confirm failed with `Lines[0].CompanyID: Company cannot be null` — a NOT NULL
75
+ * column the line derives from its product and no caller ever authors.
76
+ *
77
+ * Idempotent, so the ordinary path (`Save()` calling it directly) is unaffected, and a line
78
+ * that was prepared by its order and then saved individually simply re-derives the same values.
79
+ */
80
+ PrepareForSave(): Promise<void>;
81
+ Save(options?: EntitySaveOptions): Promise<boolean>;
82
+ private persistExtension;
83
+ private extensionHasLeafDirtyFields;
84
+ /** Derived from the product, always — plan D6. */
85
+ private stampCompanyFromProduct;
86
+ private computeTotals;
87
+ }
88
+ /** Tree-shaking anchor — call from the server bootstrap so @RegisterClass is retained. */
89
+ export declare function LoadOrderLineEntityServer(): void;
90
+ //# sourceMappingURL=OrderLineEntityServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OrderLineEntityServer.d.ts","sourceRoot":"","sources":["../src/OrderLineEntityServer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAEH,iBAAiB,EAMjB,gBAAgB,EACnB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAyC,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAWtG,qBACa,qBAAsB,SAAQ,eAAe;IACtD;;;;;;;;;;;;OAYG;IACI,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpD;;;;;;OAMG;IACH,IAAoB,0BAA0B,IAAI,OAAO,CAExD;IAEqB,aAAa,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAuBhE,yFAAyF;IAClF,iBAAiB,UAAS;IAEjC;;;;OAIG;YACW,0BAA0B;IA2BxC;;;;;;;;;;;;;OAaG;IACU,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,IAAI,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;YAW3D,gBAAgB;IAwC9B,OAAO,CAAC,2BAA2B;IAKnC,kDAAkD;YACpC,uBAAuB;IAoBrC,OAAO,CAAC,aAAa;CAkExB;AAED,0FAA0F;AAC1F,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}