@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,133 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /**
8
+ * Revenue-recognition drivers — the pluggable "how is this earned over time?" layer (plan D43).
9
+ *
10
+ * DESIGN: there is no "standard vs custom" split. EVERY `RevenueRecognitionType` row — including
11
+ * the three we ship — names a `DriverClass` resolved through MJ's ClassFactory. The shipped
12
+ * drivers are ordinary implementations with overridable `protected` methods, so an adopter can
13
+ * subclass one and re-register under the SAME key to swap their behaviour in wholesale. That is
14
+ * strictly more powerful than a hardcoded switch plus an escape hatch, and it means our own types
15
+ * are exercised by the same path every extension uses.
16
+ *
17
+ * SEPARATION OF CONCERNS: a driver computes a SCHEDULE — dates and amounts — and nothing else.
18
+ * It never touches the database, never creates journal entries, and never opens a transaction.
19
+ * `OrderEntityServer` turns the schedule into forward-dated JEs (D14) inside the single booking
20
+ * transaction, which keeps transaction management in exactly one place and makes drivers trivially
21
+ * unit-testable.
22
+ *
23
+ * ROUNDING: the remainder is front-loaded into the FIRST period (plan §4.6). A 12 × $100.00
24
+ * schedule off $1,200.01 recognizes $100.01 then 11 × $100.00 — never a trailing fractional cent,
25
+ * and the periods always sum exactly to the line amount.
26
+ *
27
+ * CONNECTS TO:
28
+ * TABLE: __mj_BizAppsOrders.RevenueRecognitionType (Code, DriverClass, IsDeferred, ...)
29
+ * CALLER: OrderJournalEntryFactory (./OrderJournalEntryFactory.ts)
30
+ */
31
+ import { RegisterClass } from '@memberjunction/global';
32
+ function money(v) {
33
+ return Math.round((v + Number.EPSILON) * 100) / 100;
34
+ }
35
+ function addMonths(d, n) {
36
+ const r = new Date(d.getTime());
37
+ const day = r.getDate();
38
+ r.setMonth(r.getMonth() + n);
39
+ if (r.getDate() < day)
40
+ r.setDate(0); // clamp: Jan 31 + 1mo -> Feb 28/29
41
+ return r;
42
+ }
43
+ /**
44
+ * Base driver. Subclass, override `BuildSchedule` (or just the protected helpers), and register
45
+ * under an existing key to replace a shipped type:
46
+ *
47
+ * @RegisterClass(RevenueRecognitionDriver, 'EvenOverTime')
48
+ * export class OurEvenOverTime extends EvenOverTimeDriver { ... }
49
+ */
50
+ export class RevenueRecognitionDriver {
51
+ /**
52
+ * Split `amount` across `periods`, front-loading the rounding remainder into the first period
53
+ * so the slices always sum EXACTLY to the amount.
54
+ */
55
+ AllocateEvenly(amount, periods) {
56
+ if (periods <= 0)
57
+ return [];
58
+ const base = money(amount / periods);
59
+ const out = new Array(periods).fill(base);
60
+ out[0] = money(amount - base * (periods - 1));
61
+ return out;
62
+ }
63
+ /** Whole months between two dates, minimum 1. */
64
+ MonthSpan(start, end) {
65
+ const months = (end.getFullYear() - start.getFullYear()) * 12 + (end.getMonth() - start.getMonth());
66
+ return Math.max(1, months + (end.getDate() >= start.getDate() ? 1 : 0));
67
+ }
68
+ RequireServicePeriod(context, driver) {
69
+ if (!context.ServicePeriodStart || !context.ServicePeriodEnd) {
70
+ throw new Error(`${driver} needs a service period, but this order line has no ` +
71
+ `ServicePeriodStart/ServicePeriodEnd. Set them on the line, or use a revenue ` +
72
+ `recognition type that does not require a coverage window.`);
73
+ }
74
+ return { start: new Date(context.ServicePeriodStart), end: new Date(context.ServicePeriodEnd) };
75
+ }
76
+ }
77
+ /**
78
+ * UpFront — 100% earned when the sale is booked. One-time goods and services.
79
+ * The booking entry credits Sales directly; there is no deferral round-trip.
80
+ */
81
+ let UpFrontDriver = class UpFrontDriver extends RevenueRecognitionDriver {
82
+ BuildSchedule(context) {
83
+ const d = new Date(context.BookingDate);
84
+ return { Entries: [{ RecognitionDate: d, Amount: money(context.Amount), PeriodStart: d, PeriodEnd: d }] };
85
+ }
86
+ };
87
+ UpFrontDriver = __decorate([
88
+ RegisterClass(RevenueRecognitionDriver, 'UpFront')
89
+ ], UpFrontDriver);
90
+ export { UpFrontDriver };
91
+ /**
92
+ * EvenOverTime — straight-line across the line's service period. Most subscriptions.
93
+ * A 12-month $1,200 subscription produces 12 monthly $100 entries dated on the anniversaries.
94
+ */
95
+ let EvenOverTimeDriver = class EvenOverTimeDriver extends RevenueRecognitionDriver {
96
+ BuildSchedule(context) {
97
+ const { start, end } = this.RequireServicePeriod(context, 'EvenOverTime');
98
+ const step = Math.max(1, context.PeriodMonths ?? 1);
99
+ const periods = Math.max(1, Math.ceil(this.MonthSpan(start, end) / step));
100
+ const amounts = this.AllocateEvenly(context.Amount, periods);
101
+ return {
102
+ Entries: amounts.map((amount, i) => {
103
+ const periodStart = addMonths(start, i * step);
104
+ const periodEnd = i === periods - 1 ? end : addMonths(start, (i + 1) * step);
105
+ return { RecognitionDate: periodStart, Amount: amount, PeriodStart: periodStart, PeriodEnd: periodEnd };
106
+ }),
107
+ };
108
+ }
109
+ };
110
+ EvenOverTimeDriver = __decorate([
111
+ RegisterClass(RevenueRecognitionDriver, 'EvenOverTime')
112
+ ], EvenOverTimeDriver);
113
+ export { EvenOverTimeDriver };
114
+ /**
115
+ * AllBackEnd — 100% earned on the END date. Events and milestone deliverables, where nothing is
116
+ * earned until the thing actually happens: cash is collected up front and sits in Deferred Revenue
117
+ * until the event date.
118
+ */
119
+ let AllBackEndDriver = class AllBackEndDriver extends RevenueRecognitionDriver {
120
+ BuildSchedule(context) {
121
+ const { start, end } = this.RequireServicePeriod(context, 'AllBackEnd');
122
+ return { Entries: [{ RecognitionDate: end, Amount: money(context.Amount), PeriodStart: start, PeriodEnd: end }] };
123
+ }
124
+ };
125
+ AllBackEndDriver = __decorate([
126
+ RegisterClass(RevenueRecognitionDriver, 'AllBackEnd')
127
+ ], AllBackEndDriver);
128
+ export { AllBackEndDriver };
129
+ /** Tree-shaking anchor — the shipped drivers must be registered before booking runs. */
130
+ export function LoadRevenueRecognitionDrivers() {
131
+ // intentionally empty
132
+ }
133
+ //# sourceMappingURL=RevenueRecognition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RevenueRecognition.js","sourceRoot":"","sources":["../src/RevenueRecognition.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAkCvD,SAAS,KAAK,CAAC,CAAS;IACpB,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AACxD,CAAC;AAED,SAAS,SAAS,CAAC,CAAO,EAAE,CAAS;IACjC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC,OAAO,EAAE,GAAG,GAAG;QAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,mCAAmC;IACxE,OAAO,CAAC,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAgB,wBAAwB;IAI1C;;;OAGG;IACO,cAAc,CAAC,MAAc,EAAE,OAAe;QACpD,IAAI,OAAO,IAAI,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1C,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC;IACf,CAAC;IAED,iDAAiD;IACvC,SAAS,CAAC,KAAW,EAAE,GAAS;QACtC,MAAM,MAAM,GACR,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAES,oBAAoB,CAAC,OAAsB,EAAE,MAAc;QACjE,IAAI,CAAC,OAAO,CAAC,kBAAkB,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC3D,MAAM,IAAI,KAAK,CACX,GAAG,MAAM,sDAAsD;gBAC3D,8EAA8E;gBAC9E,2DAA2D,CAClE,CAAC;QACN,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;IACpG,CAAC;CACJ;AAED;;;GAGG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,wBAAwB;IAChD,aAAa,CAAC,OAAsB;QACvC,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACxC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAC9G,CAAC;CACJ,CAAA;AALY,aAAa;IADzB,aAAa,CAAC,wBAAwB,EAAE,SAAS,CAAC;GACtC,aAAa,CAKzB;;AAED;;;GAGG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,wBAAwB;IACrD,aAAa,CAAC,OAAsB;QACvC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAC1E,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAE7D,OAAO;YACH,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBAC/B,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC/C,MAAM,SAAS,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC7E,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;YAC5G,CAAC,CAAC;SACL,CAAC;IACN,CAAC;CACJ,CAAA;AAfY,kBAAkB;IAD9B,aAAa,CAAC,wBAAwB,EAAE,cAAc,CAAC;GAC3C,kBAAkB,CAe9B;;AAED;;;;GAIG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,wBAAwB;IACnD,aAAa,CAAC,OAAsB;QACvC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,oBAAoB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACxE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;IACtH,CAAC;CACJ,CAAA;AALY,gBAAgB;IAD5B,aAAa,CAAC,wBAAwB,EAAE,YAAY,CAAC;GACzC,gBAAgB,CAK5B;;AAED,wFAAwF;AACxF,MAAM,UAAU,6BAA6B;IACzC,sBAAsB;AAC1B,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * What a reversal line is allowed to be — the arithmetic, with no database in sight.
3
+ *
4
+ * A reversal line carries a negative quantity and points at the line it unwinds
5
+ * (`ReversesOrderLineID`). `OrderLineEntityServer` already refuses a negative quantity with no
6
+ * pointer, because a negative line with no origin is indistinguishable from a typo. This module
7
+ * answers the harder question the pointer makes possible: given the origin, is THIS reversal
8
+ * legitimate, and what should it cost?
9
+ *
10
+ * Three facts the origin line is the only authority on:
11
+ *
12
+ * 1. **HOW MUCH is left to give back.** Nothing else in the system knows. Over-returning produces
13
+ * a perfectly balanced journal entry that refunds money never collected, so the ledger cannot
14
+ * catch it — the origin line has to.
15
+ *
16
+ * 2. **WHAT IT COST.** A return must refund the price PAID, not today's price. Resolving a
17
+ * reversal against the current price table refunds last year's purchase at this year's rate,
18
+ * which is wrong in whichever direction prices moved. (It is also why `ComputeAmount` refuses
19
+ * a negative quantity outright: asking "which volume band does -5 land in?" has no answer.)
20
+ *
21
+ * 3. **WHICH PRODUCT.** An ID copied from the wrong row books a credit against another company's
22
+ * revenue and still balances.
23
+ *
24
+ * THE SHAPE THIS SHARES WITH THE REST OF THE PACKAGE: every one of these produces a wrong answer
25
+ * that looks exactly like a right one. Hence refusal rather than a best guess.
26
+ *
27
+ * CONNECTS TO:
28
+ * CODE: ReversalResolver (the lookups), OrderEntityServer.savePendingLines (the caller)
29
+ * DOC: plans/archive/bizapps-orders-master.md D16
30
+ */
31
+ /** The line being unwound, as the database holds it. Quantity is positive — it was a sale. */
32
+ export interface ReversalOrigin {
33
+ ID: string;
34
+ ProductID: string;
35
+ Quantity: number;
36
+ UnitPrice: number;
37
+ DiscountPct: number;
38
+ /** The origin's ALLOCATED discount — an order-level promotion's share of this line (D70). */
39
+ DiscountAmount?: number;
40
+ /** For the refusal message — an ID alone tells the reader nothing about what they mispointed at. */
41
+ OrderNumber?: string | null;
42
+ }
43
+ /** The reversal being attempted. Quantity is negative, as the caller wrote it. */
44
+ export interface ReversalRequest {
45
+ ProductID: string;
46
+ Quantity: number;
47
+ }
48
+ /**
49
+ * How much of the origin line is still returnable.
50
+ *
51
+ * Rounded to the quantity column's 4dp scale: a prorated origin (a short first subscription period)
52
+ * carries a fractional quantity, and comparing an unrounded remainder against a stored one rejects
53
+ * a legitimate final return by a billionth of a unit.
54
+ */
55
+ export declare function RemainingReturnable(originalQuantity: number, alreadyReversed: number): number;
56
+ /**
57
+ * Is this reversal legal? Returns `null` when it is, and the reason it is not when it is not.
58
+ *
59
+ * A string rather than a boolean because every caller needs the reason: these refusals reach a
60
+ * person who is trying to process a return and has to be told what to do instead.
61
+ */
62
+ export declare function ValidateReversal(request: ReversalRequest, origin: ReversalOrigin, alreadyReversed: number): string | null;
63
+ /**
64
+ * What the reversal line should cost: the origin's terms, not today's.
65
+ *
66
+ * `DiscountAmount` IS PART OF THE PRICE PAID, and leaving it out was a real defect. `DiscountPct` is
67
+ * a rate, so it carries to any quantity unchanged — but `DiscountAmount` is an ALLOCATED cash amount
68
+ * (an order-level promotion's share of this line, D70), so returning half the units must give back
69
+ * half of it. Without that, a line that sold 4 × 100 less a 50 promotion — 350 actually paid — refunds
70
+ * 400, and the 50 is given away. The journal entry balances perfectly while doing it.
71
+ *
72
+ * RT7 tested exactly this concern and passed, because it used `DiscountPct`. The two fields express
73
+ * the same idea and only one of them was carried through. Surfaced by Marcelo on PR #17.
74
+ *
75
+ * `reversalQuantity` is what the caller intends to send back, in either sign.
76
+ */
77
+ export declare function InheritedTerms(origin: ReversalOrigin, reversalQuantity: number): {
78
+ UnitPrice: number;
79
+ DiscountPct: number;
80
+ DiscountAmount: number;
81
+ };
82
+ //# sourceMappingURL=ReversalBehavior.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReversalBehavior.d.ts","sourceRoot":"","sources":["../src/ReversalBehavior.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,8FAA8F;AAC9F,MAAM,WAAW,cAAc;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAG7F;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC5B,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,cAAc,EACtB,eAAe,EAAE,MAAM,GACxB,MAAM,GAAG,IAAI,CAmCf;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC1B,MAAM,EAAE,cAAc,EACtB,gBAAgB,EAAE,MAAM,GACzB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAWpE"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * What a reversal line is allowed to be — the arithmetic, with no database in sight.
3
+ *
4
+ * A reversal line carries a negative quantity and points at the line it unwinds
5
+ * (`ReversesOrderLineID`). `OrderLineEntityServer` already refuses a negative quantity with no
6
+ * pointer, because a negative line with no origin is indistinguishable from a typo. This module
7
+ * answers the harder question the pointer makes possible: given the origin, is THIS reversal
8
+ * legitimate, and what should it cost?
9
+ *
10
+ * Three facts the origin line is the only authority on:
11
+ *
12
+ * 1. **HOW MUCH is left to give back.** Nothing else in the system knows. Over-returning produces
13
+ * a perfectly balanced journal entry that refunds money never collected, so the ledger cannot
14
+ * catch it — the origin line has to.
15
+ *
16
+ * 2. **WHAT IT COST.** A return must refund the price PAID, not today's price. Resolving a
17
+ * reversal against the current price table refunds last year's purchase at this year's rate,
18
+ * which is wrong in whichever direction prices moved. (It is also why `ComputeAmount` refuses
19
+ * a negative quantity outright: asking "which volume band does -5 land in?" has no answer.)
20
+ *
21
+ * 3. **WHICH PRODUCT.** An ID copied from the wrong row books a credit against another company's
22
+ * revenue and still balances.
23
+ *
24
+ * THE SHAPE THIS SHARES WITH THE REST OF THE PACKAGE: every one of these produces a wrong answer
25
+ * that looks exactly like a right one. Hence refusal rather than a best guess.
26
+ *
27
+ * CONNECTS TO:
28
+ * CODE: ReversalResolver (the lookups), OrderEntityServer.savePendingLines (the caller)
29
+ * DOC: plans/archive/bizapps-orders-master.md D16
30
+ */
31
+ /**
32
+ * How much of the origin line is still returnable.
33
+ *
34
+ * Rounded to the quantity column's 4dp scale: a prorated origin (a short first subscription period)
35
+ * carries a fractional quantity, and comparing an unrounded remainder against a stored one rejects
36
+ * a legitimate final return by a billionth of a unit.
37
+ */
38
+ export function RemainingReturnable(originalQuantity, alreadyReversed) {
39
+ const remaining = Math.abs(originalQuantity) - Math.abs(alreadyReversed);
40
+ return Math.round(remaining * 1e4) / 1e4;
41
+ }
42
+ /**
43
+ * Is this reversal legal? Returns `null` when it is, and the reason it is not when it is not.
44
+ *
45
+ * A string rather than a boolean because every caller needs the reason: these refusals reach a
46
+ * person who is trying to process a return and has to be told what to do instead.
47
+ */
48
+ export function ValidateReversal(request, origin, alreadyReversed) {
49
+ // Case-INSENSITIVE. SQL Server hands UUIDs back uppercase while application code writes them
50
+ // lowercase, so a `!==` here refuses every legitimate reversal — and the message it prints shows
51
+ // the same UUID twice, which reads as a system fault rather than as a comparison bug.
52
+ if (request.ProductID.toLowerCase() !== origin.ProductID.toLowerCase()) {
53
+ return (`This reversal line is for a different product than the line it reverses. The origin ` +
54
+ `line${origin.OrderNumber ? ` on order ${origin.OrderNumber}` : ''} sold product ` +
55
+ `${origin.ProductID}; this line names ${request.ProductID}. Point the reversal at the ` +
56
+ `line that actually sold this product — crediting a different product books the refund ` +
57
+ `against the wrong revenue account, and it still balances.`);
58
+ }
59
+ const wanted = Math.abs(request.Quantity);
60
+ const remaining = RemainingReturnable(origin.Quantity, alreadyReversed);
61
+ if (remaining <= 0) {
62
+ return (`Nothing remains to be returned against this line. It sold ${origin.Quantity} and ` +
63
+ `${Math.abs(alreadyReversed)} has already been reversed.`);
64
+ }
65
+ if (wanted > remaining) {
66
+ return (`Cannot return ${wanted} against a line that sold ${origin.Quantity}` +
67
+ `${alreadyReversed ? ` and has already had ${Math.abs(alreadyReversed)} reversed` : ''}. ` +
68
+ `At most ${remaining} remains returnable. Returning more than was bought refunds money ` +
69
+ `that was never collected, and the resulting journal entry balances, so nothing further ` +
70
+ `downstream would notice.`);
71
+ }
72
+ return null;
73
+ }
74
+ /**
75
+ * What the reversal line should cost: the origin's terms, not today's.
76
+ *
77
+ * `DiscountAmount` IS PART OF THE PRICE PAID, and leaving it out was a real defect. `DiscountPct` is
78
+ * a rate, so it carries to any quantity unchanged — but `DiscountAmount` is an ALLOCATED cash amount
79
+ * (an order-level promotion's share of this line, D70), so returning half the units must give back
80
+ * half of it. Without that, a line that sold 4 × 100 less a 50 promotion — 350 actually paid — refunds
81
+ * 400, and the 50 is given away. The journal entry balances perfectly while doing it.
82
+ *
83
+ * RT7 tested exactly this concern and passed, because it used `DiscountPct`. The two fields express
84
+ * the same idea and only one of them was carried through. Surfaced by Marcelo on PR #17.
85
+ *
86
+ * `reversalQuantity` is what the caller intends to send back, in either sign.
87
+ */
88
+ export function InheritedTerms(origin, reversalQuantity) {
89
+ const originQty = Math.abs(origin.Quantity);
90
+ const share = originQty > 0 ? Math.abs(reversalQuantity) / originQty : 0;
91
+ // Positive: the column is CHECK (DiscountAmount >= 0) and `NetAfterDiscount` reads it as a
92
+ // magnitude that moves the line toward zero.
93
+ const allocated = Math.abs(origin.DiscountAmount ?? 0) * share;
94
+ return {
95
+ UnitPrice: origin.UnitPrice,
96
+ DiscountPct: origin.DiscountPct ?? 0,
97
+ DiscountAmount: Math.round(allocated * 100) / 100,
98
+ };
99
+ }
100
+ //# sourceMappingURL=ReversalBehavior.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReversalBehavior.js","sourceRoot":"","sources":["../src/ReversalBehavior.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAqBH;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,gBAAwB,EAAE,eAAuB;IACjF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACzE,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC5B,OAAwB,EACxB,MAAsB,EACtB,eAAuB;IAEvB,6FAA6F;IAC7F,iGAAiG;IACjG,sFAAsF;IACtF,IAAI,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QACrE,OAAO,CACH,sFAAsF;YACtF,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB;YAClF,GAAG,MAAM,CAAC,SAAS,qBAAqB,OAAO,CAAC,SAAS,8BAA8B;YACvF,wFAAwF;YACxF,2DAA2D,CAC9D,CAAC;IACN,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,mBAAmB,CAAC,MAAM,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;IAExE,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QACjB,OAAO,CACH,6DAA6D,MAAM,CAAC,QAAQ,OAAO;YACnF,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,6BAA6B,CAC5D,CAAC;IACN,CAAC;IAED,IAAI,MAAM,GAAG,SAAS,EAAE,CAAC;QACrB,OAAO,CACH,iBAAiB,MAAM,6BAA6B,MAAM,CAAC,QAAQ,EAAE;YACrE,GAAG,eAAe,CAAC,CAAC,CAAC,wBAAwB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI;YAC1F,WAAW,SAAS,oEAAoE;YACxF,yFAAyF;YACzF,0BAA0B,CAC7B,CAAC;IACN,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAC1B,MAAsB,EACtB,gBAAwB;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,2FAA2F;IAC3F,6CAA6C;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;IAC/D,OAAO;QACH,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,CAAC;QACpC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,GAAG;KACpD,CAAC;AACN,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ReversalResolver — finds the line a reversal unwinds, and how much of it is already gone.
3
+ *
4
+ * The server half of `ReversalBehavior`: this does the lookups, that does the judging. Same split
5
+ * as `PriceResolver`/`PricingBehavior` and for the same reason — the rule about how much may be
6
+ * returned is provable without a database, and only finding the rows needs one.
7
+ *
8
+ * ALREADY-REVERSED IS A SUM ACROSS ORDERS, not a flag on the line. A customer may send back two of
9
+ * four units in March and two more in June, on separate return orders. Each of those is individually
10
+ * within the original, so a guard that reads one reversal at a time passes both — and a third one
11
+ * too. Only the running total against the origin catches it.
12
+ *
13
+ * DRAFT AND VOIDED RETURNS DO NOT COUNT. A draft that never confirms would otherwise hold the
14
+ * customer's allowance hostage, and a voided one already gave it back.
15
+ *
16
+ * CONNECTS TO:
17
+ * PURE: ./ReversalBehavior.ts
18
+ * CALLER: OrderEntityServer.savePendingLines (before pricing — see there for why)
19
+ */
20
+ import { IMetadataProvider, UserInfo } from '@memberjunction/core';
21
+ import type { ReversalOrigin } from './ReversalBehavior.js';
22
+ /** The origin line plus what prior reversals have already taken from it. */
23
+ export interface ReversalContext {
24
+ Origin: ReversalOrigin;
25
+ AlreadyReversed: number;
26
+ }
27
+ /**
28
+ * Load the origin line for `reversesOrderLineID` and total the reversals already booked against it.
29
+ *
30
+ * Returns `null` when the origin does not exist — the caller refuses, rather than treating a
31
+ * dangling pointer as "no constraint". A reversal pointing at nothing is the case where every
32
+ * guard in `ReversalBehavior` would otherwise pass vacuously.
33
+ */
34
+ export declare function LoadReversalContext(reversesOrderLineID: string, provider: IMetadataProvider, user: UserInfo,
35
+ /** IDs to exclude from the already-reversed total — the reversal line being validated, on a re-save. */
36
+ excludeLineIDs?: string[]): Promise<ReversalContext | null>;
37
+ //# sourceMappingURL=ReversalResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReversalResolver.d.ts","sourceRoot":"","sources":["../src/ReversalResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,iBAAiB,EAA6B,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,cAAc,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,mBAAmB,EAAE,MAAM,EAC3B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ;AACd,wGAAwG;AACxG,cAAc,GAAE,MAAM,EAAO,GAC9B,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAoFjC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * ReversalResolver — finds the line a reversal unwinds, and how much of it is already gone.
3
+ *
4
+ * The server half of `ReversalBehavior`: this does the lookups, that does the judging. Same split
5
+ * as `PriceResolver`/`PricingBehavior` and for the same reason — the rule about how much may be
6
+ * returned is provable without a database, and only finding the rows needs one.
7
+ *
8
+ * ALREADY-REVERSED IS A SUM ACROSS ORDERS, not a flag on the line. A customer may send back two of
9
+ * four units in March and two more in June, on separate return orders. Each of those is individually
10
+ * within the original, so a guard that reads one reversal at a time passes both — and a third one
11
+ * too. Only the running total against the origin catches it.
12
+ *
13
+ * DRAFT AND VOIDED RETURNS DO NOT COUNT. A draft that never confirms would otherwise hold the
14
+ * customer's allowance hostage, and a voided one already gave it back.
15
+ *
16
+ * CONNECTS TO:
17
+ * PURE: ./ReversalBehavior.ts
18
+ * CALLER: OrderEntityServer.savePendingLines (before pricing — see there for why)
19
+ */
20
+ import { RunView } from '@memberjunction/core';
21
+ const ORDER_LINE_ENTITY = 'MJ_BizApps_Orders: Order Lines';
22
+ const ORDER_HEADER_ENTITY = 'MJ_BizApps_Orders: Order Headers';
23
+ /**
24
+ * Load the origin line for `reversesOrderLineID` and total the reversals already booked against it.
25
+ *
26
+ * Returns `null` when the origin does not exist — the caller refuses, rather than treating a
27
+ * dangling pointer as "no constraint". A reversal pointing at nothing is the case where every
28
+ * guard in `ReversalBehavior` would otherwise pass vacuously.
29
+ */
30
+ export async function LoadReversalContext(reversesOrderLineID, provider, user,
31
+ /** IDs to exclude from the already-reversed total — the reversal line being validated, on a re-save. */
32
+ excludeLineIDs = []) {
33
+ // A FORMAT CHECK ON AN INTERPOLATED ID. Everything reaching here comes from our own columns, so
34
+ // this is not the last line of defence against injection — but it is free, it turns a malformed
35
+ // pointer into a clear refusal instead of a SQL syntax error from inside a booking transaction,
36
+ // and it means the filter below cannot be built from arbitrary text. Raised by Marcelo on PR #17.
37
+ if (!/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(reversesOrderLineID)) {
38
+ throw new Error(`'${reversesOrderLineID}' is not a valid order line identifier, so the line it claims to ` +
39
+ `reverse cannot be looked up.`);
40
+ }
41
+ const rv = new RunView(provider);
42
+ // The origin and every reversal already pointing at it, in ONE view. Splitting them costs a
43
+ // round trip and buys nothing — both are order lines and both are needed.
44
+ const lines = await rv.RunView({
45
+ EntityName: ORDER_LINE_ENTITY,
46
+ ExtraFilter: `ID = '${reversesOrderLineID}' OR ReversesOrderLineID = '${reversesOrderLineID}'`,
47
+ ResultType: 'simple',
48
+ }, user);
49
+ const rows = lines?.Results ?? [];
50
+ const origin = rows.find((r) => String(r.ID).toLowerCase() === reversesOrderLineID.toLowerCase());
51
+ if (!origin)
52
+ return null;
53
+ const priors = rows.filter((r) => r !== origin);
54
+ // The order-line view does not carry its header's Status, and the status is what decides
55
+ // whether a prior reversal counts — so the headers have to be fetched. One view, not one per.
56
+ const statusByOrder = new Map();
57
+ if (priors.length) {
58
+ const ids = [...new Set(priors.map((p) => `'${p.OrderHeaderID}'`))].join(',');
59
+ const headers = await rv.RunView({
60
+ EntityName: ORDER_HEADER_ENTITY,
61
+ ExtraFilter: `ID IN (${ids})`,
62
+ ResultType: 'simple',
63
+ }, user);
64
+ for (const h of headers?.Results ?? []) {
65
+ statusByOrder.set(String(h.ID).toLowerCase(), String(h.Status ?? ''));
66
+ }
67
+ }
68
+ const excluded = new Set(excludeLineIDs.map((id) => id.toLowerCase()));
69
+ let alreadyReversed = 0;
70
+ for (const prior of priors) {
71
+ if (excluded.has(String(prior.ID).toLowerCase()))
72
+ continue;
73
+ // A Draft return has not taken anything yet and a Voided one has given it back. Anything
74
+ // else — Confirmed, Posted, Fulfilled — is money the customer already has. An UNKNOWN
75
+ // status counts: a prior reversal whose header could not be read is not evidence of room.
76
+ const status = statusByOrder.get(String(prior.OrderHeaderID).toLowerCase()) ?? '';
77
+ if (status === 'Draft' || status === 'Voided')
78
+ continue;
79
+ // `ABS` because reversal quantities are stored negative, and a signed sum here would let a
80
+ // reversal and a re-sale cancel out into a fresh allowance.
81
+ alreadyReversed += Math.abs(Number(prior.Quantity ?? 0));
82
+ }
83
+ return {
84
+ Origin: {
85
+ ID: origin.ID,
86
+ ProductID: origin.ProductID,
87
+ Quantity: Number(origin.Quantity ?? 0),
88
+ UnitPrice: Number(origin.UnitPrice ?? 0),
89
+ DiscountPct: Number(origin.DiscountPct ?? 0),
90
+ DiscountAmount: Number(origin.DiscountAmount ?? 0),
91
+ OrderNumber: null,
92
+ },
93
+ AlreadyReversed: Math.round(alreadyReversed * 1e4) / 1e4,
94
+ };
95
+ }
96
+ //# sourceMappingURL=ReversalResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReversalResolver.js","sourceRoot":"","sources":["../src/ReversalResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Orders.SpawnRenewals — place the renewal orders that are due (plan D55).
3
+ *
4
+ * The last piece of the subscription lifecycle. `AutoRenew` and `RenewalLeadDays` were columns with
5
+ * no consumer: a subscription would reach the end of its term and simply stop, with nothing to
6
+ * continue it.
7
+ *
8
+ * THE DESIGN QUESTION THIS ANSWERS
9
+ * "Is a renewal an order the customer approves, or one the system places for them?" — BOTH, and
10
+ * `AutoRenew` is the switch. `AutoRenew = true` means the customer has already consented to
11
+ * recurring billing, so the system places a CONFIRMED order: it books, it invoices, and coverage
12
+ * continues without a gap. `AutoRenew = false` means it does not renew, full stop — this operation
13
+ * skips it and the term simply ends. Reminder-and-approve for the second case is a communication
14
+ * flow, not a booking one, and does not belong here.
15
+ *
16
+ * The order is placed at LEAD TIME, not on the expiry date, which is how subscription billing
17
+ * actually works: the invoice goes out before the period it covers. Revenue is not affected — the
18
+ * booking entry credits Deferred Revenue and the recognition entries are dated into the new term's
19
+ * own window (D14).
20
+ *
21
+ * IDEMPOTENCY, which a scheduled job makes non-negotiable
22
+ * Two independent guards, because this runs unattended and a double-spawn double-bills a customer:
23
+ * 1. the SELECTION only finds subscriptions whose LATEST term ends inside the window — once a
24
+ * renewal is booked, term N+1 exists and the subscription no longer qualifies;
25
+ * 2. an explicit check for an existing order with `RenewsSubscriptionID` covering that term,
26
+ * which catches the case where a prior pass booked the order but its term write failed.
27
+ * Running the operation twice in a row is a no-op, and that is asserted by the check suite.
28
+ *
29
+ * CONNECTS TO:
30
+ * BOOKING: OrderEntityServer.Save — the renewal order goes through the ordinary confirm path,
31
+ * so extension, term creation, GL resolution and recognition are all the SAME code
32
+ * POLICY: SubscriptionBehavior (IsRenewal bypasses ConcurrencyMode — a renewal is not a second
33
+ * concurrent subscription, it is this one continuing)
34
+ * TABLES: __mj_BizAppsOrders.{Subscription,SubscriptionTerm,SubscriptionType,OrderHeader,OrderLine}
35
+ */
36
+ import { BaseRemotableOperation, IMetadataProvider, UserInfo } from '@memberjunction/core';
37
+ export interface SpawnRenewalsInput {
38
+ /** Treat this as "today". Defaults to now. */
39
+ AsOfDate?: Date | string;
40
+ /** Restrict to one subscription — for a targeted retry, or for a test. */
41
+ SubscriptionID?: string;
42
+ /** Report what WOULD be placed, without placing anything. */
43
+ Preview?: boolean;
44
+ /**
45
+ * Cap on orders placed in one pass. A safety valve for the first production run, where a
46
+ * mis-set lead time could otherwise invoice an entire book of business at once.
47
+ */
48
+ MaxCount?: number;
49
+ }
50
+ export interface RenewalCandidate {
51
+ SubscriptionID: string;
52
+ SubscriptionNumber: string;
53
+ ProductID: string;
54
+ /** End of the term that is expiring. */
55
+ CurrentTermEnd: string;
56
+ /** Lead days actually applied, after the subscription's override of the type's default. */
57
+ LeadDays: number;
58
+ /** Set when the renewal was placed (absent on a preview, or when placing failed). */
59
+ OrderID?: string;
60
+ OrderNumber?: string;
61
+ /** Set when this candidate was skipped, with the reason. */
62
+ SkippedReason?: string;
63
+ }
64
+ export interface SpawnRenewalsOutput {
65
+ Success: boolean;
66
+ Message?: string;
67
+ /** Every subscription considered due, whether or not an order was placed. */
68
+ Candidates: RenewalCandidate[];
69
+ Placed: number;
70
+ Skipped: number;
71
+ }
72
+ export declare class SpawnRenewalsOperation extends BaseRemotableOperation<SpawnRenewalsInput, SpawnRenewalsOutput> {
73
+ OperationKey: string;
74
+ protected InternalExecute(input: SpawnRenewalsInput, provider: IMetadataProvider, user: UserInfo): Promise<SpawnRenewalsOutput>;
75
+ /**
76
+ * Subscriptions whose latest term expires within their effective lead window.
77
+ *
78
+ * Raw SQL rather than RunView because the selection is inherently a JOIN across four tables with
79
+ * a "latest term per subscription" window — expressible in one statement and awkward as several
80
+ * round trips. `RenewalLeadDays` falls back from the subscription to its type, which is the
81
+ * inheritance rule the schema documents.
82
+ */
83
+ private findDue;
84
+ /** True when an order already exists that renews this subscription past the expiring term. */
85
+ private alreadyRenewed;
86
+ /**
87
+ * Place the renewal as an ordinary confirmed order.
88
+ *
89
+ * Deliberately NOT a special write path: routing it through `OrderEntityServer.Save` means the
90
+ * extension, the new term, GL resolution, the recognition schedule and the all-or-none
91
+ * guarantee are the same code that handles a customer purchase. A bespoke renewal writer would
92
+ * be a second implementation of booking, drifting from the first.
93
+ */
94
+ private placeRenewal;
95
+ /**
96
+ * Quantity for the renewal.
97
+ *
98
+ * A PRORATED source line carries a fractional quantity — the short first period into a calendar
99
+ * anchor (D54). Renewing at that fraction would bill half a year forever. A renewal is always a
100
+ * FULL period, so the fraction is dropped and the quantity rounds up to whole units.
101
+ */
102
+ private renewalQuantity;
103
+ private dayAfter;
104
+ private loadSourceLine;
105
+ private logEvent;
106
+ }
107
+ /** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
108
+ export declare function LoadSpawnRenewalsOperation(): void;
109
+ //# sourceMappingURL=SpawnRenewalsOperation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpawnRenewalsOperation.d.ts","sourceRoot":"","sources":["../src/SpawnRenewalsOperation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAEH,sBAAsB,EAEtB,iBAAiB,EAIjB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAgB9B,MAAM,WAAW,kBAAkB;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACzB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,cAAc,EAAE,MAAM,CAAC;IACvB,2FAA2F;IAC3F,QAAQ,EAAE,MAAM,CAAC;IACjB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACnB;AAwBD,qBACa,sBAAuB,SAAQ,sBAAsB,CAAC,kBAAkB,EAAE,mBAAmB,CAAC;IAChG,YAAY,SAA0B;cAE7B,eAAe,CAC3B,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,mBAAmB,CAAC;IAyD/B;;;;;;;OAOG;YACW,OAAO;IA6CrB,8FAA8F;YAChF,cAAc;IA8B5B;;;;;;;OAOG;YACW,YAAY;IAsE1B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,QAAQ;YAKF,cAAc;YAmBd,QAAQ;CA0BzB;AAED,8FAA8F;AAC9F,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}