@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,267 @@
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
+ * @fileoverview `Orders.AdvanceOrderState` — move a booked order up the status ladder.
9
+ *
10
+ * WHAT THIS IS FOR. Back-office entry of something that has ALREADY happened: a sale taken at a
11
+ * counter, a shipment that went out before anyone opened the system, a migration from whatever came
12
+ * before. The order needs to land in its final state without a human clicking through
13
+ * Confirmed → Posted → Fulfilled (D17).
14
+ *
15
+ * WHAT IT REPLACED, AND WHY IT SHRANK. This was `Orders.CreateOrderInState`, which took an
16
+ * `OrderDraft` — a hand-maintained mirror of the order entity — created the order by delegating to
17
+ * `Orders.ConfirmOrder`, and only then advanced it. Both halves of that are gone: composing and
18
+ * booking an order is now `order.Save()` through MJ's entity graph, which runs the identical booking
19
+ * walk on the server subclass. What is left is the part a save cannot do, and that part is this file.
20
+ *
21
+ * WHY THE LADDER STILL NEEDS AN OPERATION. Advancing to Posted is a plain save. Advancing to
22
+ * Fulfilled is not: the fulfillable LINES have to be marked first, and whether the order may move at
23
+ * all depends on how many could not be. That is a decision over a set of rows, taken on the server,
24
+ * with a caller-supplied override — a save on one header has nowhere to put it.
25
+ *
26
+ * NOTHING HERE BOOKS. Journal entries, subscriptions and entitlements are the confirm's business and
27
+ * have already happened by the time this runs. This operation reads the ledger back only to REPORT
28
+ * it, so a caller can tell "advanced an order that booked" from "advanced an order that did not".
29
+ *
30
+ * @module @mj-biz-apps/orders-core-entities-server
31
+ */
32
+ import { BaseRemotableOperation, RunView, } from '@memberjunction/core';
33
+ import { RegisterClass } from '@memberjunction/global';
34
+ import { IsAwaitingFulfillment } from './FulfillmentBehavior.js';
35
+ import { ORDER_HEADER_ENTITY } from './entity-names.js';
36
+ import { RequireUUID } from './sql-guards.js';
37
+ const ORDER_LINE_ENTITY = 'MJ_BizApps_Orders: Order Lines';
38
+ const PRODUCT_ENTITY = 'MJ_BizApps_Orders: Products';
39
+ const PRODUCT_TYPE_ENTITY = 'MJ_BizApps_Orders: Product Types';
40
+ const key = (id) => (id ?? '').toLowerCase();
41
+ const quote = (ids) => [...new Set(ids.map((i) => `'${i}'`))].join(',');
42
+ /** The status ladder, in the order an order climbs it. */
43
+ const LADDER = ['Draft', 'Quoted', 'Confirmed'];
44
+ /** Where this operation will take an order. Everything else is somebody else's job. */
45
+ const ACCEPTED_TARGETS = new Set(['Fulfilled']);
46
+ let AdvanceOrderStateOperation = class AdvanceOrderStateOperation extends BaseRemotableOperation {
47
+ constructor() {
48
+ super(...arguments);
49
+ this.OperationKey = 'Orders.AdvanceOrderState';
50
+ }
51
+ async InternalExecute(input, provider, user) {
52
+ const target = (input?.TargetStatus ?? '').trim();
53
+ if (!ACCEPTED_TARGETS.has(target)) {
54
+ return this.refuse(target, [
55
+ this.blocker('UNSUPPORTED_TARGET', `'${target || '(none)'}' is not a state this operation advances to. Use Fulfilled.`, target === 'Draft' || target === 'Quoted' || target === 'Confirmed'
56
+ ? 'Those states are reached by saving the order itself — set Status and call Save(). ' +
57
+ 'Confirmed runs the booking walk on the way through, which is where it belongs.'
58
+ : 'Voiding is a separate decision about an existing order, not a rung on the ladder.'),
59
+ ]);
60
+ }
61
+ if (!input?.OrderHeaderID) {
62
+ return this.refuse(target, [this.blocker('NO_ORDER', 'An OrderHeaderID is required.')]);
63
+ }
64
+ // Reaches SQL filter text below.
65
+ RequireUUID(input.OrderHeaderID, 'OrderHeaderID');
66
+ const header = await provider.GetEntityObject(ORDER_HEADER_ENTITY, user);
67
+ if (!(await header.Load(input.OrderHeaderID))) {
68
+ return this.refuse(target, [
69
+ this.blocker('NOT_FOUND', `Order ${input.OrderHeaderID} could not be loaded.`),
70
+ ]);
71
+ }
72
+ const orderID = header.ID;
73
+ const status = header.Status ?? 'Draft';
74
+ const transitions = [];
75
+ let unfulfilled = 0;
76
+ // AN ORDER THAT HAS NOT BOOKED CANNOT BE ADVANCED.
77
+ if (status !== 'Confirmed') {
78
+ return this.refuse(target, [
79
+ this.blocker('NOT_CONFIRMED', `The order is ${status}. Only a Confirmed order can be advanced.`, 'Set Status to Confirmed and save the order — that runs the booking walk. Then advance it.'),
80
+ ], orderID, header.OrderNumber, status);
81
+ }
82
+ const rv = new RunView(provider);
83
+ if (header.FulfillmentStatus === 'Fulfilled') {
84
+ return {
85
+ Success: true,
86
+ Message: `The order is already Fulfilled.`,
87
+ OrderHeaderID: orderID,
88
+ OrderNumber: header.OrderNumber ?? null,
89
+ Status: 'Fulfilled',
90
+ RequestedStatus: target,
91
+ Transitions: [],
92
+ ...(await this.readBookedEntries(orderID, provider)),
93
+ UnfulfilledLineCount: 0,
94
+ Blockers: [],
95
+ };
96
+ }
97
+ // Mark the fulfillable lines FIRST.
98
+ unfulfilled = await this.fulfillLines(orderID, rv, provider, user);
99
+ if (unfulfilled > 0 && !input?.ForceFulfillment) {
100
+ transitions.push({
101
+ From: header.FulfillmentStatus ?? 'Pending',
102
+ To: 'Fulfilled',
103
+ Applied: false,
104
+ Reason: `${unfulfilled} fulfillable line(s) could not be marked Fulfilled. The order sits in ` +
105
+ `the fulfillment queue. Set ForceFulfillment to advance anyway.`,
106
+ });
107
+ return this.stopped(orderID, header, target, header.FulfillmentStatus ?? 'Pending', transitions, unfulfilled, provider);
108
+ }
109
+ header.FulfillmentStatus = 'Fulfilled';
110
+ if (input?.Reason) {
111
+ const existing = header.Description ?? '';
112
+ header.Description = existing ? `${existing} — ${input.Reason}` : input.Reason;
113
+ }
114
+ const saved = await header.Save();
115
+ transitions.push({
116
+ From: 'Pending',
117
+ To: 'Fulfilled',
118
+ Applied: saved,
119
+ Reason: saved && unfulfilled > 0
120
+ ? `Forced with ${unfulfilled} line(s) still Pending.`
121
+ : header.LatestResult?.CompleteMessage ?? null,
122
+ });
123
+ const booked = await this.readBookedEntries(orderID, provider);
124
+ return {
125
+ Success: saved,
126
+ Message: saved ? undefined : `The order could not be advanced to Fulfilled: ${header.LatestResult?.CompleteMessage ?? 'Save failed'}`,
127
+ OrderHeaderID: orderID,
128
+ OrderNumber: header.OrderNumber ?? null,
129
+ Status: saved ? 'Fulfilled' : (header.FulfillmentStatus ?? 'Pending'),
130
+ RequestedStatus: target,
131
+ Transitions: transitions,
132
+ EntryCount: booked.EntryCount,
133
+ AllBalanced: booked.AllBalanced,
134
+ UnfulfilledLineCount: unfulfilled,
135
+ Blockers: [],
136
+ };
137
+ }
138
+ /**
139
+ * What booked against this order's lines, read back rather than assumed.
140
+ *
141
+ * The confirm happened on a different call — possibly on a different day, for a migration — so
142
+ * this operation has no first-hand knowledge of it. Reporting zero entries because nobody looked
143
+ * is indistinguishable from an order that never booked, and this whole file exists to keep those
144
+ * two apart.
145
+ */
146
+ async readBookedEntries(orderID, provider) {
147
+ const rows = (await provider.ExecuteSQL(`
148
+ SELECT je.ID AS EntryID,
149
+ SUM(ISNULL(jel.DebitAmount, 0)) AS D,
150
+ SUM(ISNULL(jel.CreditAmount, 0)) AS C
151
+ FROM __mj_BizAppsAccounting.JournalEntry je
152
+ JOIN __mj_BizAppsAccounting.JournalEntryLine jel ON jel.JournalEntryID = je.ID
153
+ WHERE je.LinkedRecordID IN (
154
+ SELECT CAST(ol.ID AS NVARCHAR(400)) FROM __mj_BizAppsOrders.OrderLine ol
155
+ WHERE ol.OrderHeaderID = '${orderID}')
156
+ GROUP BY je.ID`)) ?? [];
157
+ return {
158
+ EntryCount: rows.length,
159
+ AllBalanced: rows.every((r) => Math.abs(Number(r.D) - Number(r.C)) < 0.005),
160
+ };
161
+ }
162
+ /** Move the header, reporting a refusal rather than throwing — a stalled advance is still a result. */
163
+ async setStatus(header,
164
+ // Derived from the entity: `Status` is CHECK-constrained, so CodeGen owns this union and it
165
+ // widens with the constraint. Restating it here would freeze it at today's six values.
166
+ status, reason) {
167
+ header.Status = status;
168
+ if (reason) {
169
+ const existing = header.Description ?? '';
170
+ header.Description = existing ? `${existing} — ${reason}` : reason;
171
+ }
172
+ if (!(await header.Save())) {
173
+ return { ok: false, reason: header.LatestResult?.CompleteMessage ?? 'no reason given' };
174
+ }
175
+ return { ok: true, reason: null };
176
+ }
177
+ /**
178
+ * Mark every line that is awaiting fulfilment, and report how many would not go.
179
+ *
180
+ * The three lookups are per-order rather than per-line on purpose: a migration advances orders in
181
+ * bulk, and a per-line product/type round trip turns a hundred-line order into three hundred
182
+ * queries.
183
+ */
184
+ async fulfillLines(orderID, rv, provider, user) {
185
+ const lines = await rv.RunView({ EntityName: ORDER_LINE_ENTITY, ExtraFilter: `OrderHeaderID = '${orderID}'`, ResultType: 'simple' }, user);
186
+ const rows = lines.Results ?? [];
187
+ if (!rows.length)
188
+ return 0;
189
+ const products = await rv.RunView({
190
+ EntityName: PRODUCT_ENTITY,
191
+ ExtraFilter: `ID IN (${quote(rows.map((l) => l.ProductID))})`,
192
+ ResultType: 'simple',
193
+ }, user);
194
+ const typeIDs = [...new Set((products.Results ?? []).map((p) => p.ProductTypeID))].filter(Boolean);
195
+ const types = typeIDs.length
196
+ ? await rv.RunView({ EntityName: PRODUCT_TYPE_ENTITY, ExtraFilter: `ID IN (${quote(typeIDs)})`, ResultType: 'simple' }, user)
197
+ : { Results: [] };
198
+ const requiresByType = new Map((types.Results ?? []).map((t) => [key(t.ID), !!t.RequiresFulfillment]));
199
+ const typeByProduct = new Map((products.Results ?? []).map((p) => [key(p.ID), key(p.ProductTypeID)]));
200
+ let remaining = 0;
201
+ for (const row of rows) {
202
+ const shaped = {
203
+ ID: row.ID,
204
+ RequiresFulfillment: requiresByType.get(typeByProduct.get(key(row.ProductID)) ?? '') ?? false,
205
+ FulfillmentStatus: row.FulfillmentStatus ?? null,
206
+ ReversesOrderLineID: row.ReversesOrderLineID,
207
+ IsRollupParent: !!row.IsRollupParent,
208
+ };
209
+ if (!IsAwaitingFulfillment(shaped))
210
+ continue;
211
+ const entity = await provider.GetEntityObject(ORDER_LINE_ENTITY, user);
212
+ if (!(await entity.Load(row.ID))) {
213
+ remaining++;
214
+ continue;
215
+ }
216
+ entity.FulfillmentStatus = 'Fulfilled';
217
+ if (!(await entity.Save()))
218
+ remaining++;
219
+ }
220
+ return remaining;
221
+ }
222
+ /** The order is booked and moved as far as it could, but not as far as asked. */
223
+ async stopped(orderID, header, target, status, transitions, unfulfilled, provider) {
224
+ return {
225
+ Success: false,
226
+ Message: `The order stopped at ${status} rather than ${target}.`,
227
+ OrderHeaderID: orderID,
228
+ OrderNumber: header.OrderNumber ?? null,
229
+ Status: status,
230
+ RequestedStatus: target,
231
+ Transitions: transitions,
232
+ ...(await this.readBookedEntries(orderID, provider)),
233
+ UnfulfilledLineCount: unfulfilled,
234
+ Blockers: [],
235
+ };
236
+ }
237
+ blocker(code, message, hint) {
238
+ return { Code: code, Message: message, ResolutionHint: hint ?? null, LineNumber: null };
239
+ }
240
+ refuse(target, blockers, orderID = null, orderNumber = null, status = null) {
241
+ return {
242
+ Success: false,
243
+ Message: blockers.map((b) => b.Message).join(' '),
244
+ OrderHeaderID: orderID,
245
+ OrderNumber: orderNumber,
246
+ Status: status,
247
+ RequestedStatus: target,
248
+ Transitions: [],
249
+ EntryCount: 0,
250
+ AllBalanced: true,
251
+ UnfulfilledLineCount: 0,
252
+ Blockers: blockers,
253
+ };
254
+ }
255
+ };
256
+ AdvanceOrderStateOperation = __decorate([
257
+ RegisterClass(BaseRemotableOperation, 'Orders.AdvanceOrderState')
258
+ ], AdvanceOrderStateOperation);
259
+ export { AdvanceOrderStateOperation };
260
+ /**
261
+ * Force the class registration. Tree-shaking removes a class nobody imports, and the decorator only
262
+ * runs if the module is loaded — so the server's bootstrap calls this.
263
+ */
264
+ export function LoadAdvanceOrderStateOperation() {
265
+ // no-op by design
266
+ }
267
+ //# sourceMappingURL=AdvanceOrderStateOperation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AdvanceOrderStateOperation.js","sourceRoot":"","sources":["../src/AdvanceOrderStateOperation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Orders.ApplyAccountCredit — spend an order's credit balance on another order (plan D68).
3
+ *
4
+ * WHAT AN ACCOUNT CREDIT IS
5
+ * Not a separate instrument. When a customer pays more than an order is worth, the surplus stays on
6
+ * that order as a NEGATIVE balance, and that negative balance IS the credit. Nothing else holds it —
7
+ * deliberately, because a second record carrying the same balance is a second thing that can
8
+ * disagree with the first. (A gift card is different: `StoredValueAccount` exists because nothing
9
+ * else could hold that money.)
10
+ *
11
+ * WHAT THIS OPERATION WRITES
12
+ * A payment whose `Amount` is ZERO, carrying two offsetting allocations:
13
+ *
14
+ * Payment PAY-000042 Amount 0.00 type AccountCredit
15
+ * PaymentDetail.SourceOrderHeaderID = <the credit order>
16
+ * line 1: <credit order> -100.00 the credit is consumed
17
+ * line 2: <target order> +100.00 and lands here
18
+ * SUM = 0.00 == Amount
19
+ *
20
+ * Zero is not a degenerate case here, it is the truth: no new cash entered the business. The money
21
+ * arrived earlier, on the payment that over-paid the first order; this only re-attributes it. The
22
+ * D68 invariant (`Amount` = sum of lines) therefore holds exactly, with nothing special-cased.
23
+ *
24
+ * WHY NOT JUST EDIT THE ORIGINAL PAYMENT'S LINES
25
+ * Because a credit is not always traceable to one payment — it can accumulate from several, or
26
+ * survive a partial refund — and because a captured payment is frozen (51005/51010/51011). Rewriting
27
+ * history to express a new event would destroy the audit trail of money that genuinely moved.
28
+ *
29
+ * THE LEDGER FALLS OUT OF THE EXISTING MACHINERY
30
+ * `PaymentLineEntityServer` already books each allocation and already treats a negative amount as a
31
+ * reversal, so the two lines produce a mirrored pair and an ordinary pair:
32
+ *
33
+ * credit order: Dr A/R 100 Cr Cash 100 (mirrored — the reversal)
34
+ * target order: Dr Cash 100 Cr A/R 100
35
+ *
36
+ * Cash nets to zero across them; A/R moves from one order to the other. No new booking code exists
37
+ * for this operation, and none should — if it needed its own entries, that would mean the allocation
38
+ * path did not really understand negative applications.
39
+ *
40
+ * CROSS-COMPANY IS NOT A SPECIAL CASE EITHER. When the two orders belong to different companies the
41
+ * same path raises the intercompany legs, because the allocation factory splits per owning company.
42
+ * Note this is not merely convenient: a single `Dr A/R / Cr A/R` entry spanning two companies could
43
+ * not be booked at all (accounting refuses cross-company entries, D6), so the per-company shape is
44
+ * the only bookable form rather than an implementation preference.
45
+ *
46
+ * FAILURE MODEL: logical refusals come back INSIDE the output as `Success: false` with a reason —
47
+ * the same contract `Orders.RefundPayment` and `Orders.CancelSubscription` use. Only genuine faults
48
+ * throw.
49
+ *
50
+ * CONNECTS TO:
51
+ * BOOKING: PaymentLineEntityServer.Save — both legs book through the ordinary allocation path
52
+ * TABLES: __mj_BizAppsOrders.{PaymentHeader,PaymentLine,PaymentDetail,OrderHeader}
53
+ * DOC: plans/archive/bizapps-orders-master.md D68
54
+ */
55
+ import { BaseRemotableOperation, IMetadataProvider, UserInfo } from '@memberjunction/core';
56
+ export interface ApplyAccountCreditInput {
57
+ /** The order carrying the credit (its Balance is negative). */
58
+ SourceOrderHeaderID: string;
59
+ /** The order to spend it on. */
60
+ TargetOrderHeaderID: string;
61
+ /** Omit to apply as much as both sides allow. */
62
+ Amount?: number;
63
+ Reason?: string;
64
+ /** Compute and validate without writing — for a confirmation screen. */
65
+ Preview?: boolean;
66
+ }
67
+ export interface ApplyAccountCreditOutput {
68
+ Success: boolean;
69
+ Message?: string;
70
+ /** What was (or would be) applied. */
71
+ AppliedAmount?: number;
72
+ /** The source order's credit still available AFTER this application. */
73
+ RemainingCredit?: number;
74
+ /** The target order's balance AFTER this application. */
75
+ TargetBalanceAfter?: number;
76
+ PaymentHeaderID?: string;
77
+ PaymentNumber?: string;
78
+ }
79
+ export declare class ApplyAccountCreditOperation extends BaseRemotableOperation<ApplyAccountCreditInput, ApplyAccountCreditOutput> {
80
+ OperationKey: string;
81
+ protected InternalExecute(input: ApplyAccountCreditInput, provider: IMetadataProvider, user: UserInfo): Promise<ApplyAccountCreditOutput>;
82
+ private loadOrder;
83
+ /**
84
+ * The `AccountCredit` tender's ID.
85
+ *
86
+ * Cache first, then the query it always did. The row is seeded metadata and the cache answers it
87
+ * without a round trip; the fallback stays because a deployment that has not seeded this tender
88
+ * yet, or one that added it in the transaction now running, must still resolve it — and the
89
+ * caller's whole operation depends on finding it.
90
+ */
91
+ private accountCreditTypeID;
92
+ /** Gap-free payment numbering, same sequence the capture path uses. */
93
+ private nextPaymentNumber;
94
+ }
95
+ /** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
96
+ export declare function LoadApplyAccountCreditOperation(): void;
97
+ //# sourceMappingURL=ApplyAccountCreditOperation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApplyAccountCreditOperation.d.ts","sourceRoot":"","sources":["../src/ApplyAccountCreditOperation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,OAAO,EAEH,sBAAsB,EAEtB,iBAAiB,EAIjB,QAAQ,EACX,MAAM,sBAAsB,CAAC;AAsB9B,MAAM,WAAW,uBAAuB;IACpC,+DAA+D;IAC/D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gCAAgC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,wBAAwB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAaD,qBACa,2BAA4B,SAAQ,sBAAsB,CAAC,uBAAuB,EAAE,wBAAwB,CAAC;IAC/G,YAAY,SAA+B;cAElC,eAAe,CAC3B,KAAK,EAAE,uBAAuB,EAC9B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,wBAAwB,CAAC;YA2JtB,SAAS;IAevB;;;;;;;OAOG;YACW,mBAAmB;IAmBjC,uEAAuE;YACzD,iBAAiB;CAelC;AAED,8FAA8F;AAC9F,wBAAgB,+BAA+B,IAAI,IAAI,CAEtD"}
@@ -0,0 +1,275 @@
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
+ * Orders.ApplyAccountCredit — spend an order's credit balance on another order (plan D68).
9
+ *
10
+ * WHAT AN ACCOUNT CREDIT IS
11
+ * Not a separate instrument. When a customer pays more than an order is worth, the surplus stays on
12
+ * that order as a NEGATIVE balance, and that negative balance IS the credit. Nothing else holds it —
13
+ * deliberately, because a second record carrying the same balance is a second thing that can
14
+ * disagree with the first. (A gift card is different: `StoredValueAccount` exists because nothing
15
+ * else could hold that money.)
16
+ *
17
+ * WHAT THIS OPERATION WRITES
18
+ * A payment whose `Amount` is ZERO, carrying two offsetting allocations:
19
+ *
20
+ * Payment PAY-000042 Amount 0.00 type AccountCredit
21
+ * PaymentDetail.SourceOrderHeaderID = <the credit order>
22
+ * line 1: <credit order> -100.00 the credit is consumed
23
+ * line 2: <target order> +100.00 and lands here
24
+ * SUM = 0.00 == Amount
25
+ *
26
+ * Zero is not a degenerate case here, it is the truth: no new cash entered the business. The money
27
+ * arrived earlier, on the payment that over-paid the first order; this only re-attributes it. The
28
+ * D68 invariant (`Amount` = sum of lines) therefore holds exactly, with nothing special-cased.
29
+ *
30
+ * WHY NOT JUST EDIT THE ORIGINAL PAYMENT'S LINES
31
+ * Because a credit is not always traceable to one payment — it can accumulate from several, or
32
+ * survive a partial refund — and because a captured payment is frozen (51005/51010/51011). Rewriting
33
+ * history to express a new event would destroy the audit trail of money that genuinely moved.
34
+ *
35
+ * THE LEDGER FALLS OUT OF THE EXISTING MACHINERY
36
+ * `PaymentLineEntityServer` already books each allocation and already treats a negative amount as a
37
+ * reversal, so the two lines produce a mirrored pair and an ordinary pair:
38
+ *
39
+ * credit order: Dr A/R 100 Cr Cash 100 (mirrored — the reversal)
40
+ * target order: Dr Cash 100 Cr A/R 100
41
+ *
42
+ * Cash nets to zero across them; A/R moves from one order to the other. No new booking code exists
43
+ * for this operation, and none should — if it needed its own entries, that would mean the allocation
44
+ * path did not really understand negative applications.
45
+ *
46
+ * CROSS-COMPANY IS NOT A SPECIAL CASE EITHER. When the two orders belong to different companies the
47
+ * same path raises the intercompany legs, because the allocation factory splits per owning company.
48
+ * Note this is not merely convenient: a single `Dr A/R / Cr A/R` entry spanning two companies could
49
+ * not be booked at all (accounting refuses cross-company entries, D6), so the per-company shape is
50
+ * the only bookable form rather than an implementation preference.
51
+ *
52
+ * FAILURE MODEL: logical refusals come back INSIDE the output as `Success: false` with a reason —
53
+ * the same contract `Orders.RefundPayment` and `Orders.CancelSubscription` use. Only genuine faults
54
+ * throw.
55
+ *
56
+ * CONNECTS TO:
57
+ * BOOKING: PaymentLineEntityServer.Save — both legs book through the ordinary allocation path
58
+ * TABLES: __mj_BizAppsOrders.{PaymentHeader,PaymentLine,PaymentDetail,OrderHeader}
59
+ * DOC: plans/archive/bizapps-orders-master.md D68
60
+ */
61
+ import { BaseRemotableOperation, LogError, RunView, } from '@memberjunction/core';
62
+ import { RegisterClass } from '@memberjunction/global';
63
+ import { RequireUUID } from './sql-guards.js';
64
+ import { LoadOrdersEngine, OrdersEngine } from '@mj-biz-apps/orders-entities';
65
+ const PAYMENT_HEADER_ENTITY = 'MJ_BizApps_Orders: Payment Headers';
66
+ const PAYMENT_LINE_ENTITY = 'MJ_BizApps_Orders: Payment Lines';
67
+ const PAYMENT_DETAIL_ENTITY = 'MJ_BizApps_Orders: Payment Details';
68
+ const PAYMENT_TYPE_ENTITY = 'MJ_BizApps_Orders: Payment Types';
69
+ const ORDER_HEADER_ENTITY = 'MJ_BizApps_Orders: Order Headers';
70
+ /** The payment type this operation writes. Seeded in metadata/payment-types. */
71
+ const ACCOUNT_CREDIT_TYPE_CODE = 'AccountCredit';
72
+ /** Half a cent — the same tolerance the allocation guard uses. */
73
+ const TOLERANCE = 0.005;
74
+ const money = (v) => Math.round((v + Number.EPSILON) * 100) / 100;
75
+ let ApplyAccountCreditOperation = class ApplyAccountCreditOperation extends BaseRemotableOperation {
76
+ constructor() {
77
+ super(...arguments);
78
+ this.OperationKey = 'Orders.ApplyAccountCredit';
79
+ }
80
+ async InternalExecute(input, provider, user) {
81
+ if (!input?.SourceOrderHeaderID || !input?.TargetOrderHeaderID) {
82
+ return { Success: false, Message: 'Both SourceOrderHeaderID and TargetOrderHeaderID are required.' };
83
+ }
84
+ // Caller-supplied ids reach SQL filter text downstream. Validated here,
85
+ // at the boundary, so every frame below this one can trust them.
86
+ RequireUUID(input.SourceOrderHeaderID, 'SourceOrderHeaderID');
87
+ RequireUUID(input.TargetOrderHeaderID, 'TargetOrderHeaderID');
88
+ if (input.SourceOrderHeaderID.toLowerCase() === input.TargetOrderHeaderID.toLowerCase()) {
89
+ return {
90
+ Success: false,
91
+ Message: 'The source and target orders are the same. Moving a credit onto the order that already holds it would change nothing.',
92
+ };
93
+ }
94
+ const source = await this.loadOrder(provider, user, input.SourceOrderHeaderID);
95
+ if (!source)
96
+ return { Success: false, Message: `Order ${input.SourceOrderHeaderID} was not found.` };
97
+ const target = await this.loadOrder(provider, user, input.TargetOrderHeaderID);
98
+ if (!target)
99
+ return { Success: false, Message: `Order ${input.TargetOrderHeaderID} was not found.` };
100
+ // The credit is the source order's negative balance, expressed positive.
101
+ const available = money(-Number(source.Balance ?? 0));
102
+ if (available <= TOLERANCE) {
103
+ return {
104
+ Success: false,
105
+ Message: `Order ${source.OrderNumber} has no credit to spend — its balance is ${money(Number(source.Balance ?? 0))}. ` +
106
+ `A credit exists only when an order has been paid MORE than it is worth, which shows as a negative balance.`,
107
+ };
108
+ }
109
+ // Nothing to pay toward is a refusal rather than a no-op: the caller believes it is settling
110
+ // something, and silently writing a zero-value payment would hide that it did not.
111
+ const owing = money(Number(target.Balance ?? 0));
112
+ if (owing <= TOLERANCE) {
113
+ return {
114
+ Success: false,
115
+ Message: `Order ${target.OrderNumber} has nothing outstanding (balance ${owing}), so there is nothing to apply the credit to.`,
116
+ };
117
+ }
118
+ // Default to as much as both sides allow; an explicit amount is checked against both.
119
+ const requested = input.Amount === undefined ? Math.min(available, owing) : money(Number(input.Amount));
120
+ if (!(requested > TOLERANCE)) {
121
+ return { Success: false, Message: `Amount must be greater than zero (received ${input.Amount}).` };
122
+ }
123
+ if (requested > available + TOLERANCE) {
124
+ return {
125
+ Success: false,
126
+ Message: `Order ${source.OrderNumber} only has ${available} of credit; ${requested} was requested.`,
127
+ };
128
+ }
129
+ if (requested > owing + TOLERANCE) {
130
+ return {
131
+ Success: false,
132
+ Message: `Order ${target.OrderNumber} only owes ${owing}; applying ${requested} would over-pay it. ` +
133
+ `Apply ${owing} instead, or spend the rest of the credit on another order.`,
134
+ };
135
+ }
136
+ const remainingCredit = money(available - requested);
137
+ const targetBalanceAfter = money(owing - requested);
138
+ if (input.Preview) {
139
+ return {
140
+ Success: true,
141
+ Message: `${requested} of order ${source.OrderNumber}'s credit would settle order ${target.OrderNumber}, ` +
142
+ `leaving ${remainingCredit} of credit and a balance of ${targetBalanceAfter}.`,
143
+ AppliedAmount: requested,
144
+ RemainingCredit: remainingCredit,
145
+ TargetBalanceAfter: targetBalanceAfter,
146
+ };
147
+ }
148
+ const typeID = await this.accountCreditTypeID(provider, user);
149
+ if (!typeID) {
150
+ return {
151
+ Success: false,
152
+ Message: `The '${ACCOUNT_CREDIT_TYPE_CODE}' payment type is not present. Push metadata/payment-types before applying credits.`,
153
+ };
154
+ }
155
+ const db = provider;
156
+ await db.BeginTransaction();
157
+ try {
158
+ const detail = await provider.GetEntityObject(PAYMENT_DETAIL_ENTITY, user);
159
+ detail.NewRecord();
160
+ detail.CompanyID = target.CompanyID;
161
+ detail.PaymentTypeID = typeID;
162
+ detail.SourceOrderHeaderID = source.ID;
163
+ detail.Notes = input.Reason ?? `Credit from order ${source.OrderNumber}`;
164
+ if (!(await detail.Save())) {
165
+ throw new Error(`Could not record the credit tender: ${detail.LatestResult?.CompleteMessage ?? 'unknown error'}`);
166
+ }
167
+ const payment = await provider.GetEntityObject(PAYMENT_HEADER_ENTITY, user);
168
+ payment.NewRecord();
169
+ const paymentNumber = await this.nextPaymentNumber(db);
170
+ payment.PaymentNumber = paymentNumber;
171
+ payment.ReceivingCompanyID = target.CompanyID;
172
+ payment.PaymentTypeID = typeID;
173
+ payment.PaymentDetailID = detail.ID;
174
+ // ZERO on purpose — no new cash entered the business, this re-attributes money already
175
+ // received. The D68 invariant holds exactly: 0 == (-requested) + (+requested).
176
+ payment.Amount = 0;
177
+ payment.ProcessingFeeAmount = 0;
178
+ payment.PaymentDate = new Date();
179
+ payment.Status = 'Captured';
180
+ payment.Notes = input.Reason ?? `Applied ${requested} of order ${source.OrderNumber}'s credit`;
181
+ // Both legs ride the header's Lines collection so they land inside this transaction and
182
+ // the invariant is checked against the pair, never against a half-written payment.
183
+ const consume = await provider.GetEntityObject(PAYMENT_LINE_ENTITY, user);
184
+ consume.NewRecord();
185
+ consume.OrderHeaderID = source.ID;
186
+ consume.Amount = -requested;
187
+ consume.AllocatedByUserID = user?.ID ?? null;
188
+ const apply = await provider.GetEntityObject(PAYMENT_LINE_ENTITY, user);
189
+ apply.NewRecord();
190
+ apply.OrderHeaderID = target.ID;
191
+ apply.Amount = requested;
192
+ apply.AllocatedByUserID = user?.ID ?? null;
193
+ // Attached, not assigned: `Lines` is a RelatedRecordCollection and `Add()` stamps
194
+ // PaymentHeaderID for us — correct even though the header has not been saved yet.
195
+ payment.Lines.Add(consume);
196
+ payment.Lines.Add(apply);
197
+ if (!(await payment.Save())) {
198
+ throw new Error(`Could not save the credit application: ${payment.LatestResult?.CompleteMessage ?? 'unknown error'}`);
199
+ }
200
+ await db.CommitTransaction();
201
+ return {
202
+ Success: true,
203
+ Message: `Applied ${requested} of order ${source.OrderNumber}'s credit to order ${target.OrderNumber} as ${paymentNumber}.`,
204
+ AppliedAmount: requested,
205
+ RemainingCredit: remainingCredit,
206
+ TargetBalanceAfter: targetBalanceAfter,
207
+ PaymentHeaderID: payment.ID,
208
+ PaymentNumber: paymentNumber,
209
+ };
210
+ }
211
+ catch (err) {
212
+ await db.RollbackTransaction();
213
+ LogError(err);
214
+ throw err;
215
+ }
216
+ }
217
+ async loadOrder(provider, user, id) {
218
+ const rv = new RunView(provider);
219
+ const res = await rv.RunView({
220
+ EntityName: ORDER_HEADER_ENTITY,
221
+ ExtraFilter: `ID='${id}'`,
222
+ Fields: ['ID', 'OrderNumber', 'Status', 'Balance', 'TotalGross', 'CompanyID'],
223
+ ResultType: 'simple',
224
+ BypassCache: true,
225
+ }, user);
226
+ return res?.Results?.[0] ?? null;
227
+ }
228
+ /**
229
+ * The `AccountCredit` tender's ID.
230
+ *
231
+ * Cache first, then the query it always did. The row is seeded metadata and the cache answers it
232
+ * without a round trip; the fallback stays because a deployment that has not seeded this tender
233
+ * yet, or one that added it in the transaction now running, must still resolve it — and the
234
+ * caller's whole operation depends on finding it.
235
+ */
236
+ async accountCreditTypeID(provider, user) {
237
+ await LoadOrdersEngine(provider, user);
238
+ const cached = OrdersEngine.Instance.PaymentTypeByCode(ACCOUNT_CREDIT_TYPE_CODE);
239
+ if (cached?.ID)
240
+ return cached.ID;
241
+ const rv = new RunView(provider);
242
+ const res = await rv.RunView({
243
+ EntityName: PAYMENT_TYPE_ENTITY,
244
+ ExtraFilter: `Code='${ACCOUNT_CREDIT_TYPE_CODE}'`,
245
+ Fields: ['ID'],
246
+ ResultType: 'simple',
247
+ BypassCache: true,
248
+ }, user);
249
+ return res?.Results?.[0]?.ID ?? null;
250
+ }
251
+ /** Gap-free payment numbering, same sequence the capture path uses. */
252
+ async nextPaymentNumber(db) {
253
+ const rows = (await db.ExecuteSQL(`
254
+ DECLARE @seq TABLE (Seq INT);
255
+ UPDATE __mj_BizAppsOrders.PaymentSequence WITH (UPDLOCK, HOLDLOCK)
256
+ SET NextSequenceNumber = NextSequenceNumber + 1
257
+ OUTPUT deleted.NextSequenceNumber INTO @seq(Seq)
258
+ WHERE ID = 1;
259
+ SELECT Seq FROM @seq;`));
260
+ const seq = rows?.[0]?.Seq;
261
+ if (!seq) {
262
+ throw new Error('Could not obtain the next payment number — PaymentSequence (ID=1) is missing.');
263
+ }
264
+ return `PAY-${String(seq).padStart(6, '0')}`;
265
+ }
266
+ };
267
+ ApplyAccountCreditOperation = __decorate([
268
+ RegisterClass(BaseRemotableOperation, 'Orders.ApplyAccountCredit')
269
+ ], ApplyAccountCreditOperation);
270
+ export { ApplyAccountCreditOperation };
271
+ /** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
272
+ export function LoadApplyAccountCreditOperation() {
273
+ // intentionally empty
274
+ }
275
+ //# sourceMappingURL=ApplyAccountCreditOperation.js.map