@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.
Files changed (81) hide show
  1. package/dist/AccessOverrideOperations.d.ts +4 -5
  2. package/dist/AccessOverrideOperations.d.ts.map +1 -1
  3. package/dist/AccessOverrideOperations.js +3 -10
  4. package/dist/AccessOverrideOperations.js.map +1 -1
  5. package/dist/AdvanceOrderStateOperation.d.ts +3 -4
  6. package/dist/AdvanceOrderStateOperation.d.ts.map +1 -1
  7. package/dist/AdvanceOrderStateOperation.js +2 -6
  8. package/dist/AdvanceOrderStateOperation.js.map +1 -1
  9. package/dist/AmendArrangementOperation.d.ts +3 -3
  10. package/dist/AmendArrangementOperation.d.ts.map +1 -1
  11. package/dist/AmendArrangementOperation.js +2 -6
  12. package/dist/AmendArrangementOperation.js.map +1 -1
  13. package/dist/ApplyAccountCreditOperation.d.ts +3 -3
  14. package/dist/ApplyAccountCreditOperation.d.ts.map +1 -1
  15. package/dist/ApplyAccountCreditOperation.js +2 -6
  16. package/dist/ApplyAccountCreditOperation.js.map +1 -1
  17. package/dist/CancelSubscriptionOperation.d.ts +5 -6
  18. package/dist/CancelSubscriptionOperation.d.ts.map +1 -1
  19. package/dist/CancelSubscriptionOperation.js +14 -9
  20. package/dist/CancelSubscriptionOperation.js.map +1 -1
  21. package/dist/CheckCoverageOverlapOperation.d.ts +28 -0
  22. package/dist/CheckCoverageOverlapOperation.d.ts.map +1 -0
  23. package/dist/CheckCoverageOverlapOperation.js +70 -0
  24. package/dist/CheckCoverageOverlapOperation.js.map +1 -0
  25. package/dist/CheckEntitlementOperation.d.ts +3 -3
  26. package/dist/CheckEntitlementOperation.d.ts.map +1 -1
  27. package/dist/CheckEntitlementOperation.js +2 -5
  28. package/dist/CheckEntitlementOperation.js.map +1 -1
  29. package/dist/CheckoutMemberDiscountResolver.d.ts +22 -0
  30. package/dist/CheckoutMemberDiscountResolver.d.ts.map +1 -1
  31. package/dist/CheckoutMemberDiscountResolver.js +2 -0
  32. package/dist/CheckoutMemberDiscountResolver.js.map +1 -1
  33. package/dist/CheckoutSessionService.d.ts +16 -1
  34. package/dist/CheckoutSessionService.d.ts.map +1 -1
  35. package/dist/CheckoutSessionService.js +68 -12
  36. package/dist/CheckoutSessionService.js.map +1 -1
  37. package/dist/DetectOverlappingSubscriptionsOperation.d.ts +16 -6
  38. package/dist/DetectOverlappingSubscriptionsOperation.d.ts.map +1 -1
  39. package/dist/DetectOverlappingSubscriptionsOperation.js +19 -9
  40. package/dist/DetectOverlappingSubscriptionsOperation.js.map +1 -1
  41. package/dist/ListEntitlementsOperation.d.ts +3 -3
  42. package/dist/ListEntitlementsOperation.d.ts.map +1 -1
  43. package/dist/ListEntitlementsOperation.js +2 -5
  44. package/dist/ListEntitlementsOperation.js.map +1 -1
  45. package/dist/OrderEntityServer.d.ts +71 -3
  46. package/dist/OrderEntityServer.d.ts.map +1 -1
  47. package/dist/OrderEntityServer.js +262 -26
  48. package/dist/OrderEntityServer.js.map +1 -1
  49. package/dist/PreviewPriceOperation.d.ts +3 -3
  50. package/dist/PreviewPriceOperation.d.ts.map +1 -1
  51. package/dist/PreviewPriceOperation.js +2 -5
  52. package/dist/PreviewPriceOperation.js.map +1 -1
  53. package/dist/PriceOrderOperation.d.ts +3 -3
  54. package/dist/PriceOrderOperation.d.ts.map +1 -1
  55. package/dist/PriceOrderOperation.js +2 -5
  56. package/dist/PriceOrderOperation.js.map +1 -1
  57. package/dist/RefundPaymentOperation.d.ts +3 -3
  58. package/dist/RefundPaymentOperation.d.ts.map +1 -1
  59. package/dist/RefundPaymentOperation.js +2 -5
  60. package/dist/RefundPaymentOperation.js.map +1 -1
  61. package/dist/SpawnRenewalsOperation.d.ts +53 -4
  62. package/dist/SpawnRenewalsOperation.d.ts.map +1 -1
  63. package/dist/SpawnRenewalsOperation.js +211 -24
  64. package/dist/SpawnRenewalsOperation.js.map +1 -1
  65. package/dist/SubscriptionBehavior.d.ts +125 -0
  66. package/dist/SubscriptionBehavior.d.ts.map +1 -1
  67. package/dist/SubscriptionBehavior.js +147 -5
  68. package/dist/SubscriptionBehavior.js.map +1 -1
  69. package/dist/SubscriptionFamilyRules.d.ts +34 -0
  70. package/dist/SubscriptionFamilyRules.d.ts.map +1 -0
  71. package/dist/SubscriptionFamilyRules.js +96 -0
  72. package/dist/SubscriptionFamilyRules.js.map +1 -0
  73. package/dist/entity-names.d.ts +2 -0
  74. package/dist/entity-names.d.ts.map +1 -1
  75. package/dist/entity-names.js +2 -0
  76. package/dist/entity-names.js.map +1 -1
  77. package/dist/index.d.ts +4 -2
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +3 -1
  80. package/dist/index.js.map +1 -1
  81. 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 { BaseRemotableOperation, type IMetadataProvider, type UserInfo } from '@memberjunction/core';
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 BaseRemotableOperation<CheckEntitlementInput, CheckEntitlementOutput> {
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,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErG,OAAO,EAEH,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC9B,MAAM,sBAAsB,CAAC;AAE9B,qBACa,yBAA0B,SAAQ,sBAAsB,CACjE,qBAAqB,EACrB,sBAAsB,CACzB;IACU,YAAY,SAA6B;cAEhC,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"}
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 BaseRemotableOperation {
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,sBAG9C;IAHM;;QAII,iBAAY,GAAG,yBAAyB,CAAC;IASpD,CAAC;IAPa,KAAK,CAAC,eAAe,CAC3B,KAA4B,EAC5B,QAA2B,EAC3B,IAAc;QAEd,OAAO,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACzD,CAAC;CACJ,CAAA;AAbY,yBAAyB;IADrC,aAAa,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;GACpD,yBAAyB,CAarC;;AAED,8FAA8F;AAC9F,MAAM,UAAU,6BAA6B;IACzC,KAAK,yBAAyB,CAAC;AACnC,CAAC"}
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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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,4BAA4B;AAC5B,MAAM,WAAW,8BAA8B;IAC3C,kFAAkF;IAClF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;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
+ {"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":"AA4BA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AA6BlD;;;;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"}
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. Whether they stack is the promotion engine's call.
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;AAmDpH,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,aAAa,CAAC,EAAE,2BAA2B,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GAAG,qBAAqB,CAAC;AAElD,MAAM,WAAW,yBAAyB;IACtC,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,kFAAkF;IAClF,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,yBAAyB,CAAC;IAC1C,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,kCAAkC;IAClC,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,0CAA0C;IAC1C,SAAS,CAAC,EAAE,qBAAqB,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,WAAW,2BAA2B;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAkBD,MAAM,WAAW,mBAAmB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,mGAAmG;IACnG,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,wEAAwE;IACxE,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,sGAAsG;IACtG,sBAAsB,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,2FAA2F;IAC3F,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAClC;AAUD,6FAA6F;AAC7F,eAAO,MAAM,gCAAgC,IAAI,CAAC;AAIlD;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAmBvG;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAKnH;AAkBD,qFAAqF;AACrF,MAAM,WAAW,yBAAyB;IACtC,yFAAyF;IACzF,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sGAAsG;IACtG,OAAO,CAAC,EAAE,eAAe,CAAC;CAC7B;AAED,qBAAa,sBAAsB;IAC/B;;OAEG;WACiB,iBAAiB,CACjC,IAAI,EAAE,MAAM,EACZ,gBAAgB,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,iBAAiB,CAAC;IAmG7B;;;;;;OAMG;IACH;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CA0B9C;IAEH,OAAO,CAAC,MAAM,CAAC,8BAA8B;IAU7C,OAAO,CAAC,MAAM,CAAC,QAAQ;IAOvB;;;;;OAKG;mBACkB,wBAAwB;IAwB7C,2EAA2E;WACvD,uBAAuB,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAmChG;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAarC;;;;OAIG;mBACkB,oBAAoB;IAczC;;OAEG;IACH;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,4BAA4B;mBAwCtB,uBAAuB;IAgH5C;;;;;OAKG;mBACkB,qBAAqB;IAqE1C,+EAA+E;IAC/E,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAQhC;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAuBlC,0FAA0F;IAC1F,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAI/B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IAuBlC;;OAEG;IACH;;;;;OAKG;mBACkB,qBAAqB;IAoD1C;;;;OAIG;mBACkB,gBAAgB;mBAShB,eAAe;IAepC;;OAEG;mBACkB,oBAAoB;IAyEzC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,mBAAmB;IA2BlC;;;;;;;OAOG;WACiB,WAAW,CAC3B,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,iBAAiB,EAAE,EAC1B,cAAc,EAAE,2BAA2B,GAAG,IAAI,GAAG,SAAS,EAC9D,WAAW,CAAC,EAAE,QAAQ,EACtB,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GACpJ,OAAO,CAAC,iBAAiB,CAAC;IA0Z7B;;;;;;;;;OASG;WACiB,2BAA2B,CAC3C,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,QAAQ,EACtB,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzC,OAAO,CAAC,8BAA8B,CAAC;IA8J1C,oFAAoF;mBAC/D,sBAAsB;IAqB3C;;;;;;OAMG;mBACkB,yBAAyB;IA6C9C;;;OAGG;mBACkB,SAAS;IAK9B;;;;OAIG;WACiB,gBAAgB,CAChC,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,QAAQ,GACvB,OAAO,CAAC,sBAAsB,CAAC;IA6clC,wFAAwF;IACxF,OAAO,CAAC,MAAM,CAAC,YAAY;IAU3B,sGAAsG;IACtG,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAKtC,OAAO,CAAC,MAAM,CAAC,YAAY;IAS3B;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAQ5B,OAAO,CAAC,MAAM,CAAC,UAAU;IAKzB;;;;;;;OAOG;mBACkB,oBAAoB;mBAkBpB,kBAAkB;IA8BvC;;;;;OAKG;mBACkB,oBAAoB;IAiCzC;;;;;;;;;;;OAWG;WACiB,kCAAkC,CAClD,eAAe,EAAE,MAAM,EACvB,WAAW,EAAE,QAAQ,GACtB,OAAO,CAAC,yBAAyB,CAAC;IA8BrC;;;;OAIG;WACiB,aAAa,CAC7B,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,QAAQ,EACrB,gBAAgB,EAAE,MAAM,GACzB,OAAO,CAAC,yBAAyB,GAAG,MAAM,CAAC;IAgB9C;;;;;;;OAOG;mBACkB,0BAA0B;mBAqI1B,aAAa;IAqBlC;;;OAGG;mBACkB,wBAAwB;IAkC7C;;;OAGG;mBACkB,2BAA2B;IA2BhD;;;OAGG;mBACkB,4BAA4B;IA0BjD;;OAEG;mBACkB,uBAAuB;CA0B/C"}
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. Whether they stack is the promotion engine's call.
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
- return { PromotionCode: code };
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 priced = await pricingService.Price({
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: CombineCheckoutPromotionCodes(promotionCodes, memberDiscount.PromotionCode),
1077
+ PromotionCodes: codes,
1053
1078
  ManualDiscounts: [],
1054
1079
  Charges: [],
1055
1080
  });
1056
- // Only the buyer's own codes are reported as unusable; a declined member code is explained
1057
- // through MemberDiscountMessage below.
1058
- const buyerKeys = new Set(promotionCodes.map((c) => c.toLowerCase()));
1059
- unusableCodes = (priced?.UnusableCodes ?? []).filter((u) => buyerKeys.has(u.Code.toLowerCase()));
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 declined = memberDiscount.PromotionCode
1063
- ? (priced?.UnusableCodes ?? []).find((u) => u.Code.toLowerCase() === memberDiscount.PromotionCode.toLowerCase())
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
  }