@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,220 @@
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
+ * PaymentProviderResolver — turns a `PaymentProvider` row into a working driver.
9
+ *
10
+ * Two jobs, and the second is the one with teeth.
11
+ *
12
+ * 1. FIND THE DRIVER. `PaymentProviderType.Code` is the `@RegisterClass` key (D37), so resolution is a
13
+ * ClassFactory lookup and adding a gateway needs no schema change. A missing registration REFUSES
14
+ * rather than falling back to the base class: the base's methods all decline, so a fallback would
15
+ * look like a gateway that cannot do anything rather than like a driver nobody registered — and the
16
+ * difference is a five-minute fix versus an afternoon.
17
+ *
18
+ * 2. FIND THE CREDENTIALS, WITHOUT EVER STORING THEM. `PaymentProvider.CredentialsRef` is a POINTER —
19
+ * the name of a place to look, not a secret. Nothing in this schema holds an API key, because a
20
+ * database that holds live payment credentials is a database whose backups do too.
21
+ *
22
+ * THE SECRET SEAM. `CredentialsRef` resolves through `BaseSecretResolver`, registered by ClassFactory
23
+ * like everything else here. The default reads environment variables, which is right for a single
24
+ * deployment and inadequate for a real one — so a customer using Vault, AWS Secrets Manager or Azure
25
+ * Key Vault registers a subclass and changes no other code. Naming the seam is the point; pretending
26
+ * environment variables are a secret store would be the mistake.
27
+ *
28
+ * CREDENTIALS ARE NEVER CACHED. They are fetched per operation and dropped. A cache would keep live
29
+ * keys in process memory for the lifetime of a server for the sake of avoiding a lookup that happens
30
+ * once per payment, which is not a trade worth making.
31
+ *
32
+ * CONNECTS TO:
33
+ * BASE: ./BasePaymentProvider.ts
34
+ * DRIVERS: ./StripePaymentProvider.ts · ./ManualPaymentProvider.ts · ./StoredValuePaymentProvider.ts
35
+ * DOC: plans/archive/bizapps-orders-master.md D19, D37
36
+ */
37
+ import { RunView } from '@memberjunction/core';
38
+ import { MJGlobal, RegisterClassEx } from '@memberjunction/global';
39
+ import { LoadOrdersEngine, OrdersEngine } from '@mj-biz-apps/orders-entities';
40
+ import { BasePaymentProvider, } from './BasePaymentProvider.js';
41
+ const PAYMENT_PROVIDER_ENTITY = 'MJ_BizApps_Orders: Payment Providers';
42
+ /**
43
+ * How a `CredentialsRef` becomes actual secrets.
44
+ *
45
+ * The default treats the ref as an environment-variable PREFIX, so `STRIPE_BLUECYPRESS` reads
46
+ * `STRIPE_BLUECYPRESS_API_KEY` and `STRIPE_BLUECYPRESS_WEBHOOK_SECRET`. Prefixed rather than a single
47
+ * variable because one deployment routinely holds several configured accounts — a live one and a test
48
+ * one at minimum — and they need separate keys.
49
+ */
50
+ export class BaseSecretResolver {
51
+ /**
52
+ * Returns whatever it can find. An EMPTY result is not an error here: a Manual provider has no
53
+ * credentials at all, and the driver that needs a key is the one that should complain about its
54
+ * absence, with the context to say what it was trying to do.
55
+ */
56
+ async Resolve(_credentialsRef) {
57
+ return {};
58
+ }
59
+ }
60
+ /**
61
+ * The default: `CredentialsRef` is an environment-variable PREFIX.
62
+ *
63
+ * `STRIPE_BLUECYPRESS` reads `STRIPE_BLUECYPRESS_API_KEY` and `STRIPE_BLUECYPRESS_WEBHOOK_SECRET`.
64
+ * Prefixed rather than a single variable because one deployment routinely holds several configured
65
+ * accounts — a live one and a test one at minimum — and they need separate keys.
66
+ *
67
+ * Registered with NO key, so it is the fallback a deployment replaces by registering its own against
68
+ * `BaseSecretResolver` — the same shape as `DefaultPriceResolver`.
69
+ */
70
+ let EnvironmentSecretResolver = class EnvironmentSecretResolver extends BaseSecretResolver {
71
+ async Resolve(credentialsRef) {
72
+ if (!credentialsRef)
73
+ return {};
74
+ const prefix = credentialsRef.replace(/[^A-Za-z0-9_]/g, '_').toUpperCase();
75
+ const env = process.env;
76
+ const credentials = {};
77
+ // `|| undefined` rather than `?? ''`: an empty string satisfies a truthiness check downstream
78
+ // and produces an authorization header of `Bearer `, which fails confusingly.
79
+ credentials.ApiKey = env[`${prefix}_API_KEY`] || undefined;
80
+ credentials.WebhookSecret = env[`${prefix}_WEBHOOK_SECRET`] || undefined;
81
+ return credentials;
82
+ }
83
+ };
84
+ EnvironmentSecretResolver = __decorate([
85
+ RegisterClassEx(BaseSecretResolver, { skipNullKeyWarning: true })
86
+ ], EnvironmentSecretResolver);
87
+ export { EnvironmentSecretResolver };
88
+ /** Tree-shaking anchor for the secret seam. */
89
+ export function LoadEnvironmentSecretResolver() {
90
+ // intentionally empty
91
+ }
92
+ export class PaymentProviderNotConfiguredError extends Error {
93
+ }
94
+ /**
95
+ * Load a configured provider row and hand back a ready driver.
96
+ *
97
+ * Throws rather than returning null. Every caller of this is about to move money and cannot proceed
98
+ * without a driver, so there is no branch for a caller to take — and an exception carries the reason to
99
+ * a log, where a returned null would arrive as "cannot read property of undefined" somewhere else.
100
+ */
101
+ export async function ResolvePaymentProvider(paymentProviderID, provider, user) {
102
+ const config = await LoadPaymentProviderConfig(paymentProviderID, provider, user);
103
+ return BuildPaymentProvider(config, provider, user);
104
+ }
105
+ /** The configured account, with its type's code and capability flags flattened onto it. */
106
+ export async function LoadPaymentProviderConfig(paymentProviderID, provider, user) {
107
+ if (!/^[0-9a-fA-F-]{36}$/.test(paymentProviderID)) {
108
+ throw new PaymentProviderNotConfiguredError(`'${paymentProviderID}' is not a valid payment provider identifier.`);
109
+ }
110
+ const rv = new RunView(provider);
111
+ // The generated view flattens the type's fields onto the provider, which is what makes this one
112
+ // query rather than two. `PaymentProviderType` is the related entity, so `Code` arrives as
113
+ // `PaymentProviderType` — MJ names a related display field after its entity.
114
+ const result = await rv.RunView({
115
+ EntityName: PAYMENT_PROVIDER_ENTITY,
116
+ ExtraFilter: `ID = '${paymentProviderID}'`,
117
+ ResultType: 'simple',
118
+ }, user);
119
+ const row = result?.Results?.[0];
120
+ if (!row) {
121
+ throw new PaymentProviderNotConfiguredError(`No payment provider ${paymentProviderID} exists. A payment cannot be routed without one.`);
122
+ }
123
+ if (!row.IsActive) {
124
+ throw new PaymentProviderNotConfiguredError(`Payment provider '${row.Name}' is inactive. Reactivate it or point the payment at another, ` +
125
+ `rather than letting an inactive gateway be used silently.`);
126
+ }
127
+ const typeCode = await resolveTypeCode(row.PaymentProviderTypeID, row.PaymentProviderType, provider, user);
128
+ return {
129
+ ID: row.ID,
130
+ TypeCode: typeCode.Code,
131
+ CompanyID: row.CompanyID,
132
+ Name: row.Name,
133
+ CredentialsRef: row.CredentialsRef,
134
+ IsLiveMode: !!row.IsLiveMode,
135
+ Capabilities: {
136
+ SupportsTokenization: typeCode.SupportsTokenization,
137
+ SupportsRefund: typeCode.SupportsRefund,
138
+ SupportsWebhooks: typeCode.SupportsWebhooks,
139
+ },
140
+ };
141
+ }
142
+ /**
143
+ * Instantiate the driver for a config and attach everything it needs.
144
+ *
145
+ * Exposed separately from `ResolvePaymentProvider` so the webhook route can build a driver from a config
146
+ * it already loaded — the route resolves a provider from the URL before it has a payment in hand, and
147
+ * making it re-query would mean two lookups for one request.
148
+ */
149
+ export async function BuildPaymentProvider(config, provider, user) {
150
+ const driver = MJGlobal.Instance.ClassFactory.CreateInstance(BasePaymentProvider, config.TypeCode);
151
+ if (!driver) {
152
+ throw new PaymentProviderNotConfiguredError(`No payment driver is registered for provider type '${config.TypeCode}'. Register one with ` +
153
+ `@RegisterClass(BasePaymentProvider, '${config.TypeCode}') and call its Load* anchor from ` +
154
+ `the server bootstrap — without the anchor the decorator is tree-shaken away and the ` +
155
+ `class is silently absent.`);
156
+ }
157
+ // REFUSE THE BASE CLASS. `CreateInstance` falls back to the base when no key matches, and the base
158
+ // declines every operation — so accepting it would turn "nobody registered a Stripe driver" into
159
+ // "Stripe cannot take payments", which sends the reader to the gateway instead of to the bootstrap.
160
+ if (driver.constructor === BasePaymentProvider) {
161
+ throw new PaymentProviderNotConfiguredError(`Provider type '${config.TypeCode}' resolved to the BASE payment driver, which implements ` +
162
+ `nothing. Its Load* anchor is almost certainly missing from the server bootstrap.`);
163
+ }
164
+ const secrets = MJGlobal.Instance.ClassFactory.CreateInstance(BaseSecretResolver) ??
165
+ new EnvironmentSecretResolver();
166
+ driver.Config = config;
167
+ driver.Credentials = await secrets.Resolve(config.CredentialsRef);
168
+ driver.Provider = provider;
169
+ driver.User = user;
170
+ return driver;
171
+ }
172
+ /**
173
+ * The type's `Code` and capability flags.
174
+ *
175
+ * The provider view carries the type's NAME as a related field, and name is not key — a deployment may
176
+ * rename 'Stripe' to 'Stripe (Blue Cypress)' and the ClassFactory key must not move with it. So the
177
+ * type row is read for its `Code`.
178
+ */
179
+ async function resolveTypeCode(typeID, relatedName, provider, user) {
180
+ // CACHE FIRST, THEN THE QUERY — and the fallback is not belt-and-braces.
181
+ //
182
+ // Provider types are seeded metadata and belong in {@link OrdersEngine} like every other lookup,
183
+ // so the common path is a property read. But unlike the other lookups, a provider type is also
184
+ // created at RUN TIME: a deployment adding a gateway, and the integration fixture creating one
185
+ // inside a rolled-back transaction. A cache loaded before that row existed cannot see it, and a
186
+ // miss here does not degrade gracefully — it throws `PaymentProviderNotConfiguredError`, which
187
+ // reads as "this gateway is not set up" for a gateway that plainly is.
188
+ //
189
+ // So a miss falls through to the query it always did. Same behaviour, same errors; the reads
190
+ // that hit the cache simply stop costing a round trip.
191
+ await LoadOrdersEngine(provider, user);
192
+ const cached = OrdersEngine.Instance.PaymentProviderTypeByID(typeID);
193
+ let type = cached
194
+ ? {
195
+ Code: cached.Code,
196
+ SupportsTokenization: cached.SupportsTokenization,
197
+ SupportsRefund: cached.SupportsRefund,
198
+ SupportsWebhooks: cached.SupportsWebhooks,
199
+ }
200
+ : undefined;
201
+ if (!type) {
202
+ const rv = new RunView(provider);
203
+ const result = await rv.RunView({
204
+ EntityName: 'MJ_BizApps_Orders: Payment Provider Types',
205
+ ExtraFilter: `ID = '${typeID}'`,
206
+ ResultType: 'simple',
207
+ }, user);
208
+ type = result?.Results?.[0];
209
+ }
210
+ if (!type) {
211
+ throw new PaymentProviderNotConfiguredError(`Payment provider type ${typeID}${relatedName ? ` ('${relatedName}')` : ''} was not found.`);
212
+ }
213
+ return {
214
+ Code: type.Code,
215
+ SupportsTokenization: !!type.SupportsTokenization,
216
+ SupportsRefund: !!type.SupportsRefund,
217
+ SupportsWebhooks: !!type.SupportsWebhooks,
218
+ };
219
+ }
220
+ //# sourceMappingURL=PaymentProviderResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentProviderResolver.js","sourceRoot":"","sources":["../src/PaymentProviderResolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Building the payment that takes money back out — the one way, used by both callers.
3
+ *
4
+ * TWO THINGS REVERSE A PAYMENT, and until bank debits arrived only one of them existed:
5
+ *
6
+ * `Orders.RefundPayment` somebody DECIDED to give the money back
7
+ * `PaymentSettlement` the BANK took it back, days after we booked it as received
8
+ *
9
+ * They differ entirely in why they happen and not at all in what they must write. Both produce a new
10
+ * `PaymentHeader` with `Status='Refunded'` and `ReversesPaymentHeaderID` pointing at the original,
11
+ * carrying negative `PaymentLine`s that un-apply the cash from the orders the original settled. That
12
+ * shape is not incidental — `Status='Refunded'` is precisely what makes `PaymentHeaderEntityServer`
13
+ * book the MIRROR of the capture entry (D53), and the negative lines are what move each order's
14
+ * `Balance` back up. A second implementation that got any part of it subtly different would produce a
15
+ * reversal that balances, posts, and is wrong, which is the failure mode nothing downstream catches.
16
+ *
17
+ * SO THE MECHANICS LIVE HERE AND THE POLICY LIVES IN THE CALLERS. Whether a refund is allowed, how
18
+ * much is still refundable, whether a returned debit should reverse at all — those are decisions, and
19
+ * they stay with whoever is making them. This module only knows how to write the reversal once the
20
+ * decision is made.
21
+ *
22
+ * WHY `.Set()` AND `BaseEntity` RATHER THAN A TYPED SUBCLASS. `PaymentHeader`'s `Lines` collection is
23
+ * transient — CodeGen cannot emit it, so the generated entity has no property for it — and the whole
24
+ * point of this factory is to hand the header its lines before the single co-ordinated save. That is
25
+ * the same reason `RefundPaymentOperation` and `CapturePaymentOperation` work this way.
26
+ *
27
+ * CONNECTS TO:
28
+ * CALLERS: ./RefundPaymentOperation.ts · ./PaymentSettlement.ts
29
+ * BOOKING: ./PaymentHeaderEntityServer.ts — the reversal books through the ordinary save path
30
+ * DOC: plans/archive/bizapps-orders-master.md D17, D39, D53, D68
31
+ */
32
+ import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
33
+ import { mjBizAppsOrdersPaymentLineEntity } from '@mj-biz-apps/orders-entities';
34
+ /** The fields of the original payment a reversal has to carry forward. */
35
+ export interface ReversiblePayment {
36
+ ID: string;
37
+ PaymentNumber: string;
38
+ ReceivingCompanyID: string;
39
+ BillToOrganizationID: string | null;
40
+ BillToPersonID: string | null;
41
+ PaymentTypeID: string;
42
+ PaymentDetailID: string | null;
43
+ }
44
+ /** One order the original payment was applied to, and by how much. */
45
+ export interface AppliedAllocation {
46
+ OrderHeaderID: string;
47
+ Amount: number;
48
+ }
49
+ /** Why this reversal is being written, and what to stamp on it. */
50
+ export interface PaymentReversalRequest {
51
+ /** Positive magnitude, as `Amount` is stored on both a capture and a reversal. */
52
+ Amount: number;
53
+ Reason: string | null;
54
+ /** The gateway's own refund/return id, when the money moved through one. */
55
+ ProviderRefundID?: string | null;
56
+ /** Defaults to `Refund of {original}`. Settlement overrides it to name the return. */
57
+ Description?: string;
58
+ }
59
+ export interface PaymentReversalResult {
60
+ ID: string;
61
+ Number: string;
62
+ JournalEntryID?: string;
63
+ }
64
+ /**
65
+ * The orders a captured payment settled, and by how much.
66
+ *
67
+ * Only POSITIVE lines: a payment that has already been partly reversed carries negative lines too, and
68
+ * counting them would shrink the base a further reversal is spread across.
69
+ */
70
+ export declare function LoadAppliedAllocations(provider: IMetadataProvider, user: UserInfo, paymentID: string): Promise<AppliedAllocation[]>;
71
+ /**
72
+ * Un-apply the reversed cash from the orders the original settled.
73
+ *
74
+ * PROPORTIONAL, so a payment split across three orders reverses across the same three rather than
75
+ * dumping the whole thing on whichever happened to be first — which would leave two orders looking
76
+ * paid and one looking wildly overdue. The final line absorbs the rounding remainder so the un-applied
77
+ * total is exact rather than a penny short, which the allocation invariant would reject.
78
+ */
79
+ export declare function BuildUnapplyLines(provider: IMetadataProvider, user: UserInfo, applications: AppliedAllocation[], reversalAmount: number): Promise<mjBizAppsOrdersPaymentLineEntity[]>;
80
+ /**
81
+ * A fresh instrument snapshot for the reversal, never the original's row (D39).
82
+ *
83
+ * `PaymentDetail` is a point-in-time record of the instrument as it was. Sharing one row between the
84
+ * capture and its reversal would mean editing either rewrites the other's history.
85
+ */
86
+ export declare function CopyPaymentDetail(provider: IMetadataProvider, user: UserInfo, sourceID: string): Promise<string>;
87
+ /**
88
+ * The next number in the shared payment series.
89
+ *
90
+ * The SAME counter the capture path uses, so a reversal sits in the same series as everything else
91
+ * rather than in a parallel one nobody thinks to search.
92
+ */
93
+ export declare function NextPaymentNumber(provider: IMetadataProvider): Promise<string>;
94
+ /**
95
+ * Write the reversing payment, header and un-apply lines in ONE save.
96
+ *
97
+ * ONE SAVE IS THE REQUIREMENT, not an optimisation. `PaymentHeaderEntityServer` checks the allocation
98
+ * invariant across the header and its lines together (D68) and books the mirrored entries as the lines
99
+ * go down. Saving the header first would present a reversal for the full amount with no allocations
100
+ * against it — which the invariant correctly rejects — and any failure between the two steps would
101
+ * leave that state in the database permanently.
102
+ *
103
+ * THE FEE IS NOT MIRRORED. A processor does not hand its cut back when a payment reverses, so a
104
+ * reversal that carried the original's fee would credit back money nobody received.
105
+ */
106
+ export declare function CreateReversingPayment(provider: IMetadataProvider, user: UserInfo, original: ReversiblePayment, request: PaymentReversalRequest, lines: mjBizAppsOrdersPaymentLineEntity[]): Promise<PaymentReversalResult>;
107
+ //# sourceMappingURL=PaymentReversalFactory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentReversalFactory.d.ts","sourceRoot":"","sources":["../src/PaymentReversalFactory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAIH,KAAK,iBAAiB,EAEtB,KAAK,QAAQ,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAEH,gCAAgC,EACnC,MAAM,8BAA8B,CAAC;AAStC,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,mEAAmE;AACnE,MAAM,WAAW,sBAAsB;IACnC,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,sFAAsF;IACtF,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,SAAS,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAe9B;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,YAAY,EAAE,iBAAiB,EAAE,EACjC,cAAc,EAAE,MAAM,GACvB,OAAO,CAAC,gCAAgC,EAAE,CAAC,CAyB7C;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACnC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAepF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,sBAAsB,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,EACd,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,sBAAsB,EAC/B,KAAK,EAAE,gCAAgC,EAAE,GAC1C,OAAO,CAAC,qBAAqB,CAAC,CAoChC"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Building the payment that takes money back out — the one way, used by both callers.
3
+ *
4
+ * TWO THINGS REVERSE A PAYMENT, and until bank debits arrived only one of them existed:
5
+ *
6
+ * `Orders.RefundPayment` somebody DECIDED to give the money back
7
+ * `PaymentSettlement` the BANK took it back, days after we booked it as received
8
+ *
9
+ * They differ entirely in why they happen and not at all in what they must write. Both produce a new
10
+ * `PaymentHeader` with `Status='Refunded'` and `ReversesPaymentHeaderID` pointing at the original,
11
+ * carrying negative `PaymentLine`s that un-apply the cash from the orders the original settled. That
12
+ * shape is not incidental — `Status='Refunded'` is precisely what makes `PaymentHeaderEntityServer`
13
+ * book the MIRROR of the capture entry (D53), and the negative lines are what move each order's
14
+ * `Balance` back up. A second implementation that got any part of it subtly different would produce a
15
+ * reversal that balances, posts, and is wrong, which is the failure mode nothing downstream catches.
16
+ *
17
+ * SO THE MECHANICS LIVE HERE AND THE POLICY LIVES IN THE CALLERS. Whether a refund is allowed, how
18
+ * much is still refundable, whether a returned debit should reverse at all — those are decisions, and
19
+ * they stay with whoever is making them. This module only knows how to write the reversal once the
20
+ * decision is made.
21
+ *
22
+ * WHY `.Set()` AND `BaseEntity` RATHER THAN A TYPED SUBCLASS. `PaymentHeader`'s `Lines` collection is
23
+ * transient — CodeGen cannot emit it, so the generated entity has no property for it — and the whole
24
+ * point of this factory is to hand the header its lines before the single co-ordinated save. That is
25
+ * the same reason `RefundPaymentOperation` and `CapturePaymentOperation` work this way.
26
+ *
27
+ * CONNECTS TO:
28
+ * CALLERS: ./RefundPaymentOperation.ts · ./PaymentSettlement.ts
29
+ * BOOKING: ./PaymentHeaderEntityServer.ts — the reversal books through the ordinary save path
30
+ * DOC: plans/archive/bizapps-orders-master.md D17, D39, D53, D68
31
+ */
32
+ import { CompositeKey, RunView, } from '@memberjunction/core';
33
+ const PAYMENT_HEADER_ENTITY = 'MJ_BizApps_Orders: Payment Headers';
34
+ const PAYMENT_LINE_ENTITY = 'MJ_BizApps_Orders: Payment Lines';
35
+ const PAYMENT_DETAIL_ENTITY = 'MJ_BizApps_Orders: Payment Details';
36
+ const money = (v) => Math.round((v + Number.EPSILON) * 100) / 100;
37
+ /**
38
+ * The orders a captured payment settled, and by how much.
39
+ *
40
+ * Only POSITIVE lines: a payment that has already been partly reversed carries negative lines too, and
41
+ * counting them would shrink the base a further reversal is spread across.
42
+ */
43
+ export async function LoadAppliedAllocations(provider, user, paymentID) {
44
+ const rv = new RunView(provider);
45
+ const result = await rv.RunView({
46
+ EntityName: PAYMENT_LINE_ENTITY,
47
+ ExtraFilter: `PaymentHeaderID='${paymentID}'`,
48
+ Fields: ['OrderHeaderID', 'Amount'],
49
+ ResultType: 'simple',
50
+ // The lines may have been written moments ago by the capture this is reversing, and a
51
+ // cached read that missed them would spread the reversal across too few orders.
52
+ BypassCache: true,
53
+ }, user);
54
+ return (result?.Results ?? []).filter((r) => Number(r.Amount) > 0);
55
+ }
56
+ /**
57
+ * Un-apply the reversed cash from the orders the original settled.
58
+ *
59
+ * PROPORTIONAL, so a payment split across three orders reverses across the same three rather than
60
+ * dumping the whole thing on whichever happened to be first — which would leave two orders looking
61
+ * paid and one looking wildly overdue. The final line absorbs the rounding remainder so the un-applied
62
+ * total is exact rather than a penny short, which the allocation invariant would reject.
63
+ */
64
+ export async function BuildUnapplyLines(provider, user, applications, reversalAmount) {
65
+ const built = [];
66
+ const appliedTotal = applications.reduce((s, a) => s + Number(a.Amount), 0);
67
+ if (appliedTotal <= 0)
68
+ return built;
69
+ let allocated = 0;
70
+ for (let i = 0; i < applications.length; i++) {
71
+ const app = applications[i];
72
+ const isLast = i === applications.length - 1;
73
+ const share = isLast
74
+ ? money(reversalAmount - allocated)
75
+ : money((Number(app.Amount) / appliedTotal) * reversalAmount);
76
+ allocated = money(allocated + share);
77
+ if (share <= 0)
78
+ continue;
79
+ const line = await provider.GetEntityObject(PAYMENT_LINE_ENTITY, user);
80
+ line.NewRecord();
81
+ line.OrderHeaderID = app.OrderHeaderID;
82
+ // NEGATIVE: this removes cash from the order, which is what moves Balance back up.
83
+ line.Amount = -share;
84
+ line.AllocatedAt = new Date();
85
+ line.AllocatedByUserID = user?.ID ?? null;
86
+ built.push(line);
87
+ }
88
+ return built;
89
+ }
90
+ /**
91
+ * A fresh instrument snapshot for the reversal, never the original's row (D39).
92
+ *
93
+ * `PaymentDetail` is a point-in-time record of the instrument as it was. Sharing one row between the
94
+ * capture and its reversal would mean editing either rewrites the other's history.
95
+ */
96
+ export async function CopyPaymentDetail(provider, user, sourceID) {
97
+ const source = await provider.GetEntityObject(PAYMENT_DETAIL_ENTITY, CompositeKey.FromID(sourceID), user);
98
+ const copy = await provider.GetEntityObject(PAYMENT_DETAIL_ENTITY, user);
99
+ copy.NewRecord();
100
+ // `CopyFrom` skips primary keys by default, which is the only exclusion this needs: the
101
+ // `__mj_*` columns the hand-rolled loop also skipped are ReadOnly and are not parameters of
102
+ // spCreatePaymentDetail, so copying them cannot reach the insert.
103
+ copy.CopyFrom(source);
104
+ if (!(await copy.Save())) {
105
+ throw new Error(`Failed to copy the payment instrument: ${copy.LatestResult?.CompleteMessage ?? 'unknown error'}`);
106
+ }
107
+ return copy.ID;
108
+ }
109
+ /**
110
+ * The next number in the shared payment series.
111
+ *
112
+ * The SAME counter the capture path uses, so a reversal sits in the same series as everything else
113
+ * rather than in a parallel one nobody thinks to search.
114
+ */
115
+ export async function NextPaymentNumber(provider) {
116
+ const db = provider;
117
+ const rows = (await db.ExecuteSQL(`
118
+ DECLARE @seq TABLE (Seq INT);
119
+ UPDATE __mj_BizAppsOrders.PaymentSequence WITH (UPDLOCK, HOLDLOCK)
120
+ SET NextSequenceNumber = NextSequenceNumber + 1
121
+ OUTPUT deleted.NextSequenceNumber INTO @seq(Seq)
122
+ WHERE ID = 1;
123
+ SELECT Seq FROM @seq;`));
124
+ const seq = rows?.[0]?.Seq;
125
+ if (!seq) {
126
+ throw new Error('Could not obtain the next payment number — PaymentSequence (ID=1) is missing.');
127
+ }
128
+ return `PAY-${String(seq).padStart(6, '0')}`;
129
+ }
130
+ /**
131
+ * Write the reversing payment, header and un-apply lines in ONE save.
132
+ *
133
+ * ONE SAVE IS THE REQUIREMENT, not an optimisation. `PaymentHeaderEntityServer` checks the allocation
134
+ * invariant across the header and its lines together (D68) and books the mirrored entries as the lines
135
+ * go down. Saving the header first would present a reversal for the full amount with no allocations
136
+ * against it — which the invariant correctly rejects — and any failure between the two steps would
137
+ * leave that state in the database permanently.
138
+ *
139
+ * THE FEE IS NOT MIRRORED. A processor does not hand its cut back when a payment reverses, so a
140
+ * reversal that carried the original's fee would credit back money nobody received.
141
+ */
142
+ export async function CreateReversingPayment(provider, user, original, request, lines) {
143
+ const reversal = await provider.GetEntityObject(PAYMENT_HEADER_ENTITY, user);
144
+ reversal.NewRecord();
145
+ reversal.PaymentNumber = await NextPaymentNumber(provider);
146
+ reversal.ReceivingCompanyID = original.ReceivingCompanyID;
147
+ reversal.BillToOrganizationID = original.BillToOrganizationID;
148
+ reversal.BillToPersonID = original.BillToPersonID;
149
+ reversal.PaymentDate = new Date();
150
+ reversal.PaymentTypeID = original.PaymentTypeID;
151
+ reversal.Amount = request.Amount;
152
+ reversal.ProcessingFeeAmount = 0;
153
+ reversal.ReversesPaymentHeaderID = original.ID;
154
+ reversal.ReversalReason = request.Reason ?? null;
155
+ reversal.ProviderRefundID = request.ProviderRefundID ?? null;
156
+ reversal.Status = 'Refunded';
157
+ reversal.Description = request.Description ?? `Refund of ${original.PaymentNumber}`;
158
+ if (original.PaymentDetailID) {
159
+ reversal.PaymentDetailID = await CopyPaymentDetail(provider, user, original.PaymentDetailID);
160
+ }
161
+ // Attached, not assigned — the collection stamps PaymentHeaderID.
162
+ for (const line of lines)
163
+ reversal.Lines.Add(line);
164
+ if (!(await reversal.Save())) {
165
+ throw new Error(`Failed to create the reversal of ${original.PaymentNumber}: ` +
166
+ `${reversal.LatestResult?.CompleteMessage ?? 'unknown error'}`);
167
+ }
168
+ return {
169
+ ID: reversal.ID,
170
+ Number: reversal.PaymentNumber,
171
+ JournalEntryID: reversal.JournalEntryID ?? undefined,
172
+ };
173
+ }
174
+ //# sourceMappingURL=PaymentReversalFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentReversalFactory.js","sourceRoot":"","sources":["../src/PaymentReversalFactory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAEH,YAAY,EACZ,OAAO,GAIV,MAAM,sBAAsB,CAAC;AAO9B,MAAM,qBAAqB,GAAG,oCAAoC,CAAC;AACnE,MAAM,mBAAmB,GAAG,kCAAkC,CAAC;AAC/D,MAAM,qBAAqB,GAAG,oCAAoC,CAAC;AAEnE,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAoClF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CACxC,QAA2B,EAC3B,IAAc,EACd,SAAiB;IAEjB,MAAM,EAAE,GAAG,IAAI,OAAO,CAAC,QAAuC,CAAC,CAAC;IAChE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAC3B;QACI,UAAU,EAAE,mBAAmB;QAC/B,WAAW,EAAE,oBAAoB,SAAS,GAAG;QAC7C,MAAM,EAAE,CAAC,eAAe,EAAE,QAAQ,CAAC;QACnC,UAAU,EAAE,QAAQ;QACpB,sFAAsF;QACtF,gFAAgF;QAChF,WAAW,EAAE,IAAI;KACpB,EACD,IAAI,CACP,CAAC;IACF,OAAO,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,QAA2B,EAC3B,IAAc,EACd,YAAiC,EACjC,cAAsB;IAEtB,MAAM,KAAK,GAAuC,EAAE,CAAC;IACrD,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IAC5E,IAAI,YAAY,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAEpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,CAAC,KAAK,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC7C,MAAM,KAAK,GAAG,MAAM;YAChB,CAAC,CAAC,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;YACnC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,YAAY,CAAC,GAAG,cAAc,CAAC,CAAC;QAClE,SAAS,GAAG,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;QACrC,IAAI,KAAK,IAAI,CAAC;YAAE,SAAS;QAEzB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAmC,mBAAmB,EAAE,IAAI,CAAC,CAAC;QACzG,IAAI,CAAC,SAAS,EAAE,CAAC;QACjB,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;QACvC,mFAAmF;QACnF,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,iBAAiB,GAAG,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,QAA2B,EAC3B,IAAc,EACd,QAAgB;IAEhB,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,CACzC,qBAAqB,EACrB,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,EAC7B,IAAI,CACP,CAAC;IACF,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAqC,qBAAqB,EAAE,IAAI,CAAC,CAAC;IAC7G,IAAI,CAAC,SAAS,EAAE,CAAC;IACjB,wFAAwF;IACxF,4FAA4F;IAC5F,kEAAkE;IAClE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtB,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACX,0CAA0C,IAAI,CAAC,YAAY,EAAE,eAAe,IAAI,eAAe,EAAE,CACpG,CAAC;IACN,CAAC;IACD,OAAO,IAAI,CAAC,EAAE,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAA2B;IAC/D,MAAM,EAAE,GAAG,QAAoE,CAAC;IAChF,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC;;;;;;8BAMR,CAAC,CAA2B,CAAC;IAEvD,MAAM,GAAG,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;IAC3B,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;IACrG,CAAC;IACD,OAAO,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CACxC,QAA2B,EAC3B,IAAc,EACd,QAA2B,EAC3B,OAA+B,EAC/B,KAAyC;IAEzC,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,eAAe,CAA4B,qBAAqB,EAAE,IAAI,CAAC,CAAC;IACxG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACrB,QAAQ,CAAC,aAAa,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC3D,QAAQ,CAAC,kBAAkB,GAAG,QAAQ,CAAC,kBAAkB,CAAC;IAC1D,QAAQ,CAAC,oBAAoB,GAAG,QAAQ,CAAC,oBAAoB,CAAC;IAC9D,QAAQ,CAAC,cAAc,GAAG,QAAQ,CAAC,cAAc,CAAC;IAClD,QAAQ,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;IAChD,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,GAAG,CAAC,CAAC;IACjC,QAAQ,CAAC,uBAAuB,GAAG,QAAQ,CAAC,EAAE,CAAC;IAC/C,QAAQ,CAAC,cAAc,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACjD,QAAQ,CAAC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,IAAI,CAAC;IAC7D,QAAQ,CAAC,MAAM,GAAG,UAAU,CAAC;IAC7B,QAAQ,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,aAAa,QAAQ,CAAC,aAAa,EAAE,CAAC;IAEpF,IAAI,QAAQ,CAAC,eAAe,EAAE,CAAC;QAC3B,QAAQ,CAAC,eAAe,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;IACjG,CAAC;IAED,kEAAkE;IAClE,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEnD,IAAI,CAAC,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACX,oCAAoC,QAAQ,CAAC,aAAa,IAAI;YAC1D,GAAG,QAAQ,CAAC,YAAY,EAAE,eAAe,IAAI,eAAe,EAAE,CACrE,CAAC;IACN,CAAC;IAED,OAAO;QACH,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,MAAM,EAAE,QAAQ,CAAC,aAAa;QAC9B,cAAc,EAAE,QAAQ,CAAC,cAAc,IAAI,SAAS;KACvD,CAAC;AACN,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Promoting a bank debit into cash — the only place a webhook is allowed to move money.
3
+ *
4
+ * WHY THIS EXISTS AT ALL. `PaymentWebhookHandler` was written deliberately narrow: it records what the
5
+ * gateway said on the `PaymentIntent` and stops there, because a webhook reaching into the ledger
6
+ * would give an unauthenticated endpoint a second path into the books. That was exactly right for
7
+ * cards, where the money has already moved by the time anyone asks and the event only confirms it.
8
+ *
9
+ * A bank debit breaks the assumption underneath it. Nothing has moved when the caller asks; the answer
10
+ * arrives days later, in an event, and there is no other moment at which cash can honestly be booked.
11
+ * So the webhook has to be able to move money — and this module is that capability, kept in one file,
12
+ * reachable only when a driver has declared `SettlesAsynchronously`, and doing exactly three things.
13
+ *
14
+ * IT DOES NOT BOOK ANYTHING ITSELF. That is the part worth being clear about. `Promote` sets a status
15
+ * and saves; `PaymentHeaderEntityServer` notices the transition into `Captured` and books the cash
16
+ * through the same path a card capture uses — including calling back to the driver to ask what
17
+ * actually moved. `Reverse` writes a reversing payment through the same factory `Orders.RefundPayment`
18
+ * uses. Nothing here writes a journal entry, and nothing here knows how one is shaped. The ledger keeps
19
+ * a single author.
20
+ *
21
+ * ORDERING MATTERS, AND IT IS NOT THE OBVIOUS ONE. This runs BEFORE the handler stamps
22
+ * `PaymentIntent.ProviderEventID`, not after. Stamping first would look tidier and would silently
23
+ * strand payments: the stamp is the idempotency key, so an event that was recorded and then failed to
24
+ * settle would be judged `AlreadyApplied` on every retry, and a payment the bank confirmed would sit
25
+ * `Pending` forever with nothing left to move it. Settling first means a failure returns 500 with
26
+ * nothing stamped, the gateway retries, and both steps run again. The re-run is safe because
27
+ * `DecideSettlement` reads the PAYMENT'S state rather than the event's novelty — a promotion that
28
+ * already happened decides `None`.
29
+ *
30
+ * CONNECTS TO:
31
+ * PURE: ./PaymentProviderBehavior.ts — DecideSettlement, the decision table
32
+ * ROUTE: ./PaymentWebhookHandler.ts — the only caller
33
+ * WRITES: ./PaymentHeaderEntityServer.ts (promote) · ./PaymentReversalFactory.ts (reverse)
34
+ * DOC: plans/archive/bizapps-orders-master.md D17, D19, D53
35
+ */
36
+ import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
37
+ import { type SettlementAction } from './PaymentProviderBehavior.js';
38
+ import type { WebhookEvent } from './BasePaymentProvider.js';
39
+ export interface SettlementOutcome {
40
+ Action: SettlementAction;
41
+ Reason: string;
42
+ /** The payment the event was about, when there was one. */
43
+ PaymentHeaderID?: string;
44
+ /** The reversing payment written, when the action was `Reverse`. */
45
+ ReversalPaymentHeaderID?: string;
46
+ }
47
+ /**
48
+ * Apply a settlement event to the payment behind its intent.
49
+ *
50
+ * THROWS ON FAULTS, DELIBERATELY. A refusal here is not a business outcome to be reported and
51
+ * forgotten — it means the bank told us something about real money and we failed to record it. The
52
+ * caller turns a throw into a 500 so the gateway asks again, which is the only way that notice is not
53
+ * lost. Decisions that legitimately do nothing (`None`, `Hold`) return normally.
54
+ */
55
+ export declare function SettlePaymentForEvent(event: WebhookEvent, paymentIntentID: string, provider: IMetadataProvider, user: UserInfo): Promise<SettlementOutcome>;
56
+ //# sourceMappingURL=PaymentSettlement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentSettlement.d.ts","sourceRoot":"","sources":["../src/PaymentSettlement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,OAAO,EAOH,KAAK,iBAAiB,EAEtB,KAAK,QAAQ,EAChB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACvF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAkB7D,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,gBAAgB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,uBAAuB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACvC,KAAK,EAAE,YAAY,EACnB,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,iBAAiB,CAAC,CAmE5B"}