@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.
- package/LICENSE +183 -0
- package/README.md +141 -2
- package/dist/AccountingBridge.d.ts +65 -0
- package/dist/AccountingBridge.d.ts.map +1 -0
- package/dist/AccountingBridge.js +102 -0
- package/dist/AccountingBridge.js.map +1 -0
- package/dist/AdvanceOrderStateOperation.d.ts +80 -0
- package/dist/AdvanceOrderStateOperation.d.ts.map +1 -0
- package/dist/AdvanceOrderStateOperation.js +267 -0
- package/dist/AdvanceOrderStateOperation.js.map +1 -0
- package/dist/ApplyAccountCreditOperation.d.ts +97 -0
- package/dist/ApplyAccountCreditOperation.d.ts.map +1 -0
- package/dist/ApplyAccountCreditOperation.js +275 -0
- package/dist/ApplyAccountCreditOperation.js.map +1 -0
- package/dist/BaseDeliveryChannel.d.ts +106 -0
- package/dist/BaseDeliveryChannel.d.ts.map +1 -0
- package/dist/BaseDeliveryChannel.js +36 -0
- package/dist/BaseDeliveryChannel.js.map +1 -0
- package/dist/BasePaymentProvider.d.ts +239 -0
- package/dist/BasePaymentProvider.d.ts.map +1 -0
- package/dist/BasePaymentProvider.js +91 -0
- package/dist/BasePaymentProvider.js.map +1 -0
- package/dist/BundleBehavior.d.ts +139 -0
- package/dist/BundleBehavior.d.ts.map +1 -0
- package/dist/BundleBehavior.js +173 -0
- package/dist/BundleBehavior.js.map +1 -0
- package/dist/BundleEngine.d.ts +60 -0
- package/dist/BundleEngine.d.ts.map +1 -0
- package/dist/BundleEngine.js +197 -0
- package/dist/BundleEngine.js.map +1 -0
- package/dist/CancelSubscriptionOperation.d.ts +98 -0
- package/dist/CancelSubscriptionOperation.d.ts.map +1 -0
- package/dist/CancelSubscriptionOperation.js +317 -0
- package/dist/CancelSubscriptionOperation.js.map +1 -0
- package/dist/CapturePaymentOperation.d.ts +62 -0
- package/dist/CapturePaymentOperation.d.ts.map +1 -0
- package/dist/CapturePaymentOperation.js +463 -0
- package/dist/CapturePaymentOperation.js.map +1 -0
- package/dist/CheckEntitlementOperation.d.ts +27 -0
- package/dist/CheckEntitlementOperation.d.ts.map +1 -0
- package/dist/CheckEntitlementOperation.js +45 -0
- package/dist/CheckEntitlementOperation.js.map +1 -0
- package/dist/CheckoutSessionService.d.ts +258 -0
- package/dist/CheckoutSessionService.d.ts.map +1 -0
- package/dist/CheckoutSessionService.js +1557 -0
- package/dist/CheckoutSessionService.js.map +1 -0
- package/dist/DeliveryBehavior.d.ts +121 -0
- package/dist/DeliveryBehavior.d.ts.map +1 -0
- package/dist/DeliveryBehavior.js +145 -0
- package/dist/DeliveryBehavior.js.map +1 -0
- package/dist/DeliveryRecipientResolver.d.ts +38 -0
- package/dist/DeliveryRecipientResolver.d.ts.map +1 -0
- package/dist/DeliveryRecipientResolver.js +93 -0
- package/dist/DeliveryRecipientResolver.js.map +1 -0
- package/dist/DeliveryResolver.d.ts +14 -0
- package/dist/DeliveryResolver.d.ts.map +1 -0
- package/dist/DeliveryResolver.js +45 -0
- package/dist/DeliveryResolver.js.map +1 -0
- package/dist/EmailDeliveryChannel.d.ts +31 -0
- package/dist/EmailDeliveryChannel.d.ts.map +1 -0
- package/dist/EmailDeliveryChannel.js +158 -0
- package/dist/EmailDeliveryChannel.js.map +1 -0
- package/dist/EntitlementBehavior.d.ts +235 -0
- package/dist/EntitlementBehavior.d.ts.map +1 -0
- package/dist/EntitlementBehavior.js +330 -0
- package/dist/EntitlementBehavior.js.map +1 -0
- package/dist/EntitlementEngine.d.ts +97 -0
- package/dist/EntitlementEngine.d.ts.map +1 -0
- package/dist/EntitlementEngine.js +338 -0
- package/dist/EntitlementEngine.js.map +1 -0
- package/dist/EntitlementGrantClaimDriver.d.ts +42 -0
- package/dist/EntitlementGrantClaimDriver.d.ts.map +1 -0
- package/dist/EntitlementGrantClaimDriver.js +158 -0
- package/dist/EntitlementGrantClaimDriver.js.map +1 -0
- package/dist/EntitlementRead.d.ts +82 -0
- package/dist/EntitlementRead.d.ts.map +1 -0
- package/dist/EntitlementRead.js +368 -0
- package/dist/EntitlementRead.js.map +1 -0
- package/dist/FulfillOrderLinesOperation.d.ts +34 -0
- package/dist/FulfillOrderLinesOperation.d.ts.map +1 -0
- package/dist/FulfillOrderLinesOperation.js +208 -0
- package/dist/FulfillOrderLinesOperation.js.map +1 -0
- package/dist/FulfillmentBehavior.d.ts +101 -0
- package/dist/FulfillmentBehavior.d.ts.map +1 -0
- package/dist/FulfillmentBehavior.js +145 -0
- package/dist/FulfillmentBehavior.js.map +1 -0
- package/dist/GLAccountResolver.d.ts +123 -0
- package/dist/GLAccountResolver.d.ts.map +1 -0
- package/dist/GLAccountResolver.js +175 -0
- package/dist/GLAccountResolver.js.map +1 -0
- package/dist/GetFulfillmentQueueOperation.d.ts +35 -0
- package/dist/GetFulfillmentQueueOperation.d.ts.map +1 -0
- package/dist/GetFulfillmentQueueOperation.js +221 -0
- package/dist/GetFulfillmentQueueOperation.js.map +1 -0
- package/dist/GetOverdueWorklistOperation.d.ts +41 -0
- package/dist/GetOverdueWorklistOperation.d.ts.map +1 -0
- package/dist/GetOverdueWorklistOperation.js +210 -0
- package/dist/GetOverdueWorklistOperation.js.map +1 -0
- package/dist/GiftCardBehavior.d.ts +97 -0
- package/dist/GiftCardBehavior.d.ts.map +1 -0
- package/dist/GiftCardBehavior.js +121 -0
- package/dist/GiftCardBehavior.js.map +1 -0
- package/dist/GiftCardEngine.d.ts +59 -0
- package/dist/GiftCardEngine.d.ts.map +1 -0
- package/dist/GiftCardEngine.js +197 -0
- package/dist/GiftCardEngine.js.map +1 -0
- package/dist/GuestOrderClaimDriver.d.ts +36 -0
- package/dist/GuestOrderClaimDriver.d.ts.map +1 -0
- package/dist/GuestOrderClaimDriver.js +161 -0
- package/dist/GuestOrderClaimDriver.js.map +1 -0
- package/dist/InvoiceBehavior.d.ts +394 -0
- package/dist/InvoiceBehavior.d.ts.map +1 -0
- package/dist/InvoiceBehavior.js +496 -0
- package/dist/InvoiceBehavior.js.map +1 -0
- package/dist/InvoiceBuilder.d.ts +48 -0
- package/dist/InvoiceBuilder.d.ts.map +1 -0
- package/dist/InvoiceBuilder.js +352 -0
- package/dist/InvoiceBuilder.js.map +1 -0
- package/dist/InvoiceDisplay.d.ts +96 -0
- package/dist/InvoiceDisplay.d.ts.map +1 -0
- package/dist/InvoiceDisplay.js +121 -0
- package/dist/InvoiceDisplay.js.map +1 -0
- package/dist/ListEntitlementsOperation.d.ts +21 -0
- package/dist/ListEntitlementsOperation.d.ts.map +1 -0
- package/dist/ListEntitlementsOperation.js +39 -0
- package/dist/ListEntitlementsOperation.js.map +1 -0
- package/dist/ManualPaymentProvider.d.ts +19 -0
- package/dist/ManualPaymentProvider.d.ts.map +1 -0
- package/dist/ManualPaymentProvider.js +92 -0
- package/dist/ManualPaymentProvider.js.map +1 -0
- package/dist/OrderEntityServer.d.ts +542 -0
- package/dist/OrderEntityServer.d.ts.map +1 -0
- package/dist/OrderEntityServer.js +2100 -0
- package/dist/OrderEntityServer.js.map +1 -0
- package/dist/OrderJournalEntryFactory.d.ts +140 -0
- package/dist/OrderJournalEntryFactory.d.ts.map +1 -0
- package/dist/OrderJournalEntryFactory.js +466 -0
- package/dist/OrderJournalEntryFactory.js.map +1 -0
- package/dist/OrderLineEntityServer.d.ts +90 -0
- package/dist/OrderLineEntityServer.d.ts.map +1 -0
- package/dist/OrderLineEntityServer.js +260 -0
- package/dist/OrderLineEntityServer.js.map +1 -0
- package/dist/OrdersSettings.d.ts +36 -0
- package/dist/OrdersSettings.d.ts.map +1 -0
- package/dist/OrdersSettings.js +147 -0
- package/dist/OrdersSettings.js.map +1 -0
- package/dist/PaymentAllocationFactory.d.ts +128 -0
- package/dist/PaymentAllocationFactory.d.ts.map +1 -0
- package/dist/PaymentAllocationFactory.js +235 -0
- package/dist/PaymentAllocationFactory.js.map +1 -0
- package/dist/PaymentHeaderEntityServer.d.ts +180 -0
- package/dist/PaymentHeaderEntityServer.d.ts.map +1 -0
- package/dist/PaymentHeaderEntityServer.js +656 -0
- package/dist/PaymentHeaderEntityServer.js.map +1 -0
- package/dist/PaymentIntentService.d.ts +101 -0
- package/dist/PaymentIntentService.d.ts.map +1 -0
- package/dist/PaymentIntentService.js +150 -0
- package/dist/PaymentIntentService.js.map +1 -0
- package/dist/PaymentJournalEntryFactory.d.ts +99 -0
- package/dist/PaymentJournalEntryFactory.d.ts.map +1 -0
- package/dist/PaymentJournalEntryFactory.js +127 -0
- package/dist/PaymentJournalEntryFactory.js.map +1 -0
- package/dist/PaymentLineEntityServer.d.ts +73 -0
- package/dist/PaymentLineEntityServer.d.ts.map +1 -0
- package/dist/PaymentLineEntityServer.js +303 -0
- package/dist/PaymentLineEntityServer.js.map +1 -0
- package/dist/PaymentProviderBehavior.d.ts +222 -0
- package/dist/PaymentProviderBehavior.d.ts.map +1 -0
- package/dist/PaymentProviderBehavior.js +368 -0
- package/dist/PaymentProviderBehavior.js.map +1 -0
- package/dist/PaymentProviderResolver.d.ts +84 -0
- package/dist/PaymentProviderResolver.d.ts.map +1 -0
- package/dist/PaymentProviderResolver.js +220 -0
- package/dist/PaymentProviderResolver.js.map +1 -0
- package/dist/PaymentReversalFactory.d.ts +107 -0
- package/dist/PaymentReversalFactory.d.ts.map +1 -0
- package/dist/PaymentReversalFactory.js +174 -0
- package/dist/PaymentReversalFactory.js.map +1 -0
- package/dist/PaymentSettlement.d.ts +56 -0
- package/dist/PaymentSettlement.d.ts.map +1 -0
- package/dist/PaymentSettlement.js +243 -0
- package/dist/PaymentSettlement.js.map +1 -0
- package/dist/PaymentTermsBehavior.d.ts +109 -0
- package/dist/PaymentTermsBehavior.d.ts.map +1 -0
- package/dist/PaymentTermsBehavior.js +172 -0
- package/dist/PaymentTermsBehavior.js.map +1 -0
- package/dist/PaymentWebhookHandler.d.ts +103 -0
- package/dist/PaymentWebhookHandler.d.ts.map +1 -0
- package/dist/PaymentWebhookHandler.js +246 -0
- package/dist/PaymentWebhookHandler.js.map +1 -0
- package/dist/PreviewPriceOperation.d.ts +62 -0
- package/dist/PreviewPriceOperation.d.ts.map +1 -0
- package/dist/PreviewPriceOperation.js +161 -0
- package/dist/PreviewPriceOperation.js.map +1 -0
- package/dist/PriceOrderOperation.d.ts +93 -0
- package/dist/PriceOrderOperation.d.ts.map +1 -0
- package/dist/PriceOrderOperation.js +146 -0
- package/dist/PriceOrderOperation.js.map +1 -0
- package/dist/ProductPriceEntityServer.d.ts +34 -0
- package/dist/ProductPriceEntityServer.d.ts.map +1 -0
- package/dist/ProductPriceEntityServer.js +97 -0
- package/dist/ProductPriceEntityServer.js.map +1 -0
- package/dist/RefundPaymentOperation.d.ts +61 -0
- package/dist/RefundPaymentOperation.d.ts.map +1 -0
- package/dist/RefundPaymentOperation.js +177 -0
- package/dist/RefundPaymentOperation.js.map +1 -0
- package/dist/RevenueRecognition.d.ts +76 -0
- package/dist/RevenueRecognition.d.ts.map +1 -0
- package/dist/RevenueRecognition.js +133 -0
- package/dist/RevenueRecognition.js.map +1 -0
- package/dist/ReversalBehavior.d.ts +82 -0
- package/dist/ReversalBehavior.d.ts.map +1 -0
- package/dist/ReversalBehavior.js +100 -0
- package/dist/ReversalBehavior.js.map +1 -0
- package/dist/ReversalResolver.d.ts +37 -0
- package/dist/ReversalResolver.d.ts.map +1 -0
- package/dist/ReversalResolver.js +96 -0
- package/dist/ReversalResolver.js.map +1 -0
- package/dist/SpawnRenewalsOperation.d.ts +109 -0
- package/dist/SpawnRenewalsOperation.d.ts.map +1 -0
- package/dist/SpawnRenewalsOperation.js +295 -0
- package/dist/SpawnRenewalsOperation.js.map +1 -0
- package/dist/StoredValuePaymentProvider.d.ts +52 -0
- package/dist/StoredValuePaymentProvider.d.ts.map +1 -0
- package/dist/StoredValuePaymentProvider.js +205 -0
- package/dist/StoredValuePaymentProvider.js.map +1 -0
- package/dist/StripeACHPaymentProvider.d.ts +50 -0
- package/dist/StripeACHPaymentProvider.d.ts.map +1 -0
- package/dist/StripeACHPaymentProvider.js +211 -0
- package/dist/StripeACHPaymentProvider.js.map +1 -0
- package/dist/StripePaymentProvider.d.ts +83 -0
- package/dist/StripePaymentProvider.d.ts.map +1 -0
- package/dist/StripePaymentProvider.js +442 -0
- package/dist/StripePaymentProvider.js.map +1 -0
- package/dist/SubscriptionBehavior.d.ts +197 -0
- package/dist/SubscriptionBehavior.d.ts.map +1 -0
- package/dist/SubscriptionBehavior.js +415 -0
- package/dist/SubscriptionBehavior.js.map +1 -0
- package/dist/checkoutCaptureAlert.d.ts +16 -0
- package/dist/checkoutCaptureAlert.d.ts.map +1 -0
- package/dist/checkoutCaptureAlert.js +55 -0
- package/dist/checkoutCaptureAlert.js.map +1 -0
- package/dist/checkoutCaptureRetry.d.ts +27 -0
- package/dist/checkoutCaptureRetry.d.ts.map +1 -0
- package/dist/checkoutCaptureRetry.js +50 -0
- package/dist/checkoutCaptureRetry.js.map +1 -0
- package/dist/claimDriverHelpers.d.ts +15 -0
- package/dist/claimDriverHelpers.d.ts.map +1 -0
- package/dist/claimDriverHelpers.js +34 -0
- package/dist/claimDriverHelpers.js.map +1 -0
- package/dist/entity-names.d.ts +15 -0
- package/dist/entity-names.d.ts.map +1 -0
- package/dist/entity-names.js +15 -0
- package/dist/entity-names.js.map +1 -0
- package/dist/identityClaimContracts.d.ts +118 -0
- package/dist/identityClaimContracts.d.ts.map +1 -0
- package/dist/identityClaimContracts.js +58 -0
- package/dist/identityClaimContracts.js.map +1 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +115 -0
- package/dist/index.js.map +1 -0
- package/dist/sql-guards.d.ts +78 -0
- package/dist/sql-guards.d.ts.map +1 -0
- package/dist/sql-guards.js +115 -0
- package/dist/sql-guards.js.map +1 -0
- package/package.json +50 -5
|
@@ -0,0 +1,317 @@
|
|
|
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.CancelSubscription — cancel a subscription atomically, by POLICY (design §5).
|
|
9
|
+
*
|
|
10
|
+
* WHY THIS IS AN OPERATION AND NOT A FORM
|
|
11
|
+
* The mechanics already worked: a reversal order line with a negative quantity produces mirrored
|
|
12
|
+
* journal entries through the ordinary booking path (D16). What did not work was asking a human to
|
|
13
|
+
* do it. Amith's case — a subscription running 1/1–12/31, cancelled on 7/1 — needs a line of
|
|
14
|
+
* quantity `-0.5`. That is correct double-entry and terrible data entry, and it silently ignores
|
|
15
|
+
* the `SubscriptionType`'s own rules about WHEN coverage may end and WHETHER money comes back.
|
|
16
|
+
*
|
|
17
|
+
* So the caller supplies a subscription, a date and a reason. `SubscriptionBehavior` decides what
|
|
18
|
+
* the rules permit; this operation performs it in ONE transaction:
|
|
19
|
+
*
|
|
20
|
+
* 1. resolve the affected term (the one whose window covers the request, else the latest)
|
|
21
|
+
* 2. ask the behaviour what the rules say — effective date, refund, reversal fraction
|
|
22
|
+
* 3. when there is something to reverse, emit a reversal ORDER whose single line carries the
|
|
23
|
+
* negative quantity and points at the original line, and confirm it — booking mirrors the JEs
|
|
24
|
+
* 4. stamp the term (Canceled/Completed, CanceledAt, CancellationEffectiveDate)
|
|
25
|
+
* 5. stamp the subscription (Canceled, EndDate = access-through, so grace is visible)
|
|
26
|
+
* 6. revoke standing grants when access-through has already passed; leave them when
|
|
27
|
+
* grace remains — the read evaluator honours `subscription.EndDate` either way
|
|
28
|
+
* 7. log a `SubscriptionEvent` — the lifecycle record that made the table worth having
|
|
29
|
+
*
|
|
30
|
+
* ATOMICITY: everything above shares one transaction opened here. The reversal order's own
|
|
31
|
+
* `OrderEntityServer.Save` nests inside it as savepoints (the same composition booking already
|
|
32
|
+
* relies on), so a failure anywhere leaves the subscription exactly as it was — never a reversed
|
|
33
|
+
* ledger with a still-active subscription, or vice versa.
|
|
34
|
+
*
|
|
35
|
+
* FAILURE MODEL: logical failures (unknown subscription, already cancelled, no term) come back
|
|
36
|
+
* INSIDE the output as `Success: false` with a message — the same contract accounting's operations
|
|
37
|
+
* use. Only genuine faults throw.
|
|
38
|
+
*
|
|
39
|
+
* CONNECTS TO:
|
|
40
|
+
* POLICY: SubscriptionBehavior.DecideCancellation (./SubscriptionBehavior.ts)
|
|
41
|
+
* BOOKING: OrderEntityServer.Save (./OrderEntityServer.ts) — the reversal order goes through it
|
|
42
|
+
* TABLES: __mj_BizAppsOrders.{Subscription,SubscriptionTerm,SubscriptionEvent,OrderHeader,OrderLine}
|
|
43
|
+
*/
|
|
44
|
+
import { BaseRemotableOperation, CompositeKey, LogError, RunView, } from '@memberjunction/core';
|
|
45
|
+
import { MJGlobal, RegisterClass } from '@memberjunction/global';
|
|
46
|
+
import { RequireUUID } from './sql-guards.js';
|
|
47
|
+
import { RevokeGrantsForCanceledSubscription } from './EntitlementEngine.js';
|
|
48
|
+
import { SubscriptionBehavior, } from './SubscriptionBehavior.js';
|
|
49
|
+
const SUBSCRIPTION_ENTITY = 'MJ_BizApps_Orders: Subscriptions';
|
|
50
|
+
const SUBSCRIPTION_TERM_ENTITY = 'MJ_BizApps_Orders: Subscription Terms';
|
|
51
|
+
const SUBSCRIPTION_EVENT_ENTITY = 'MJ_BizApps_Orders: Subscription Events';
|
|
52
|
+
const SUBSCRIPTION_TYPE_ENTITY = 'MJ_BizApps_Orders: Subscription Types';
|
|
53
|
+
const ORDER_HEADER_ENTITY = 'MJ_BizApps_Orders: Order Headers';
|
|
54
|
+
const ORDER_LINE_ENTITY = 'MJ_BizApps_Orders: Order Lines';
|
|
55
|
+
let CancelSubscriptionOperation = class CancelSubscriptionOperation extends BaseRemotableOperation {
|
|
56
|
+
constructor() {
|
|
57
|
+
super(...arguments);
|
|
58
|
+
this.OperationKey = 'Orders.CancelSubscription';
|
|
59
|
+
}
|
|
60
|
+
async InternalExecute(input, provider, user) {
|
|
61
|
+
// Caller-supplied ids reach SQL filter text downstream. Validated here,
|
|
62
|
+
// at the boundary, so every frame below this one can trust them.
|
|
63
|
+
RequireUUID(input.SubscriptionID, 'SubscriptionID');
|
|
64
|
+
const requestDate = input.RequestDate ? new Date(input.RequestDate) : new Date();
|
|
65
|
+
const subscription = await this.loadSubscription(provider, user, input.SubscriptionID);
|
|
66
|
+
if (!subscription) {
|
|
67
|
+
return { Success: false, Message: `No subscription found with ID '${input.SubscriptionID}'.` };
|
|
68
|
+
}
|
|
69
|
+
if (subscription.Status === 'Canceled') {
|
|
70
|
+
// Not an error worth throwing over — the caller asked for a state that already holds.
|
|
71
|
+
return { Success: false, Message: `Subscription is already canceled.` };
|
|
72
|
+
}
|
|
73
|
+
const rules = await this.loadRules(provider, user, subscription.SubscriptionTypeID);
|
|
74
|
+
if (!rules) {
|
|
75
|
+
return {
|
|
76
|
+
Success: false,
|
|
77
|
+
Message: `Subscription type '${subscription.SubscriptionTypeID}' was not found.`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const term = await this.resolveTerm(provider, user, subscription.ID, requestDate);
|
|
81
|
+
if (!term) {
|
|
82
|
+
return {
|
|
83
|
+
Success: false,
|
|
84
|
+
Message: `Subscription has no term to cancel — nothing was ever booked against it.`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const decision = this.behaviorFor(rules).DecideCancellation({
|
|
88
|
+
Rules: rules,
|
|
89
|
+
RequestDate: requestDate,
|
|
90
|
+
Term: {
|
|
91
|
+
StartDate: new Date(term.StartDate),
|
|
92
|
+
EndDate: new Date(term.EndDate),
|
|
93
|
+
Amount: Number(term.Amount),
|
|
94
|
+
TermNumber: term.TermNumber,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
if (input.Preview) {
|
|
98
|
+
return { Success: true, Decision: decision, SubscriptionTermID: term.ID, Message: decision.Explanation };
|
|
99
|
+
}
|
|
100
|
+
const dbProvider = provider;
|
|
101
|
+
await dbProvider.BeginTransaction();
|
|
102
|
+
try {
|
|
103
|
+
const reversal = decision.ReversalFraction > 0
|
|
104
|
+
? await this.emitReversalOrder(provider, user, subscription, term, decision, input.Reason)
|
|
105
|
+
: undefined;
|
|
106
|
+
await this.stampTerm(provider, user, term.ID, decision);
|
|
107
|
+
await this.stampSubscription(provider, user, subscription.ID, decision);
|
|
108
|
+
await this.syncGrantsOnCancel(provider, user, subscription.ID, decision, input.Reason);
|
|
109
|
+
await this.logEvent(provider, user, subscription.ID, decision, input.Reason, reversal?.ID);
|
|
110
|
+
await dbProvider.CommitTransaction();
|
|
111
|
+
return {
|
|
112
|
+
Success: true,
|
|
113
|
+
Message: decision.Explanation,
|
|
114
|
+
Decision: decision,
|
|
115
|
+
SubscriptionTermID: term.ID,
|
|
116
|
+
ReversalOrderID: reversal?.ID,
|
|
117
|
+
ReversalOrderNumber: reversal?.Number,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
LogError(`Orders.CancelSubscription failed for ${input.SubscriptionID}: ${err}`);
|
|
122
|
+
try {
|
|
123
|
+
await dbProvider.RollbackTransaction();
|
|
124
|
+
}
|
|
125
|
+
catch (rollbackErr) {
|
|
126
|
+
LogError(`Rollback failed after CancelSubscription error: ${rollbackErr}`);
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
Success: false,
|
|
130
|
+
Message: err instanceof Error ? err.message : String(err),
|
|
131
|
+
Decision: decision,
|
|
132
|
+
SubscriptionTermID: term.ID,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// ─── Reads ─────────────────────────────────────────────────────────────────
|
|
137
|
+
async loadSubscription(provider, user, id) {
|
|
138
|
+
const rv = new RunView(provider);
|
|
139
|
+
const result = await rv.RunView({
|
|
140
|
+
EntityName: SUBSCRIPTION_ENTITY,
|
|
141
|
+
ExtraFilter: `ID='${id}'`,
|
|
142
|
+
Fields: [
|
|
143
|
+
'ID',
|
|
144
|
+
'CompanyID',
|
|
145
|
+
'SubscriptionTypeID',
|
|
146
|
+
'ProductID',
|
|
147
|
+
'Status',
|
|
148
|
+
'HolderOrganizationID',
|
|
149
|
+
'BeneficiaryPersonID',
|
|
150
|
+
],
|
|
151
|
+
ResultType: 'simple',
|
|
152
|
+
// The caller may have just written this row; a cached read would decide policy on
|
|
153
|
+
// stale status.
|
|
154
|
+
BypassCache: true,
|
|
155
|
+
}, user);
|
|
156
|
+
return result?.Results?.[0] ?? null;
|
|
157
|
+
}
|
|
158
|
+
async loadRules(provider, user, typeID) {
|
|
159
|
+
const rv = new RunView(provider);
|
|
160
|
+
const result = await rv.RunView({ EntityName: SUBSCRIPTION_TYPE_ENTITY, ExtraFilter: `ID='${typeID}'`, ResultType: 'simple' }, user);
|
|
161
|
+
return result?.Results?.[0] ?? null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The term the request lands in, or — when the request falls outside every window (an early
|
|
165
|
+
* cancellation of a future term, or a late one after everything lapsed) — the latest term.
|
|
166
|
+
* Cancelling always has to act on SOMETHING for the reversal to point at.
|
|
167
|
+
*/
|
|
168
|
+
async resolveTerm(provider, user, subscriptionID, requestDate) {
|
|
169
|
+
const rv = new RunView(provider);
|
|
170
|
+
const result = await rv.RunView({
|
|
171
|
+
EntityName: SUBSCRIPTION_TERM_ENTITY,
|
|
172
|
+
ExtraFilter: `SubscriptionID='${subscriptionID}' AND Status IN ('Scheduled','Active')`,
|
|
173
|
+
OrderBy: 'TermNumber DESC',
|
|
174
|
+
ResultType: 'simple',
|
|
175
|
+
BypassCache: true,
|
|
176
|
+
}, user);
|
|
177
|
+
const terms = result?.Results ?? [];
|
|
178
|
+
if (terms.length === 0)
|
|
179
|
+
return null;
|
|
180
|
+
const at = requestDate.getTime();
|
|
181
|
+
const covering = terms.find((t) => new Date(t.StartDate).getTime() <= at && new Date(t.EndDate).getTime() >= at);
|
|
182
|
+
return covering ?? terms[0];
|
|
183
|
+
}
|
|
184
|
+
// ─── Writes ────────────────────────────────────────────────────────────────
|
|
185
|
+
/**
|
|
186
|
+
* A reversal order carrying ONE line: the negative slice of the original purchase.
|
|
187
|
+
*
|
|
188
|
+
* It goes through the ordinary confirm path rather than writing journal entries directly, so the
|
|
189
|
+
* mirrored ledger, the GL account resolution and the all-or-none guarantee are the SAME code
|
|
190
|
+
* that booked the original. `ReversesOrderLineID` is what makes a negative quantity legal
|
|
191
|
+
* (OrderLineEntityServer validates exactly that).
|
|
192
|
+
*/
|
|
193
|
+
async emitReversalOrder(provider, user, subscription, term, decision, reason) {
|
|
194
|
+
const original = await this.loadOriginalLine(provider, user, term.OrderLineID);
|
|
195
|
+
if (!original) {
|
|
196
|
+
throw new Error(`The order line that bought term ${term.TermNumber} (${term.OrderLineID}) no longer exists, ` +
|
|
197
|
+
`so the cancellation cannot be reversed against it.`);
|
|
198
|
+
}
|
|
199
|
+
const order = await provider.GetEntityObject(ORDER_HEADER_ENTITY, user);
|
|
200
|
+
order.NewRecord();
|
|
201
|
+
// 'Cancellation' — one of the CK_OrderHeader_OrderType values. There is no 'Reversal'
|
|
202
|
+
// order type; reversal is what the negative LINE does, not what the order is called.
|
|
203
|
+
order.OrderType = 'Cancellation';
|
|
204
|
+
order.OrderDate = decision.EffectiveDate;
|
|
205
|
+
order.CompanyID = subscription.CompanyID;
|
|
206
|
+
order.BillToOrganizationID = subscription.HolderOrganizationID;
|
|
207
|
+
order.BillToPersonID = subscription.BeneficiaryPersonID;
|
|
208
|
+
order.Notes = reason ? `Subscription cancellation: ${reason}` : 'Subscription cancellation';
|
|
209
|
+
const line = await provider.GetEntityObject(ORDER_LINE_ENTITY, user);
|
|
210
|
+
line.NewRecord();
|
|
211
|
+
line.ProductID = original.ProductID;
|
|
212
|
+
line.LineNumber = 1;
|
|
213
|
+
// A FRACTION OF THE ORIGINAL LINE, not of one unit. The purchased line may already carry a
|
|
214
|
+
// prorated quantity (a short first period), so reversing `-fraction` flat would unwind more
|
|
215
|
+
// than was ever sold. Rounded to the column's 4dp scale for the same reason the purchase
|
|
216
|
+
// path rounds: an unrounded quantity is truncated on insert and the recomputed total then
|
|
217
|
+
// disagrees with the stored one.
|
|
218
|
+
const reversalQuantity = Math.round(Number(original.Quantity) * decision.ReversalFraction * 1e4) / 1e4;
|
|
219
|
+
if (reversalQuantity === 0) {
|
|
220
|
+
throw new Error(`The computed reversal (${decision.ReversalFraction} of quantity ${original.Quantity}) ` +
|
|
221
|
+
`rounds to zero, which is not a valid order line. Nothing can be reversed at this size.`);
|
|
222
|
+
}
|
|
223
|
+
line.Quantity = -reversalQuantity;
|
|
224
|
+
line.UnitPrice = original.UnitPrice;
|
|
225
|
+
line.DiscountPct = original.DiscountPct ?? 0;
|
|
226
|
+
line.ReversesOrderLineID = original.ID;
|
|
227
|
+
line.ServicePeriodStart = decision.EffectiveDate;
|
|
228
|
+
line.ServicePeriodEnd = new Date(term.EndDate);
|
|
229
|
+
// Attached rather than assigned: `Lines` is a RelatedRecordCollection on the generated
|
|
230
|
+
// class, and `Add()` stamps OrderHeaderID and the LineNumber for us.
|
|
231
|
+
order.Lines.Add(line);
|
|
232
|
+
order.Status = 'Confirmed';
|
|
233
|
+
if (!(await order.Save())) {
|
|
234
|
+
throw new Error(`Failed to book the reversal order: ${order.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
235
|
+
}
|
|
236
|
+
return { ID: order.ID, Number: order.OrderNumber };
|
|
237
|
+
}
|
|
238
|
+
async loadOriginalLine(provider, user, orderLineID) {
|
|
239
|
+
const rv = new RunView(provider);
|
|
240
|
+
const result = await rv.RunView({
|
|
241
|
+
EntityName: ORDER_LINE_ENTITY,
|
|
242
|
+
ExtraFilter: `ID='${orderLineID}'`,
|
|
243
|
+
Fields: ['ID', 'OrderHeaderID', 'ProductID', 'Quantity', 'UnitPrice', 'DiscountPct'],
|
|
244
|
+
ResultType: 'simple',
|
|
245
|
+
BypassCache: true,
|
|
246
|
+
}, user);
|
|
247
|
+
return result?.Results?.[0] ?? null;
|
|
248
|
+
}
|
|
249
|
+
async stampTerm(provider, user, termID, decision) {
|
|
250
|
+
const term = await provider.GetEntityObject(SUBSCRIPTION_TERM_ENTITY, CompositeKey.FromID(termID), user);
|
|
251
|
+
term.Status = decision.TermStatus;
|
|
252
|
+
term.CanceledAt = new Date();
|
|
253
|
+
term.CancellationEffectiveDate = decision.EffectiveDate;
|
|
254
|
+
if (!(await term.Save())) {
|
|
255
|
+
throw new Error(`Failed to stamp the term: ${term.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async stampSubscription(provider, user, subscriptionID, decision) {
|
|
259
|
+
const sub = await provider.GetEntityObject(SUBSCRIPTION_ENTITY, CompositeKey.FromID(subscriptionID), user);
|
|
260
|
+
sub.Status = 'Canceled';
|
|
261
|
+
sub.CanceledAt = new Date();
|
|
262
|
+
// EndDate is the ACCESS date, not the revenue date — grace is exactly the window where the
|
|
263
|
+
// customer still gets in but nothing more is earned.
|
|
264
|
+
sub.EndDate = decision.AccessThroughDate;
|
|
265
|
+
sub.AutoRenew = false;
|
|
266
|
+
if (!(await sub.Save())) {
|
|
267
|
+
throw new Error(`Failed to stamp the subscription: ${sub.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async logEvent(provider, user, subscriptionID, decision, reason, reversalOrderID) {
|
|
271
|
+
const event = await provider.GetEntityObject(SUBSCRIPTION_EVENT_ENTITY, user);
|
|
272
|
+
event.NewRecord();
|
|
273
|
+
event.SubscriptionID = subscriptionID;
|
|
274
|
+
event.EventType = 'Canceled';
|
|
275
|
+
event.OccurredAt = new Date();
|
|
276
|
+
event.RelatedOrderHeaderID = reversalOrderID ?? null;
|
|
277
|
+
event.EventData = JSON.stringify({
|
|
278
|
+
EffectiveDate: decision.EffectiveDate,
|
|
279
|
+
AccessThroughDate: decision.AccessThroughDate,
|
|
280
|
+
RefundAmount: decision.RefundAmount,
|
|
281
|
+
ReversalFraction: decision.ReversalFraction,
|
|
282
|
+
TermStatus: decision.TermStatus,
|
|
283
|
+
Explanation: decision.Explanation,
|
|
284
|
+
Reason: reason ?? null,
|
|
285
|
+
});
|
|
286
|
+
if (!(await event.Save())) {
|
|
287
|
+
throw new Error(`Failed to log the cancellation event: ${event.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Stored grant Status is a lie after cancel unless we revoke when access has already
|
|
292
|
+
* ended. Grace (AccessThroughDate still in the future) leaves the rows standing — the
|
|
293
|
+
* evaluator honours subscription.EndDate rather than the original ValidTo.
|
|
294
|
+
*/
|
|
295
|
+
async syncGrantsOnCancel(provider, user, subscriptionID, decision, reason) {
|
|
296
|
+
await RevokeGrantsForCanceledSubscription(subscriptionID, decision.AccessThroughDate, reason ? `Subscription canceled: ${reason}` : 'Subscription canceled', provider, user);
|
|
297
|
+
}
|
|
298
|
+
/** The base behaviour, or the type's registered subclass when it names one (D45). */
|
|
299
|
+
behaviorFor(rules) {
|
|
300
|
+
if (!rules.DriverClass)
|
|
301
|
+
return new SubscriptionBehavior();
|
|
302
|
+
const driver = MJGlobal.Instance.ClassFactory.CreateInstance(SubscriptionBehavior, rules.DriverClass);
|
|
303
|
+
if (!driver) {
|
|
304
|
+
throw new Error(`Subscription type '${rules.Code}' names driver '${rules.DriverClass}', which is not registered.`);
|
|
305
|
+
}
|
|
306
|
+
return driver;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
CancelSubscriptionOperation = __decorate([
|
|
310
|
+
RegisterClass(BaseRemotableOperation, 'Orders.CancelSubscription')
|
|
311
|
+
], CancelSubscriptionOperation);
|
|
312
|
+
export { CancelSubscriptionOperation };
|
|
313
|
+
/** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
|
|
314
|
+
export function LoadCancelSubscriptionOperation() {
|
|
315
|
+
// intentionally empty
|
|
316
|
+
}
|
|
317
|
+
//# sourceMappingURL=CancelSubscriptionOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CancelSubscriptionOperation.js","sourceRoot":"","sources":["../src/CancelSubscriptionOperation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview `Orders.CapturePayment` — take a payment and allocate it, in one transaction.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS AT ALL. A payment is a HEADER plus its ALLOCATION LINES, and
|
|
5
|
+
* `PaymentHeaderEntityServer.Lines` is a TRANSIENT collection rather than a column. CodeGen cannot
|
|
6
|
+
* emit it on the client entity, so a browser `entity.Save()` has nowhere to put the allocations.
|
|
7
|
+
* That is precisely the situation `Orders.SaveOrder` was built for, and it needs the same answer.
|
|
8
|
+
*
|
|
9
|
+
* A two-step create-then-allocate flow was rejected: between the steps there would be a captured
|
|
10
|
+
* payment with no allocations in the database — cash recorded against nothing — and any failure in
|
|
11
|
+
* the second step would leave it there permanently.
|
|
12
|
+
*
|
|
13
|
+
* READ WHAT THE ENGINE COMPUTED; DO NOT RECOMPUTE. The fee, the net, and every order rollup are
|
|
14
|
+
* read back from the saved rows. Recomputing them here would eventually disagree with the ledger,
|
|
15
|
+
* and the disagreement surfaces as a balanced journal entry for the wrong amount — which nothing
|
|
16
|
+
* downstream can catch.
|
|
17
|
+
*
|
|
18
|
+
* @module @mj-biz-apps/orders-core-entities-server
|
|
19
|
+
*/
|
|
20
|
+
import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
|
|
21
|
+
import { OrdersCapturePaymentOperation as OrdersCapturePaymentOperationBase, type OrdersCapturePaymentInput, type OrdersCapturePaymentOutput } from '@mj-biz-apps/orders-entities';
|
|
22
|
+
export declare class CapturePaymentOperation extends OrdersCapturePaymentOperationBase {
|
|
23
|
+
protected InternalExecute(input: OrdersCapturePaymentInput, provider: IMetadataProvider, user: UserInfo): Promise<OrdersCapturePaymentOutput>;
|
|
24
|
+
/**
|
|
25
|
+
* Header + detail + allocation lines, saved ONCE.
|
|
26
|
+
*
|
|
27
|
+
* The allocations go onto the transient `Lines` collection and are written inside the header's
|
|
28
|
+
* own transaction — the whole reason this operation exists. Status is set to Captured BEFORE the
|
|
29
|
+
* save, because `savePendingLines` books from that collection and a header saved Pending would
|
|
30
|
+
* persist its lines without booking anything.
|
|
31
|
+
*/
|
|
32
|
+
private writePayment;
|
|
33
|
+
/**
|
|
34
|
+
* Whether this payment's gateway settles on someone else's schedule.
|
|
35
|
+
*
|
|
36
|
+
* Asked of the DRIVER, not of configuration — see `BasePaymentProvider.SettlesAsynchronously` for
|
|
37
|
+
* why an operator must not be able to declare that ACH settles instantly.
|
|
38
|
+
*
|
|
39
|
+
* FALSE WHEN ANYTHING GOES WRONG, deliberately. A payment with no provider is a recorded one
|
|
40
|
+
* (cheque, cash) and captures immediately; a provider that cannot be resolved is a configuration
|
|
41
|
+
* fault that the save path is about to report far more clearly than a status guess here would.
|
|
42
|
+
* Defaulting to the existing behaviour keeps every rail that worked before working unchanged.
|
|
43
|
+
*/
|
|
44
|
+
private settlesAsynchronously;
|
|
45
|
+
/**
|
|
46
|
+
* Read back what the engine computed.
|
|
47
|
+
*
|
|
48
|
+
* Every number here comes from the saved rows — the fee the driver decided, the rollups the
|
|
49
|
+
* triggers moved. Nothing is recalculated, because a second calculation is a second opinion, and
|
|
50
|
+
* the one that reaches the screen would not be the one in the ledger.
|
|
51
|
+
*/
|
|
52
|
+
private project;
|
|
53
|
+
/** The entries this payment's allocations produced, found through accounting's D25 provenance pair. */
|
|
54
|
+
private readEntries;
|
|
55
|
+
/** Gap-conscious payment numbering — the same sequence every other capture path uses. */
|
|
56
|
+
private nextPaymentNumber;
|
|
57
|
+
private blocker;
|
|
58
|
+
private refuse;
|
|
59
|
+
}
|
|
60
|
+
/** Tree-shaking anchor — call from the server bootstrap so @RegisterClass is retained. */
|
|
61
|
+
export declare function LoadCapturePaymentOperation(): void;
|
|
62
|
+
//# sourceMappingURL=CapturePaymentOperation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CapturePaymentOperation.d.ts","sourceRoot":"","sources":["../src/CapturePaymentOperation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAKH,KAAK,iBAAiB,EAEtB,KAAK,QAAQ,EAChB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACH,6BAA6B,IAAI,iCAAiC,EAOlE,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAClC,MAAM,8BAA8B,CAAC;AAiBtC,qBACa,uBAAwB,SAAQ,iCAAiC;cAC1D,eAAe,CAC3B,KAAK,EAAE,yBAAyB,EAChC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,0BAA0B,CAAC;IAmOtC;;;;;;;OAOG;YACW,YAAY;IA8F1B;;;;;;;;;;OAUG;YACW,qBAAqB;IAenC;;;;;;OAMG;YACW,OAAO;IAqErB,uGAAuG;YACzF,WAAW;IA8DzB,yFAAyF;YAC3E,iBAAiB;IAgB/B,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,MAAM;CAWjB;AAED,0FAA0F;AAC1F,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
|