@mj-biz-apps/orders-core-entities-server 5.22.0 → 5.23.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 (129) hide show
  1. package/dist/AccountingBridge.d.ts +9 -1
  2. package/dist/AccountingBridge.d.ts.map +1 -1
  3. package/dist/AccountingBridge.js +5 -3
  4. package/dist/AccountingBridge.js.map +1 -1
  5. package/dist/AmendArrangementOperation.d.ts +78 -0
  6. package/dist/AmendArrangementOperation.d.ts.map +1 -0
  7. package/dist/AmendArrangementOperation.js +187 -0
  8. package/dist/AmendArrangementOperation.js.map +1 -0
  9. package/dist/BasePaymentProvider.d.ts +21 -0
  10. package/dist/BasePaymentProvider.d.ts.map +1 -1
  11. package/dist/BasePaymentProvider.js +4 -0
  12. package/dist/BasePaymentProvider.js.map +1 -1
  13. package/dist/BundleEngine.d.ts +7 -1
  14. package/dist/BundleEngine.d.ts.map +1 -1
  15. package/dist/BundleEngine.js +1 -0
  16. package/dist/BundleEngine.js.map +1 -1
  17. package/dist/CheckoutSessionService.d.ts +16 -1
  18. package/dist/CheckoutSessionService.d.ts.map +1 -1
  19. package/dist/CheckoutSessionService.js +141 -17
  20. package/dist/CheckoutSessionService.js.map +1 -1
  21. package/dist/CheckoutStepLog.d.ts +61 -0
  22. package/dist/CheckoutStepLog.d.ts.map +1 -0
  23. package/dist/CheckoutStepLog.js +143 -0
  24. package/dist/CheckoutStepLog.js.map +1 -0
  25. package/dist/ConcessionApprovalListener.d.ts +17 -0
  26. package/dist/ConcessionApprovalListener.d.ts.map +1 -0
  27. package/dist/ConcessionApprovalListener.js +113 -0
  28. package/dist/ConcessionApprovalListener.js.map +1 -0
  29. package/dist/ConcessionApprovalTask.d.ts +139 -0
  30. package/dist/ConcessionApprovalTask.d.ts.map +1 -0
  31. package/dist/ConcessionApprovalTask.js +467 -0
  32. package/dist/ConcessionApprovalTask.js.map +1 -0
  33. package/dist/ConcessionGate.d.ts +122 -0
  34. package/dist/ConcessionGate.d.ts.map +1 -0
  35. package/dist/ConcessionGate.js +317 -0
  36. package/dist/ConcessionGate.js.map +1 -0
  37. package/dist/DeliveryBehavior.d.ts +6 -1
  38. package/dist/DeliveryBehavior.d.ts.map +1 -1
  39. package/dist/DeliveryBehavior.js +8 -0
  40. package/dist/DeliveryBehavior.js.map +1 -1
  41. package/dist/DetectOverlappingSubscriptionsOperation.d.ts +84 -0
  42. package/dist/DetectOverlappingSubscriptionsOperation.d.ts.map +1 -0
  43. package/dist/DetectOverlappingSubscriptionsOperation.js +237 -0
  44. package/dist/DetectOverlappingSubscriptionsOperation.js.map +1 -0
  45. package/dist/EntitlementBehavior.d.ts +17 -0
  46. package/dist/EntitlementBehavior.d.ts.map +1 -1
  47. package/dist/EntitlementBehavior.js +13 -0
  48. package/dist/EntitlementBehavior.js.map +1 -1
  49. package/dist/EntitlementEngine.d.ts +7 -1
  50. package/dist/EntitlementEngine.d.ts.map +1 -1
  51. package/dist/EntitlementEngine.js +42 -1
  52. package/dist/EntitlementEngine.js.map +1 -1
  53. package/dist/EntitlementGrantEntityServer.d.ts +24 -0
  54. package/dist/EntitlementGrantEntityServer.d.ts.map +1 -0
  55. package/dist/EntitlementGrantEntityServer.js +114 -0
  56. package/dist/EntitlementGrantEntityServer.js.map +1 -0
  57. package/dist/IntentDescription.d.ts +46 -0
  58. package/dist/IntentDescription.d.ts.map +1 -0
  59. package/dist/IntentDescription.js +137 -0
  60. package/dist/IntentDescription.js.map +1 -0
  61. package/dist/OrderConcessionEntityServer.d.ts +93 -0
  62. package/dist/OrderConcessionEntityServer.d.ts.map +1 -0
  63. package/dist/OrderConcessionEntityServer.js +477 -0
  64. package/dist/OrderConcessionEntityServer.js.map +1 -0
  65. package/dist/OrderEntityServer.d.ts +21 -0
  66. package/dist/OrderEntityServer.d.ts.map +1 -1
  67. package/dist/OrderEntityServer.js +131 -1
  68. package/dist/OrderEntityServer.js.map +1 -1
  69. package/dist/OrderLineEntityServer.d.ts +19 -0
  70. package/dist/OrderLineEntityServer.d.ts.map +1 -1
  71. package/dist/OrderLineEntityServer.js +29 -0
  72. package/dist/OrderLineEntityServer.js.map +1 -1
  73. package/dist/OrdersSettings.d.ts +9 -0
  74. package/dist/OrdersSettings.d.ts.map +1 -1
  75. package/dist/OrdersSettings.js +12 -0
  76. package/dist/OrdersSettings.js.map +1 -1
  77. package/dist/OutboundEvents.d.ts +116 -0
  78. package/dist/OutboundEvents.d.ts.map +1 -0
  79. package/dist/OutboundEvents.js +273 -0
  80. package/dist/OutboundEvents.js.map +1 -0
  81. package/dist/PaymentIntentService.d.ts +5 -0
  82. package/dist/PaymentIntentService.d.ts.map +1 -1
  83. package/dist/PaymentIntentService.js +3 -0
  84. package/dist/PaymentIntentService.js.map +1 -1
  85. package/dist/PaymentTermsChange.d.ts +33 -0
  86. package/dist/PaymentTermsChange.d.ts.map +1 -0
  87. package/dist/PaymentTermsChange.js +129 -0
  88. package/dist/PaymentTermsChange.js.map +1 -0
  89. package/dist/PaymentTermsSanction.d.ts +5 -0
  90. package/dist/PaymentTermsSanction.d.ts.map +1 -0
  91. package/dist/PaymentTermsSanction.js +21 -0
  92. package/dist/PaymentTermsSanction.js.map +1 -0
  93. package/dist/PriceBelowEngineExceptions.d.ts +57 -0
  94. package/dist/PriceBelowEngineExceptions.d.ts.map +1 -0
  95. package/dist/PriceBelowEngineExceptions.js +85 -0
  96. package/dist/PriceBelowEngineExceptions.js.map +1 -0
  97. package/dist/ReplayCheckoutStepOperation.d.ts +28 -0
  98. package/dist/ReplayCheckoutStepOperation.d.ts.map +1 -0
  99. package/dist/ReplayCheckoutStepOperation.js +97 -0
  100. package/dist/ReplayCheckoutStepOperation.js.map +1 -0
  101. package/dist/SpawnRenewalsOperation.d.ts +2 -0
  102. package/dist/SpawnRenewalsOperation.d.ts.map +1 -1
  103. package/dist/SpawnRenewalsOperation.js +24 -0
  104. package/dist/SpawnRenewalsOperation.js.map +1 -1
  105. package/dist/StripePaymentProvider.d.ts +2 -1
  106. package/dist/StripePaymentProvider.d.ts.map +1 -1
  107. package/dist/StripePaymentProvider.js +16 -0
  108. package/dist/StripePaymentProvider.js.map +1 -1
  109. package/dist/SubscriptionTermEntityServer.d.ts +25 -0
  110. package/dist/SubscriptionTermEntityServer.d.ts.map +1 -0
  111. package/dist/SubscriptionTermEntityServer.js +46 -0
  112. package/dist/SubscriptionTermEntityServer.js.map +1 -0
  113. package/dist/TermExtension.d.ts +52 -0
  114. package/dist/TermExtension.d.ts.map +1 -0
  115. package/dist/TermExtension.js +442 -0
  116. package/dist/TermExtension.js.map +1 -0
  117. package/dist/TermExtensionPlan.d.ts +101 -0
  118. package/dist/TermExtensionPlan.d.ts.map +1 -0
  119. package/dist/TermExtensionPlan.js +109 -0
  120. package/dist/TermExtensionPlan.js.map +1 -0
  121. package/dist/entity-names.d.ts +4 -0
  122. package/dist/entity-names.d.ts.map +1 -1
  123. package/dist/entity-names.js +4 -0
  124. package/dist/entity-names.js.map +1 -1
  125. package/dist/index.d.ts +19 -1
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +16 -0
  128. package/dist/index.js.map +1 -1
  129. package/package.json +18 -23
@@ -1 +1 @@
1
- {"version":3,"file":"CheckoutSessionService.d.ts","sourceRoot":"","sources":["../src/CheckoutSessionService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CheckoutSessionService.d.ts","sourceRoot":"","sources":["../src/CheckoutSessionService.ts"],"names":[],"mappings":"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"}
@@ -13,13 +13,15 @@ import { BusinessTimeZoneEngine } from '@mj-biz-apps/common-entities';
13
13
  // '@memberjunction/core-entities-server' once MJ publishes the engine.
14
14
  import { CalendarDayOrToday } from './calendar-day.js';
15
15
  import { IdentityClaimEngineServer } from './identityClaimContracts.js';
16
- import { LoadOrdersEngine, OrderPricingService, OrdersEngine, TodayAsDateValue, CheckAnswersAgainstQuestions, CheckCheckoutAnswers, ReadCheckoutQuestions, NormalizeCheckoutAttribution } from '@mj-biz-apps/orders-entities';
16
+ import { LoadOrdersEngine, OrderPricingService, OrdersEngine, TodayAsDateValue, CheckAnswersAgainstQuestions, CheckCheckoutAnswers, ReadCheckoutQuestions, NormalizeCheckoutAttribution, CheckCheckoutChoices, ChoicesForStorage, ReadCheckoutChoiceGroups, CheckChoicesAgainstGroups } from '@mj-biz-apps/orders-entities';
17
17
  import { EscapeText } from './sql-guards.js';
18
18
  import { OpenPaymentIntent } from './PaymentIntentService.js';
19
19
  import { ResolvePaymentProvider } from './PaymentProviderResolver.js';
20
20
  import { CapturePaymentOperation } from './CapturePaymentOperation.js';
21
21
  import { raiseCheckoutCaptureTerminalAlert } from './checkoutCaptureAlert.js';
22
+ import { CheckoutStepLog } from './CheckoutStepLog.js';
22
23
  import { isCaptureRefusalRetryable, isTerminalCapturePrecheck, } from './checkoutCaptureRetry.js';
24
+ import { DescribeCheckoutSnapshot, SendOrderDescriptionToGateway } from './IntentDescription.js';
23
25
  const CHECKOUT_WIDGET_ENTITY = 'MJ_BizApps_Orders: Checkout Widgets';
24
26
  const CHECKOUT_DISTRIBUTION_ENTITY = 'MJ_BizApps_Orders: Checkout Widget Distributions';
25
27
  const CHECKOUT_SESSION_ENTITY = 'MJ_BizApps_Orders: Checkout Sessions';
@@ -166,6 +168,7 @@ export class CheckoutSessionService {
166
168
  'theme',
167
169
  'allowCoupons',
168
170
  'questions',
171
+ 'choiceGroups',
169
172
  ]); }
170
173
  static sanitizeConfigurationForClient(configObj) {
171
174
  const sanitized = {};
@@ -513,6 +516,36 @@ export class CheckoutSessionService {
513
516
  }
514
517
  return CheckCheckoutAnswers(questions, stored);
515
518
  }
519
+ /** Whether a line can hold Order Line Choices. An extension-type line (IS-A) does not. */
520
+ static canRecordChoices(line) {
521
+ return !!line.Choices;
522
+ }
523
+ /**
524
+ * The session's stored choices, checked in full against the widget's CURRENT choice groups:
525
+ * every group within its min and max, every option one of the group's. Run where money moves
526
+ * or the order books.
527
+ */
528
+ static checkSessionChoices(widget, session) {
529
+ let groups;
530
+ if (widget.Configuration) {
531
+ try {
532
+ groups = JSON.parse(widget.Configuration).choiceGroups;
533
+ }
534
+ catch {
535
+ return { Choices: [], Error: 'Invalid widget configuration' };
536
+ }
537
+ }
538
+ let stored;
539
+ if (session.MetadataJSON) {
540
+ try {
541
+ stored = JSON.parse(session.MetadataJSON).Choices;
542
+ }
543
+ catch {
544
+ stored = undefined;
545
+ }
546
+ }
547
+ return CheckCheckoutChoices(groups, stored);
548
+ }
516
549
  /**
517
550
  * Creates an order line entity instance attached to the order's Lines collection.
518
551
  */
@@ -678,6 +711,20 @@ export class CheckoutSessionService {
678
711
  if (draftAnswers.Error) {
679
712
  return failed(draftAnswers.Error);
680
713
  }
714
+ // Choices likewise: a draft may hold fewer than a group's minimum, never more than its
715
+ // maximum or an option it does not offer. The choice is the buyer's for the one item the
716
+ // widget sells, so a widget with choice groups takes a single line.
717
+ const choiceGroups = ReadCheckoutChoiceGroups(widgetConfig.choiceGroups);
718
+ if (choiceGroups.Error) {
719
+ return failed(choiceGroups.Error);
720
+ }
721
+ if (choiceGroups.Groups.length > 0 && Array.isArray(lines) && lines.length > 1) {
722
+ return failed('This checkout sells one item at a time.');
723
+ }
724
+ const draftChoices = CheckChoicesAgainstGroups(choiceGroups.Groups, options?.Choices, { partial: true });
725
+ if (draftChoices.Error) {
726
+ return failed(draftChoices.Error);
727
+ }
681
728
  const allowedProductIds = await this.resolveAllowedProductIds(widgetConfig, contextUser);
682
729
  const allowAnyProduct = widgetConfig.allowAnyProduct === true;
683
730
  if (!allowAnyProduct && allowedProductIds.size === 0) {
@@ -794,6 +841,12 @@ export class CheckoutSessionService {
794
841
  }
795
842
  }
796
843
  }
844
+ // A choice is recorded on the order line itself. A line of an extension type (an event
845
+ // line) has no collection for it, so refuse here, before the buyer pays, rather than at
846
+ // completion.
847
+ if (choiceGroups.Groups.length > 0 && order.Lines.Items.some((l) => !CheckoutSessionService.canRecordChoices(l))) {
848
+ return failed('This checkout is not configured correctly (its choices cannot be recorded on this item).');
849
+ }
797
850
  // Price the draft order in memory
798
851
  try {
799
852
  const pricingService = new OrderPricingService({
@@ -876,6 +929,7 @@ export class CheckoutSessionService {
876
929
  TotalGross: order.TotalGross,
877
930
  Answers: this.answersForStorage(draftAnswers.Answers),
878
931
  ...(attribution ? { Attribution: attribution } : {}),
932
+ Choices: ChoicesForStorage(draftChoices.Choices),
879
933
  UpdatedAt: new Date().toISOString()
880
934
  });
881
935
  const sessionSaved = await session.Save();
@@ -952,6 +1006,10 @@ export class CheckoutSessionService {
952
1006
  if (answersCheck.Error) {
953
1007
  return failed(answersCheck.Error);
954
1008
  }
1009
+ const choicesCheck = this.checkSessionChoices(widget, session);
1010
+ if (choicesCheck.Error) {
1011
+ return failed(choicesCheck.Error);
1012
+ }
955
1013
  let paymentProviderId;
956
1014
  let currencyCode;
957
1015
  if (widget.Configuration) {
@@ -971,6 +1029,8 @@ export class CheckoutSessionService {
971
1029
  if (!mdProvider) {
972
1030
  return failed('No metadata provider is available to open a payment intent.');
973
1031
  }
1032
+ // Products only: the order, and so its number, does not exist until completion.
1033
+ const description = await DescribeCheckoutSnapshot(session.MetadataJSON, mdProvider, contextUser);
974
1034
  const openResult = await OpenPaymentIntent({
975
1035
  PaymentProviderID: paymentProviderId,
976
1036
  Amount: snapshotTotal,
@@ -979,7 +1039,8 @@ export class CheckoutSessionService {
979
1039
  // Stable per-session idempotency key: reopening for the same session+amount
980
1040
  // returns the SAME gateway intent instead of minting a fresh one per retry.
981
1041
  IdempotencyKey: `checkout-${sessionID}-${Math.round(snapshotTotal * 100)}`,
982
- Metadata: { CheckoutSessionID: sessionID }
1042
+ Metadata: { CheckoutSessionID: sessionID },
1043
+ Description: description
983
1044
  }, mdProvider, contextUser);
984
1045
  if (!openResult.Success || !openResult.PaymentIntentID) {
985
1046
  return failed(openResult.Reason ?? 'The payment provider refused to open an intent.');
@@ -1034,7 +1095,7 @@ export class CheckoutSessionService {
1034
1095
  // `payment_intent.succeeded` is the other — BookSettledCheckoutPaymentIfNeeded, including
1035
1096
  // on AlreadyApplied webhook deliveries so a 500 after applyEvent still converges.
1036
1097
  if (orderLoaded) {
1037
- await this.applySettledPaymentToOrder(session, existingOrder, contextUser);
1098
+ await this.applySettledPaymentToOrder(session, existingOrder, contextUser, { Source: 'Checkout' });
1038
1099
  }
1039
1100
  return {
1040
1101
  Success: true,
@@ -1074,6 +1135,8 @@ export class CheckoutSessionService {
1074
1135
  session.Status = 'Processing';
1075
1136
  // Set the moment order.Confirm() commits; controls the catch's no-revert posture.
1076
1137
  let confirmedOrderID = null;
1138
+ // The Confirm step's record, begun once payment has checked out (#326).
1139
+ let confirmStep = null;
1077
1140
  try {
1078
1141
  const widget = await md.GetEntityObject(CHECKOUT_WIDGET_ENTITY, contextUser);
1079
1142
  await widget.Load(session.CheckoutWidgetID);
@@ -1091,12 +1154,14 @@ export class CheckoutSessionService {
1091
1154
  }
1092
1155
  // Refused before anything is written, so an unanswered checkout creates no Person.
1093
1156
  const answersCheck = this.checkSessionAnswers(widget, session);
1094
- if (answersCheck.Error) {
1157
+ const choicesCheck = this.checkSessionChoices(widget, session);
1158
+ const unanswered = answersCheck.Error ?? choicesCheck.Error;
1159
+ if (unanswered) {
1095
1160
  await CheckoutSessionService.revertSessionOpenAtomic(sessionID, md, contextUser);
1096
1161
  session.Status = 'Open';
1097
1162
  return {
1098
1163
  Success: false,
1099
- ErrorMessage: answersCheck.Error,
1164
+ ErrorMessage: unanswered,
1100
1165
  SessionID: sessionID,
1101
1166
  Status: 'Open'
1102
1167
  };
@@ -1242,6 +1307,21 @@ export class CheckoutSessionService {
1242
1307
  row.Answer = answer.Answer;
1243
1308
  row.OtherText = answer.OtherText;
1244
1309
  }
1310
+ // The choices ride on each line the checkout sold (every seat, in per-unit mode), in the
1311
+ // same graph: the entitlement walk reads them from the line to decide which conditional
1312
+ // entitlements to grant, and a refused confirm leaves none behind.
1313
+ for (const line of order.Lines.Items) {
1314
+ if (choicesCheck.Choices.length > 0 && !CheckoutSessionService.canRecordChoices(line)) {
1315
+ throw new Error('This checkout is not configured correctly (its choices cannot be recorded on this item).');
1316
+ }
1317
+ for (const choice of choicesCheck.Choices) {
1318
+ const row = await line.Choices.Create();
1319
+ row.GroupKey = choice.GroupKey;
1320
+ row.GroupLabel = choice.GroupLabel;
1321
+ row.OptionValue = choice.OptionValue;
1322
+ row.OptionLabel = choice.OptionLabel;
1323
+ }
1324
+ }
1245
1325
  // Price lines before confirmation
1246
1326
  const pricingService = new OrderPricingService({
1247
1327
  Provider: (order.ProviderToUse ?? md),
@@ -1290,10 +1370,16 @@ export class CheckoutSessionService {
1290
1370
  Status: 'Open'
1291
1371
  };
1292
1372
  }
1373
+ // Payment has checked out, so from here a failure leaves a paid checkout without
1374
+ // an order. Record the attempt; Confirm rolls back on failure, the record does not.
1375
+ confirmStep = await CheckoutStepLog.Begin(sessionID, 'Confirm', 'Checkout', contextUser);
1293
1376
  }
1294
1377
  // Confirm order via BaseEntity lifecycle (executes GL booking, entitlement issuance, status latching)
1295
1378
  await order.Confirm();
1296
1379
  confirmedOrderID = order.ID;
1380
+ if (confirmStep) {
1381
+ await CheckoutStepLog.Succeed(confirmStep);
1382
+ }
1297
1383
  // The order is now COMMITTED — from this point nothing may revert the session to
1298
1384
  // Open, or a retry would book a second order for the same purchase. Session
1299
1385
  // stamping failures are logged and repaired atomically, never surfaced as a
@@ -1307,7 +1393,7 @@ export class CheckoutSessionService {
1307
1393
  }
1308
1394
  // Book the PaymentHeader + allocation now that the order exists. retrieve-on-complete
1309
1395
  // only stamps PaymentIntent.Status = Succeeded; AmountPaid stays 0 until CapturePayment.
1310
- await this.applySettledPaymentToOrder(session, order, contextUser);
1396
+ await this.applySettledPaymentToOrder(session, order, contextUser, { Source: 'Checkout' });
1311
1397
  // Mint the GuestOrder identity claim for the buyer's email so a later account
1312
1398
  // (MJ core's IdentityClaimEngineServer) can attach the order + its entitlement
1313
1399
  // grants on redemption or claim-on-login. Best-effort: a claim failure must never
@@ -1354,6 +1440,9 @@ export class CheckoutSessionService {
1354
1440
  Status: 'Confirmed'
1355
1441
  };
1356
1442
  }
1443
+ if (confirmStep) {
1444
+ await CheckoutStepLog.Fail(confirmStep, msg);
1445
+ }
1357
1446
  await CheckoutSessionService.revertSessionOpenAtomic(sessionID, md, contextUser);
1358
1447
  session.Status = 'Open';
1359
1448
  LogError(`[CheckoutSessionService] CompleteCheckout failed for session ${sessionID}: ${msg}`);
@@ -1432,7 +1521,27 @@ export class CheckoutSessionService {
1432
1521
  if (!(await order.Load(session.DraftOrderID))) {
1433
1522
  return { Attempted: false, Booked: false };
1434
1523
  }
1435
- return this.applySettledPaymentToOrder(session, order, contextUser);
1524
+ return this.applySettledPaymentToOrder(session, order, contextUser, { Source: 'Webhook' });
1525
+ }
1526
+ /**
1527
+ * Operator replay of the Capture step (`Orders.ReplayCheckoutStep`, #326). The same idempotent
1528
+ * CapturePayment as the complete call and the webhook, recorded as a Replay by the operator.
1529
+ * Returns a refusal message instead when the session has no confirmed order to capture against.
1530
+ */
1531
+ static async ReplayCapture(sessionID, contextUser, replayedByUserID) {
1532
+ const md = new Metadata();
1533
+ const session = await md.GetEntityObject(CHECKOUT_SESSION_ENTITY, contextUser);
1534
+ if (!(await session.Load(sessionID))) {
1535
+ return `Checkout session ${sessionID} not found.`;
1536
+ }
1537
+ if (session.Status !== 'Confirmed' || !session.DraftOrderID) {
1538
+ return `Checkout session ${sessionID} has no confirmed order (status ${session.Status}); there is nothing to capture against.`;
1539
+ }
1540
+ const order = await md.GetEntityObject(ORDER_HEADER_ENTITY, contextUser);
1541
+ if (!(await order.Load(session.DraftOrderID))) {
1542
+ return `The order on checkout session ${sessionID} could not be read.`;
1543
+ }
1544
+ return this.applySettledPaymentToOrder(session, order, contextUser, { Source: 'Replay', ReplayedByUserID: replayedByUserID });
1436
1545
  }
1437
1546
  /**
1438
1547
  * After the order is committed, book `Orders.CapturePayment` against the session's
@@ -1442,7 +1551,7 @@ export class CheckoutSessionService {
1442
1551
  * Retries are CompleteCheckout replay and `BookSettledCheckoutPaymentIfNeeded`
1443
1552
  * from the payment_intent.succeeded webhook (including AlreadyApplied).
1444
1553
  */
1445
- static async applySettledPaymentToOrder(session, order, contextUser) {
1554
+ static async applySettledPaymentToOrder(session, order, contextUser, trigger) {
1446
1555
  if (!session.PaymentIntentID) {
1447
1556
  return { Attempted: false, Booked: false };
1448
1557
  }
@@ -1451,27 +1560,36 @@ export class CheckoutSessionService {
1451
1560
  return { Attempted: false, Booked: false };
1452
1561
  }
1453
1562
  if (Number(order.AmountPaid ?? 0) + 0.005 >= due) {
1563
+ // Paid, possibly by another path after an earlier capture attempt failed. A record
1564
+ // left Failed or Running would keep the session in the review queue.
1565
+ await CheckoutStepLog.CloseIfOpen(session.ID, 'Capture', contextUser);
1454
1566
  return { Attempted: false, Booked: true };
1455
1567
  }
1456
1568
  if (!contextUser) {
1457
- return this.captureFailed(order.ID, 'no context user', undefined, undefined, session.ID);
1569
+ return this.captureFailed(order.ID, 'no context user', undefined, undefined, session.ID, null);
1458
1570
  }
1571
+ const step = await CheckoutStepLog.Begin(session.ID, 'Capture', trigger.Source, contextUser, trigger.ReplayedByUserID);
1459
1572
  if (!order.BillToPersonID && !order.BillToOrganizationID) {
1460
- return this.captureFailed(order.ID, 'no bill-to party', undefined, contextUser, session.ID);
1573
+ return this.captureFailed(order.ID, 'no bill-to party', undefined, contextUser, session.ID, step);
1461
1574
  }
1462
1575
  const md = new Metadata();
1463
1576
  const intent = await md.GetEntityObject(PAYMENT_INTENT_ENTITY, contextUser);
1464
1577
  if (!(await intent.Load(session.PaymentIntentID))) {
1465
- return this.captureFailed(order.ID, 'payment intent not found', undefined, contextUser, session.ID);
1578
+ return this.captureFailed(order.ID, 'payment intent not found', undefined, contextUser, session.ID, step);
1466
1579
  }
1467
1580
  if (!SETTLED_INTENT_STATUSES.includes(intent.Status)) {
1468
1581
  await this.refreshIntentFromGateway(intent, contextUser);
1469
1582
  }
1470
1583
  if (!SETTLED_INTENT_STATUSES.includes(intent.Status)) {
1471
- return this.captureFailed(order.ID, `intent status is ${intent.Status}`, undefined, contextUser, session.ID);
1584
+ return this.captureFailed(order.ID, `intent status is ${intent.Status}`, undefined, contextUser, session.ID, step);
1472
1585
  }
1473
1586
  if (!intent.OrderHeaderID) {
1474
1587
  intent.OrderHeaderID = order.ID;
1588
+ // Second step of the gateway description: the intent was opened before the order existed.
1589
+ const mdForGateway = Metadata.Provider;
1590
+ if (mdForGateway) {
1591
+ await SendOrderDescriptionToGateway(intent, order.ID, mdForGateway, contextUser);
1592
+ }
1475
1593
  }
1476
1594
  if (!intent.BillToPersonID && order.BillToPersonID) {
1477
1595
  intent.BillToPersonID = order.BillToPersonID;
@@ -1497,7 +1615,7 @@ export class CheckoutSessionService {
1497
1615
  }
1498
1616
  const mdProvider = Metadata.Provider;
1499
1617
  if (!mdProvider) {
1500
- return this.captureFailed(order.ID, 'no metadata provider', undefined, contextUser, session.ID);
1618
+ return this.captureFailed(order.ID, 'no metadata provider', undefined, contextUser, session.ID, step);
1501
1619
  }
1502
1620
  try {
1503
1621
  const op = new CapturePaymentOperation();
@@ -1525,21 +1643,27 @@ export class CheckoutSessionService {
1525
1643
  ?? output?.Blockers?.map((b) => b.Message).join('; ')
1526
1644
  ?? 'unknown error';
1527
1645
  const codes = (output?.Blockers ?? []).map((b) => b.Code).filter((c) => Boolean(c));
1528
- return this.captureFailed(order.ID, detail, isCaptureRefusalRetryable(codes), contextUser, session.ID);
1646
+ return this.captureFailed(order.ID, detail, isCaptureRefusalRetryable(codes), contextUser, session.ID, step);
1529
1647
  }
1648
+ await CheckoutStepLog.Succeed(step);
1530
1649
  return { Attempted: true, Booked: true };
1531
1650
  }
1532
1651
  catch (err) {
1533
1652
  const msg = err instanceof Error ? err.message : String(err);
1534
- return this.captureFailed(order.ID, msg, true, contextUser, session.ID);
1653
+ return this.captureFailed(order.ID, msg, true, contextUser, session.ID, step);
1535
1654
  }
1536
1655
  }
1537
- static captureFailed(orderID, message, retryable, contextUser, sessionID) {
1656
+ static async captureFailed(orderID, message, retryable, contextUser, sessionID, step) {
1538
1657
  const Retryable = retryable ?? !isTerminalCapturePrecheck(message);
1539
1658
  LogError(`[CheckoutSessionService] CapturePayment failed for order ${orderID}: ${message}`);
1540
- if (!Retryable) {
1659
+ // One Task per terminal failure, not one per replay of it: the step record says whether
1660
+ // the last attempt already ended the same way.
1661
+ if (!Retryable && (!step || CheckoutStepLog.IsNewTerminalFailure(step))) {
1541
1662
  void raiseCheckoutCaptureTerminalAlert(orderID, sessionID, message, contextUser);
1542
1663
  }
1664
+ if (step) {
1665
+ await CheckoutStepLog.Fail(step, message, Retryable);
1666
+ }
1543
1667
  return { Attempted: true, Booked: false, ErrorMessage: message, Retryable };
1544
1668
  }
1545
1669
  /**