@mj-biz-apps/orders-core-entities-server 5.27.0 → 5.29.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/dist/AccessOverrideOperations.d.ts +4 -5
- package/dist/AccessOverrideOperations.d.ts.map +1 -1
- package/dist/AccessOverrideOperations.js +3 -10
- package/dist/AccessOverrideOperations.js.map +1 -1
- package/dist/AdvanceOrderStateOperation.d.ts +3 -4
- package/dist/AdvanceOrderStateOperation.d.ts.map +1 -1
- package/dist/AdvanceOrderStateOperation.js +2 -6
- package/dist/AdvanceOrderStateOperation.js.map +1 -1
- package/dist/AmendArrangementOperation.d.ts +3 -3
- package/dist/AmendArrangementOperation.d.ts.map +1 -1
- package/dist/AmendArrangementOperation.js +2 -6
- package/dist/AmendArrangementOperation.js.map +1 -1
- package/dist/ApplyAccountCreditOperation.d.ts +3 -3
- package/dist/ApplyAccountCreditOperation.d.ts.map +1 -1
- package/dist/ApplyAccountCreditOperation.js +2 -6
- package/dist/ApplyAccountCreditOperation.js.map +1 -1
- package/dist/CancelSubscriptionOperation.d.ts +5 -6
- package/dist/CancelSubscriptionOperation.d.ts.map +1 -1
- package/dist/CancelSubscriptionOperation.js +14 -9
- package/dist/CancelSubscriptionOperation.js.map +1 -1
- package/dist/CheckCoverageOverlapOperation.d.ts +28 -0
- package/dist/CheckCoverageOverlapOperation.d.ts.map +1 -0
- package/dist/CheckCoverageOverlapOperation.js +70 -0
- package/dist/CheckCoverageOverlapOperation.js.map +1 -0
- package/dist/CheckEntitlementOperation.d.ts +3 -3
- package/dist/CheckEntitlementOperation.d.ts.map +1 -1
- package/dist/CheckEntitlementOperation.js +2 -5
- package/dist/CheckEntitlementOperation.js.map +1 -1
- package/dist/CheckoutMemberDiscountResolver.d.ts +22 -0
- package/dist/CheckoutMemberDiscountResolver.d.ts.map +1 -1
- package/dist/CheckoutMemberDiscountResolver.js +2 -0
- package/dist/CheckoutMemberDiscountResolver.js.map +1 -1
- package/dist/CheckoutSessionService.d.ts +16 -1
- package/dist/CheckoutSessionService.d.ts.map +1 -1
- package/dist/CheckoutSessionService.js +68 -12
- package/dist/CheckoutSessionService.js.map +1 -1
- package/dist/DetectOverlappingSubscriptionsOperation.d.ts +16 -6
- package/dist/DetectOverlappingSubscriptionsOperation.d.ts.map +1 -1
- package/dist/DetectOverlappingSubscriptionsOperation.js +19 -9
- package/dist/DetectOverlappingSubscriptionsOperation.js.map +1 -1
- package/dist/ListEntitlementsOperation.d.ts +3 -3
- package/dist/ListEntitlementsOperation.d.ts.map +1 -1
- package/dist/ListEntitlementsOperation.js +2 -5
- package/dist/ListEntitlementsOperation.js.map +1 -1
- package/dist/OrderEntityServer.d.ts +71 -3
- package/dist/OrderEntityServer.d.ts.map +1 -1
- package/dist/OrderEntityServer.js +262 -26
- package/dist/OrderEntityServer.js.map +1 -1
- package/dist/PreviewPriceOperation.d.ts +3 -3
- package/dist/PreviewPriceOperation.d.ts.map +1 -1
- package/dist/PreviewPriceOperation.js +2 -5
- package/dist/PreviewPriceOperation.js.map +1 -1
- package/dist/PriceOrderOperation.d.ts +3 -3
- package/dist/PriceOrderOperation.d.ts.map +1 -1
- package/dist/PriceOrderOperation.js +2 -5
- package/dist/PriceOrderOperation.js.map +1 -1
- package/dist/RefundPaymentOperation.d.ts +3 -3
- package/dist/RefundPaymentOperation.d.ts.map +1 -1
- package/dist/RefundPaymentOperation.js +2 -5
- package/dist/RefundPaymentOperation.js.map +1 -1
- package/dist/SpawnRenewalsOperation.d.ts +53 -4
- package/dist/SpawnRenewalsOperation.d.ts.map +1 -1
- package/dist/SpawnRenewalsOperation.js +211 -24
- package/dist/SpawnRenewalsOperation.js.map +1 -1
- package/dist/SubscriptionBehavior.d.ts +125 -0
- package/dist/SubscriptionBehavior.d.ts.map +1 -1
- package/dist/SubscriptionBehavior.js +147 -5
- package/dist/SubscriptionBehavior.js.map +1 -1
- package/dist/SubscriptionFamilyRules.d.ts +34 -0
- package/dist/SubscriptionFamilyRules.d.ts.map +1 -0
- package/dist/SubscriptionFamilyRules.js +96 -0
- package/dist/SubscriptionFamilyRules.js.map +1 -0
- package/dist/entity-names.d.ts +2 -0
- package/dist/entity-names.d.ts.map +1 -1
- package/dist/entity-names.js +2 -0
- package/dist/entity-names.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
|
@@ -0,0 +1,70 @@
|
|
|
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.CheckCoverageOverlap` — would confirming this draft create coverage that
|
|
9
|
+
* overlaps another band the holder already has (golive #276)?
|
|
10
|
+
*
|
|
11
|
+
* WHY THIS IS AN OPERATION AND NOT A CLIENT QUERY. Who a line's subscriber is (ship-to falling back
|
|
12
|
+
* to the header, an organization inferred from the person's affiliation), which axes define a
|
|
13
|
+
* duplicate (the type's BenefitModel), and what the term's dates will be (the type's start and end
|
|
14
|
+
* rules) are all decided on the server at confirm. A notice computed from its own queries would be
|
|
15
|
+
* a second copy of those rules, and it would disagree with the refusal the first time either
|
|
16
|
+
* changed. So the editor asks the same code confirm refuses with.
|
|
17
|
+
*
|
|
18
|
+
* READ-ONLY: it loads the order and runs the confirm-time decision pass in preview, which writes
|
|
19
|
+
* nothing.
|
|
20
|
+
*
|
|
21
|
+
* CONNECTS TO:
|
|
22
|
+
* CODE: OrderEntityServer.PreviewCoverageOverlaps, SubscriptionBehavior.DecideCoverageOverlap
|
|
23
|
+
* UI: the order lines editor's coverage notice
|
|
24
|
+
*
|
|
25
|
+
* @module @mj-biz-apps/orders-core-entities-server
|
|
26
|
+
*/
|
|
27
|
+
import { BaseRemotableOperation } from '@memberjunction/core';
|
|
28
|
+
import { RegisterClass } from '@memberjunction/global';
|
|
29
|
+
import { OrdersCheckCoverageOverlapOperation as OrdersCheckCoverageOverlapOperationBase, } from '@mj-biz-apps/orders-entities';
|
|
30
|
+
import { RequireUUID } from './sql-guards.js';
|
|
31
|
+
const ORDER_ENTITY = 'MJ_BizApps_Orders: Order Headers';
|
|
32
|
+
const day = (d) => d.toISOString().slice(0, 10);
|
|
33
|
+
let CheckCoverageOverlapOperation = class CheckCoverageOverlapOperation extends OrdersCheckCoverageOverlapOperationBase {
|
|
34
|
+
async InternalExecute(input, provider, user) {
|
|
35
|
+
const orderID = RequireUUID(input?.OrderHeaderID, 'OrderHeaderID');
|
|
36
|
+
const order = await provider.GetEntityObject(ORDER_ENTITY, user);
|
|
37
|
+
if (!(await order.Load(orderID))) {
|
|
38
|
+
throw new Error(`Order ${orderID} does not exist, so its coverage cannot be checked.`);
|
|
39
|
+
}
|
|
40
|
+
// A booked order has already created its subscriptions; there is nothing left to warn about.
|
|
41
|
+
if (order.Status !== 'Draft')
|
|
42
|
+
return { Lines: [] };
|
|
43
|
+
const found = await order.PreviewCoverageOverlaps();
|
|
44
|
+
return {
|
|
45
|
+
Lines: found
|
|
46
|
+
.filter((f) => f.Decision.Outcome !== 'None')
|
|
47
|
+
.map((f) => ({
|
|
48
|
+
OrderLineID: f.Line.ID,
|
|
49
|
+
Outcome: f.Decision.Outcome,
|
|
50
|
+
Message: f.Decision.Message ?? '',
|
|
51
|
+
Overlaps: f.Overlaps.map((o) => ({
|
|
52
|
+
SubscriptionID: o.SubscriptionID,
|
|
53
|
+
SubscriptionNumber: o.SubscriptionNumber,
|
|
54
|
+
ProductName: o.ProductName,
|
|
55
|
+
CoverageStart: day(o.CoverageStart),
|
|
56
|
+
CoverageEnd: day(o.CoverageEnd),
|
|
57
|
+
})),
|
|
58
|
+
})),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
CheckCoverageOverlapOperation = __decorate([
|
|
63
|
+
RegisterClass(BaseRemotableOperation, 'Orders.CheckCoverageOverlap')
|
|
64
|
+
], CheckCoverageOverlapOperation);
|
|
65
|
+
export { CheckCoverageOverlapOperation };
|
|
66
|
+
/** Tree-shaking anchor — call from the server bootstrap so @RegisterClass is retained. */
|
|
67
|
+
export function LoadCheckCoverageOverlapOperation() {
|
|
68
|
+
// intentionally empty
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=CheckCoverageOverlapOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CheckCoverageOverlapOperation.js","sourceRoot":"","sources":["../src/CheckCoverageOverlapOperation.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,sBAAsB,EAAyC,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACH,mCAAmC,IAAI,uCAAuC,GAGjF,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C,MAAM,YAAY,GAAG,kCAAkC,CAAC;AAExD,MAAM,GAAG,GAAG,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAG/C,IAAM,6BAA6B,GAAnC,MAAM,6BAA8B,SAAQ,uCAAuC;IAC5E,KAAK,CAAC,eAAe,CAC3B,KAAgC,EAChC,QAA2B,EAC3B,IAAc;QAEd,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,aAAa,EAAE,eAAe,CAAC,CAAC;QAEnE,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAoB,YAAY,EAAE,IAAI,CAAC,CAAC;QACpF,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,SAAS,OAAO,qDAAqD,CAAC,CAAC;QAC3F,CAAC;QACD,6FAA6F;QAC7F,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;QAEnD,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,uBAAuB,EAAE,CAAC;QACpD,OAAO;YACH,KAAK,EAAE,KAAK;iBACP,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,KAAK,MAAM,CAAC;iBAC5C,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACT,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE;gBACtB,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAiE;gBACrF,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE;gBACjC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC7B,cAAc,EAAE,CAAC,CAAC,cAAc;oBAChC,kBAAkB,EAAE,CAAC,CAAC,kBAAkB;oBACxC,WAAW,EAAE,CAAC,CAAC,WAAW;oBAC1B,aAAa,EAAE,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC;oBACnC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;iBAClC,CAAC,CAAC;aACN,CAAC,CAAC;SACV,CAAC;IACN,CAAC;CACJ,CAAA;AAjCY,6BAA6B;IADzC,aAAa,CAAC,sBAAsB,EAAE,6BAA6B,CAAC;GACxD,6BAA6B,CAiCzC;;AAED,0FAA0F;AAC1F,MAAM,UAAU,iCAAiC;IAC7C,sBAAsB;AAC1B,CAAC"}
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
* LOAD: ./EntitlementRead.ts
|
|
17
17
|
* DOC: plans/entitlement-read-contract.md
|
|
18
18
|
*/
|
|
19
|
-
import {
|
|
19
|
+
import { type IMetadataProvider, type UserInfo } from '@memberjunction/core';
|
|
20
|
+
import { OrdersCheckEntitlementOperation as OrdersCheckEntitlementOperationBase } from '@mj-biz-apps/orders-entities';
|
|
20
21
|
import { type CheckEntitlementInput, type CheckEntitlementOutput } from './EntitlementRead.js';
|
|
21
|
-
export declare class CheckEntitlementOperation extends
|
|
22
|
-
OperationKey: string;
|
|
22
|
+
export declare class CheckEntitlementOperation extends OrdersCheckEntitlementOperationBase {
|
|
23
23
|
protected InternalExecute(input: CheckEntitlementInput, provider: IMetadataProvider, user: UserInfo): Promise<CheckEntitlementOutput>;
|
|
24
24
|
}
|
|
25
25
|
/** Tree-shaking anchor — called from the server bootstrap so the registration is retained. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckEntitlementOperation.d.ts","sourceRoot":"","sources":["../src/CheckEntitlementOperation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"CheckEntitlementOperation.d.ts","sourceRoot":"","sources":["../src/CheckEntitlementOperation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAA0B,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErG,OAAO,EAAE,+BAA+B,IAAI,mCAAmC,EAAE,MAAM,8BAA8B,CAAC;AACtH,OAAO,EAEH,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC9B,MAAM,sBAAsB,CAAC;AAE9B,qBACa,yBAA0B,SAAQ,mCAAmC;cAC9D,eAAe,CAC3B,KAAK,EAAE,qBAAqB,EAC5B,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GACf,OAAO,CAAC,sBAAsB,CAAC;CAGrC;AAED,8FAA8F;AAC9F,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
|
|
@@ -24,12 +24,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
24
24
|
*/
|
|
25
25
|
import { BaseRemotableOperation } from '@memberjunction/core';
|
|
26
26
|
import { RegisterClass } from '@memberjunction/global';
|
|
27
|
+
import { OrdersCheckEntitlementOperation as OrdersCheckEntitlementOperationBase } from '@mj-biz-apps/orders-entities';
|
|
27
28
|
import { CheckPersonEntitlement, } from './EntitlementRead.js';
|
|
28
|
-
let CheckEntitlementOperation = class CheckEntitlementOperation extends
|
|
29
|
-
constructor() {
|
|
30
|
-
super(...arguments);
|
|
31
|
-
this.OperationKey = 'Orders.CheckEntitlement';
|
|
32
|
-
}
|
|
29
|
+
let CheckEntitlementOperation = class CheckEntitlementOperation extends OrdersCheckEntitlementOperationBase {
|
|
33
30
|
async InternalExecute(input, provider, user) {
|
|
34
31
|
return CheckPersonEntitlement(input, provider, user);
|
|
35
32
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckEntitlementOperation.js","sourceRoot":"","sources":["../src/CheckEntitlementOperation.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,sBAAsB,EAAyC,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EACH,sBAAsB,GAGzB,MAAM,sBAAsB,CAAC;AAGvB,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,
|
|
1
|
+
{"version":3,"file":"CheckEntitlementOperation.js","sourceRoot":"","sources":["../src/CheckEntitlementOperation.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,sBAAsB,EAAyC,MAAM,sBAAsB,CAAC;AACrG,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,+BAA+B,IAAI,mCAAmC,EAAE,MAAM,8BAA8B,CAAC;AACtH,OAAO,EACH,sBAAsB,GAGzB,MAAM,sBAAsB,CAAC;AAGvB,IAAM,yBAAyB,GAA/B,MAAM,yBAA0B,SAAQ,mCAAmC;IACpE,KAAK,CAAC,eAAe,CAC3B,KAA4B,EAC5B,QAA2B,EAC3B,IAAc;QAEd,OAAO,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACzD,CAAC;CACJ,CAAA;AARY,yBAAyB;IADrC,aAAa,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;GACpD,yBAAyB,CAQrC;;AAED,8FAA8F;AAC9F,MAAM,UAAU,6BAA6B;IACzC,KAAK,yBAAyB,CAAC;AACnC,CAAC"}
|
|
@@ -24,6 +24,10 @@
|
|
|
24
24
|
* enter it in a checkout's code field and get the member price without a token (#358). Before a typed
|
|
25
25
|
* code is priced, every registered resolver is asked `IsMemberPromotionCode`, and a code any of them
|
|
26
26
|
* claims is refused — on every widget, because promotion codes are not scoped to one.
|
|
27
|
+
*
|
|
28
|
+
* A MEMBER CODE AND A TYPED CODE DO NOT STACK unless the host says so. When a buyer with a verified
|
|
29
|
+
* token also types a code, the decision's `TypedCode` says which one is priced, or `'Stack'` to price
|
|
30
|
+
* both (#358); the default is the member code alone.
|
|
27
31
|
*/
|
|
28
32
|
import { IMetadataProvider, UserInfo } from '@memberjunction/core';
|
|
29
33
|
/** What a resolver is told about the checkout the token arrived with. */
|
|
@@ -43,12 +47,30 @@ export interface CheckoutTypedPromotionCodeContext {
|
|
|
43
47
|
CompanyID: string;
|
|
44
48
|
SessionID: string;
|
|
45
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Which code wins when a verified token earns a member code and the buyer also typed one.
|
|
52
|
+
* - `'Replace'` — the member code is priced and the typed code is reported as not used.
|
|
53
|
+
* - `'Yield'` — the typed code is priced and the member code is set aside.
|
|
54
|
+
* - `'Stack'` — both are priced together, and the promotions' own stacking settings decide whether
|
|
55
|
+
* both apply. Only a host that means its member discount to combine with other offers returns it.
|
|
56
|
+
*
|
|
57
|
+
* Under `'Replace'` and `'Yield'`, when the promotion engine declines the winning code, the other one
|
|
58
|
+
* is priced instead, so the buyer is never left at full price while a usable code is in play.
|
|
59
|
+
*/
|
|
60
|
+
export type CheckoutTypedCodePrecedence = 'Replace' | 'Yield' | 'Stack';
|
|
61
|
+
/** Used when a resolver's decision names no precedence. */
|
|
62
|
+
export declare const DEFAULT_TYPED_CODE_PRECEDENCE: CheckoutTypedCodePrecedence;
|
|
46
63
|
/** A resolver's verdict. */
|
|
47
64
|
export interface CheckoutMemberDiscountDecision {
|
|
48
65
|
/** The promotion code to price with, or null when the token earns no discount. */
|
|
49
66
|
PromotionCode: string | null;
|
|
50
67
|
/** Shown to the buyer when no discount applies — e.g. why the token was not accepted. */
|
|
51
68
|
Message?: string;
|
|
69
|
+
/**
|
|
70
|
+
* Whether `PromotionCode` replaces a code the buyer typed or yields to it. Defaults to
|
|
71
|
+
* {@link DEFAULT_TYPED_CODE_PRECEDENCE} (`'Replace'`). Ignored when no code was typed.
|
|
72
|
+
*/
|
|
73
|
+
TypedCode?: CheckoutTypedCodePrecedence;
|
|
52
74
|
}
|
|
53
75
|
/**
|
|
54
76
|
* Base class for a host's member-token verifier. Returning `{ PromotionCode: null }` prices the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckoutMemberDiscountResolver.d.ts","sourceRoot":"","sources":["../src/CheckoutMemberDiscountResolver.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CheckoutMemberDiscountResolver.d.ts","sourceRoot":"","sources":["../src/CheckoutMemberDiscountResolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnE,yEAAyE;AACzE,MAAM,WAAW,6BAA6B;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,iEAAiE;IACjE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,iFAAiF;AACjF,MAAM,WAAW,iCAAiC;IAC9C,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,2BAA2B,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAExE,2DAA2D;AAC3D,eAAO,MAAM,6BAA6B,EAAE,2BAAuC,CAAC;AAEpF,4BAA4B;AAC5B,MAAM,WAAW,8BAA8B;IAC3C,kFAAkF;IAClF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,2BAA2B,CAAC;CAC3C;AAED;;;;GAIG;AACH,8BAAsB,kCAAkC;aACpC,OAAO,CACnB,GAAG,EAAE,6BAA6B,EAClC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAC3B,OAAO,CAAC,8BAA8B,CAAC;IAE1C;;;;;;;OAOG;IACU,qBAAqB,CAC9B,IAAI,EAAE,iCAAiC,EACvC,SAAS,EAAE,iBAAiB,EAC5B,KAAK,EAAE,QAAQ,GAAG,SAAS,GAC5B,OAAO,CAAC,OAAO,CAAC;CAGtB;AAED;;;;GAIG;AACH,wBAAsB,+BAA+B,CACjD,GAAG,EAAE,iCAAiC,EACtC,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,QAAQ,GAAG,SAAS,GAC3B,OAAO,CAAC,OAAO,CAAC,CAoBlB;AAED,oEAAoE;AACpE,qBAAa,wCAAyC,SAAQ,KAAK;CAAG;AAEtE;;;;GAIG;AACH,wBAAgB,qCAAqC,CAAC,GAAG,EAAE,MAAM,GAAG,kCAAkC,CAcrG"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { MJGlobal } from '@memberjunction/global';
|
|
2
|
+
/** Used when a resolver's decision names no precedence. */
|
|
3
|
+
export const DEFAULT_TYPED_CODE_PRECEDENCE = 'Replace';
|
|
2
4
|
/**
|
|
3
5
|
* Base class for a host's member-token verifier. Returning `{ PromotionCode: null }` prices the
|
|
4
6
|
* checkout at full price; throwing is treated the same way, with a generic message, so a verifier
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckoutMemberDiscountResolver.js","sourceRoot":"","sources":["../src/CheckoutMemberDiscountResolver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CheckoutMemberDiscountResolver.js","sourceRoot":"","sources":["../src/CheckoutMemberDiscountResolver.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAiClD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,6BAA6B,GAAgC,SAAS,CAAC;AAepF;;;;GAIG;AACH,MAAM,OAAgB,kCAAkC;IAOpD;;;;;;;OAOG;IACI,KAAK,CAAC,qBAAqB,CAC9B,IAAuC,EACvC,SAA4B,EAC5B,KAA2B;QAE3B,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACjD,GAAsC,EACtC,QAA2B,EAC3B,IAA0B;IAE1B,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,mBAAmB,CAAC,kCAAkC,CAAC,CAAC;IAC7G,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACxH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CAC1D,kCAAkC,EAClC,GAAG,CACN,CAAC;QACF,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,kCAAkC,EAAE,CAAC;YAC3E,SAAS;QACb,CAAC;QACD,IAAI,CAAC;YACD,IAAI,MAAM,QAAQ,CAAC,qBAAqB,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC;gBAC5D,OAAO,IAAI,CAAC;YAChB,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACjB,CAAC;AAED,oEAAoE;AACpE,MAAM,OAAO,wCAAyC,SAAQ,KAAK;CAAG;AAEtE;;;;GAIG;AACH,MAAM,UAAU,qCAAqC,CAAC,GAAW;IAC7D,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,cAAc,CAC1D,kCAAkC,EAClC,GAAG,CACN,CAAC;IACF,kGAAkG;IAClG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,WAAW,KAAK,kCAAkC,EAAE,CAAC;QAC3E,MAAM,IAAI,wCAAwC,CAC9C,kDAAkD,GAAG,uBAAuB;YACxE,uDAAuD,GAAG,+BAA+B;YACzF,4DAA4D,CACnE,CAAC;IACN,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { UserInfo } from '@memberjunction/core';
|
|
11
11
|
import { type CheckoutWidgetConfiguration, type CheckoutAnswersInput, type CheckoutChoicesInput } from '@mj-biz-apps/orders-entities';
|
|
12
12
|
import { type CheckoutRefusal } from './CheckoutPrePurchaseCheck.js';
|
|
13
|
+
import { type CheckoutTypedCodePrecedence } from './CheckoutMemberDiscountResolver.js';
|
|
13
14
|
export interface InitSessionResult {
|
|
14
15
|
Success: boolean;
|
|
15
16
|
ErrorMessage?: string;
|
|
@@ -113,9 +114,23 @@ export declare function NormalizeCheckoutPromotionCodes(input: unknown): {
|
|
|
113
114
|
};
|
|
114
115
|
/**
|
|
115
116
|
* The codes a checkout prices with: the buyer's own codes plus the code a verified member token
|
|
116
|
-
* earned, de-duplicated case-insensitively.
|
|
117
|
+
* earned, de-duplicated case-insensitively. A draft snapshots both only when the resolver chose
|
|
118
|
+
* `'Stack'` (see {@link PlanCheckoutPromotionCodes}), so at `/complete` this usually passes one side
|
|
119
|
+
* through; a session drafted before that rule may still carry both, and is priced as it was drafted.
|
|
117
120
|
*/
|
|
118
121
|
export declare function CombineCheckoutPromotionCodes(buyerCodes: string[], memberCode: string | null | undefined): string[];
|
|
122
|
+
/** One set of codes to price a draft with: the buyer's typed codes and the member code. */
|
|
123
|
+
export interface CheckoutPromotionCodeAttempt {
|
|
124
|
+
Buyer: string[];
|
|
125
|
+
Member: string | null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The code sets a draft tries, in order, when a member code and a typed code may both be present (#358).
|
|
129
|
+
* They do not stack: the precedence picks which is priced first, and the other is the fallback when the
|
|
130
|
+
* engine declines every code in the first. `'Stack'` prices both in one attempt. With only one side
|
|
131
|
+
* present, or the same code on both, there is a single attempt.
|
|
132
|
+
*/
|
|
133
|
+
export declare function PlanCheckoutPromotionCodes(buyerCodes: string[], memberCode: string | null | undefined, precedence: CheckoutTypedCodePrecedence | undefined): CheckoutPromotionCodeAttempt[];
|
|
119
134
|
/** Outcome of booking CapturePayment after a checkout order is already confirmed. */
|
|
120
135
|
export interface BookCheckoutPaymentResult {
|
|
121
136
|
/** True when CapturePayment was invoked (or would have been, but a pre-check failed). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CheckoutSessionService.d.ts","sourceRoot":"","sources":["../src/CheckoutSessionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAA+E,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAU7H,OAAO,EAgBH,KAAK,2BAA2B,EAOhC,KAAK,oBAAoB,EASzB,KAAK,oBAAoB,EAC5B,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAwB,KAAK,eAAe,EAA2B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"CheckoutSessionService.d.ts","sourceRoot":"","sources":["../src/CheckoutSessionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ import { ResolvePersonByEmail } from './PersonByEmail.js';
|
|
|
20
20
|
import { OpenPaymentIntent, SUPPORTED_PAYMENT_CURRENCY } from './PaymentIntentService.js';
|
|
21
21
|
import { ResolvePaymentProvider } from './PaymentProviderResolver.js';
|
|
22
22
|
import { FindReusableProviderCustomerRef, SnapshotSellsSubscription, SaveCheckoutInstrumentForRenewals, } from './CheckoutSavedInstrument.js';
|
|
23
|
-
import { CheckoutMemberDiscountNotConfiguredError, IsRegisteredMemberPromotionCode, ResolveCheckoutMemberDiscountResolver, } from './CheckoutMemberDiscountResolver.js';
|
|
23
|
+
import { CheckoutMemberDiscountNotConfiguredError, DEFAULT_TYPED_CODE_PRECEDENCE, IsRegisteredMemberPromotionCode, ResolveCheckoutMemberDiscountResolver, } from './CheckoutMemberDiscountResolver.js';
|
|
24
24
|
import { CapturePaymentOperation } from './CapturePaymentOperation.js';
|
|
25
25
|
import { raiseCheckoutCaptureTerminalAlert, raiseCheckoutSettledNotBookedAlert } from './checkoutCaptureAlert.js';
|
|
26
26
|
import { CheckoutStepLog } from './CheckoutStepLog.js';
|
|
@@ -86,7 +86,9 @@ export function NormalizeCheckoutPromotionCodes(input) {
|
|
|
86
86
|
}
|
|
87
87
|
/**
|
|
88
88
|
* The codes a checkout prices with: the buyer's own codes plus the code a verified member token
|
|
89
|
-
* earned, de-duplicated case-insensitively.
|
|
89
|
+
* earned, de-duplicated case-insensitively. A draft snapshots both only when the resolver chose
|
|
90
|
+
* `'Stack'` (see {@link PlanCheckoutPromotionCodes}), so at `/complete` this usually passes one side
|
|
91
|
+
* through; a session drafted before that rule may still carry both, and is priced as it was drafted.
|
|
90
92
|
*/
|
|
91
93
|
export function CombineCheckoutPromotionCodes(buyerCodes, memberCode) {
|
|
92
94
|
if (!memberCode || buyerCodes.some((c) => c.toLowerCase() === memberCode.toLowerCase())) {
|
|
@@ -94,6 +96,26 @@ export function CombineCheckoutPromotionCodes(buyerCodes, memberCode) {
|
|
|
94
96
|
}
|
|
95
97
|
return [...buyerCodes, memberCode];
|
|
96
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* The code sets a draft tries, in order, when a member code and a typed code may both be present (#358).
|
|
101
|
+
* They do not stack: the precedence picks which is priced first, and the other is the fallback when the
|
|
102
|
+
* engine declines every code in the first. `'Stack'` prices both in one attempt. With only one side
|
|
103
|
+
* present, or the same code on both, there is a single attempt.
|
|
104
|
+
*/
|
|
105
|
+
export function PlanCheckoutPromotionCodes(buyerCodes, memberCode, precedence) {
|
|
106
|
+
const member = memberCode || null;
|
|
107
|
+
const contested = !!member && buyerCodes.some((c) => c.toLowerCase() !== member.toLowerCase());
|
|
108
|
+
if (!contested || precedence === 'Stack') {
|
|
109
|
+
return [{ Buyer: [...buyerCodes], Member: member }];
|
|
110
|
+
}
|
|
111
|
+
const memberOnly = { Buyer: [], Member: member };
|
|
112
|
+
const typedOnly = { Buyer: [...buyerCodes], Member: null };
|
|
113
|
+
return (precedence ?? DEFAULT_TYPED_CODE_PRECEDENCE) === 'Yield' ? [typedOnly, memberOnly] : [memberOnly, typedOnly];
|
|
114
|
+
}
|
|
115
|
+
/** Why a typed code did nothing when the member code replaced it. Shown as "<code> can't be used: <reason>." */
|
|
116
|
+
const TYPED_CODE_REPLACED_BY_MEMBER = 'your member discount applies instead, and the two cannot be combined';
|
|
117
|
+
/** Why a member code was set aside for the buyer's typed code. */
|
|
118
|
+
const MEMBER_CODE_YIELDED_TO_TYPED = 'Your member discount cannot be combined with a promotion code, so the code you entered is used instead.';
|
|
97
119
|
const MEMBER_DISCOUNT_UNAVAILABLE = 'Your member discount could not be verified, so this checkout is priced at the standard rate.';
|
|
98
120
|
/**
|
|
99
121
|
* Shown when the payment settled but the order, re-priced at completion, now costs more than was paid:
|
|
@@ -656,7 +678,10 @@ export class CheckoutSessionService {
|
|
|
656
678
|
}, md, contextUser);
|
|
657
679
|
const code = typeof decision?.PromotionCode === 'string' ? decision.PromotionCode.trim() : '';
|
|
658
680
|
if (code) {
|
|
659
|
-
|
|
681
|
+
// Anything but an explicit 'Yield' or 'Stack' takes the default, so a misspelt value
|
|
682
|
+
// cannot hand the price to a typed code the host meant to override.
|
|
683
|
+
const precedence = decision.TypedCode === 'Yield' || decision.TypedCode === 'Stack' ? decision.TypedCode : DEFAULT_TYPED_CODE_PRECEDENCE;
|
|
684
|
+
return { PromotionCode: code, TypedCode: precedence };
|
|
660
685
|
}
|
|
661
686
|
return { PromotionCode: null, Message: decision?.Message || MEMBER_DISCOUNT_UNAVAILABLE };
|
|
662
687
|
}
|
|
@@ -1032,7 +1057,7 @@ export class CheckoutSessionService {
|
|
|
1032
1057
|
});
|
|
1033
1058
|
// Nothing is saved yet, so the location is priced inline; completion prices the same
|
|
1034
1059
|
// location from the Address row it records.
|
|
1035
|
-
const
|
|
1060
|
+
const priceWith = async (codes) => pricingService.Price({
|
|
1036
1061
|
OrderHeaderID: order.ID || null,
|
|
1037
1062
|
CompanyID: widget.CompanyID,
|
|
1038
1063
|
BillToPersonID: order.BillToPersonID ?? null,
|
|
@@ -1049,23 +1074,54 @@ export class CheckoutSessionService {
|
|
|
1049
1074
|
ShipToAddressID: null,
|
|
1050
1075
|
ShipToAddress: this.toTaxAddress(location),
|
|
1051
1076
|
Lines: [...order.Lines.Items],
|
|
1052
|
-
PromotionCodes:
|
|
1077
|
+
PromotionCodes: codes,
|
|
1053
1078
|
ManualDiscounts: [],
|
|
1054
1079
|
Charges: [],
|
|
1055
1080
|
});
|
|
1056
|
-
//
|
|
1057
|
-
//
|
|
1058
|
-
|
|
1059
|
-
|
|
1081
|
+
// A member code and a typed code do not stack unless the resolver says 'Stack' (#358): the
|
|
1082
|
+
// resolver's precedence picks which is priced, and the other is priced only when the engine
|
|
1083
|
+
// declines the first.
|
|
1084
|
+
const attempts = PlanCheckoutPromotionCodes(promotionCodes, memberDiscount.PromotionCode, memberDiscount.TypedCode);
|
|
1085
|
+
// Every code the engine declined on any attempt, with its reason.
|
|
1086
|
+
const declinedCodes = new Map();
|
|
1087
|
+
let chosen = attempts[0];
|
|
1088
|
+
for (let i = 0; i < attempts.length; i++) {
|
|
1089
|
+
if (i > 0) {
|
|
1090
|
+
// The pricing walk keeps a discount a line already carries, so clear the previous
|
|
1091
|
+
// attempt's before re-pricing. Draft lines carry no other discount.
|
|
1092
|
+
for (const l of order.Lines.Items)
|
|
1093
|
+
l.DiscountAmount = 0;
|
|
1094
|
+
}
|
|
1095
|
+
chosen = attempts[i];
|
|
1096
|
+
const codes = CombineCheckoutPromotionCodes(chosen.Buyer, chosen.Member);
|
|
1097
|
+
const priced = await priceWith(codes);
|
|
1098
|
+
const declinedNow = new Set((priced?.UnusableCodes ?? []).map((u) => u.Code.toLowerCase()));
|
|
1099
|
+
for (const u of priced?.UnusableCodes ?? [])
|
|
1100
|
+
declinedCodes.set(u.Code.toLowerCase(), u);
|
|
1101
|
+
if (codes.some((c) => !declinedNow.has(c.toLowerCase())))
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
1104
|
+
// Only the buyer's own codes are reported as unusable; a declined or set-aside member code
|
|
1105
|
+
// is explained through MemberDiscountMessage below.
|
|
1106
|
+
const pricedBuyerKeys = new Set(chosen.Buyer.map((c) => c.toLowerCase()));
|
|
1107
|
+
unusableCodes = promotionCodes.flatMap((c) => {
|
|
1108
|
+
const declined = declinedCodes.get(c.toLowerCase());
|
|
1109
|
+
if (declined)
|
|
1110
|
+
return [declined];
|
|
1111
|
+
return pricedBuyerKeys.has(c.toLowerCase()) ? [] : [{ Code: c, Reason: TYPED_CODE_REPLACED_BY_MEMBER }];
|
|
1112
|
+
});
|
|
1060
1113
|
// The engine may still decline the code (dates, limits, qualifier). Price at full rate
|
|
1061
1114
|
// and say why, rather than snapshotting a code `/complete` would also decline.
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
: undefined;
|
|
1115
|
+
const memberCode = memberDiscount.PromotionCode;
|
|
1116
|
+
const declined = memberCode ? declinedCodes.get(memberCode.toLowerCase()) : undefined;
|
|
1065
1117
|
if (declined) {
|
|
1066
1118
|
memberDiscount.PromotionCode = null;
|
|
1067
1119
|
memberDiscount.Message = `Your member discount does not apply to this order: ${declined.Reason}.`;
|
|
1068
1120
|
}
|
|
1121
|
+
else if (memberCode && !chosen.Member) {
|
|
1122
|
+
memberDiscount.PromotionCode = null;
|
|
1123
|
+
memberDiscount.Message = MEMBER_CODE_YIELDED_TO_TYPED;
|
|
1124
|
+
}
|
|
1069
1125
|
await this.settleLineTotals(order);
|
|
1070
1126
|
order.TotalGross = this.sumLineTotals(order.Lines.Items);
|
|
1071
1127
|
}
|