@aglyn/plugins-commerce 1.0.0-beta.203 → 1.0.0-beta.205

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aglyn/plugins-commerce",
3
- "version": "1.0.0-beta.203",
3
+ "version": "1.0.0-beta.205",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://aglyn.com",
6
6
  "repository": {
@@ -25,18 +25,18 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "dependencies": {
28
- "@aglyn/aglyn": "1.0.0-beta.203",
29
- "@aglyn/shared-data-mdi": "1.0.0-beta.203",
30
- "@aglyn/shared-ui-jsx": "1.0.0-beta.203",
31
- "@aglyn/shared-ui-next": "1.0.0-beta.203",
32
- "@aglyn/shared-ui-snackstack": "1.0.0-beta.203",
33
- "@aglyn/shared-util-email": "1.0.0-beta.203",
34
- "@aglyn/shared-util-http": "1.0.0-beta.203",
35
- "@aglyn/shared-util-timestamp": "1.0.0-beta.203",
36
- "@aglyn/shared-util-tools": "1.0.0-beta.203",
37
- "@aglyn/tenant-data-admin": "1.0.0-beta.203",
38
- "@aglyn/tenant-feature-instance": "1.0.0-beta.203",
39
- "@aglyn/tenant-runtime": "1.0.0-beta.203",
28
+ "@aglyn/aglyn": "1.0.0-beta.205",
29
+ "@aglyn/shared-data-mdi": "1.0.0-beta.205",
30
+ "@aglyn/shared-ui-jsx": "1.0.0-beta.205",
31
+ "@aglyn/shared-ui-next": "1.0.0-beta.205",
32
+ "@aglyn/shared-ui-snackstack": "1.0.0-beta.205",
33
+ "@aglyn/shared-util-email": "1.0.0-beta.205",
34
+ "@aglyn/shared-util-http": "1.0.0-beta.205",
35
+ "@aglyn/shared-util-timestamp": "1.0.0-beta.205",
36
+ "@aglyn/shared-util-tools": "1.0.0-beta.205",
37
+ "@aglyn/tenant-data-admin": "1.0.0-beta.205",
38
+ "@aglyn/tenant-feature-instance": "1.0.0-beta.205",
39
+ "@aglyn/tenant-runtime": "1.0.0-beta.205",
40
40
  "@stripe/react-stripe-js": "^3.10.0",
41
41
  "@stripe/stripe-js": "^5.10.0",
42
42
  "@swc/helpers": "0.5.23",
@@ -15,7 +15,7 @@
15
15
  * limitations under the License.
16
16
  */ import { _ as _extends } from "@swc/helpers/_/_extends";
17
17
  import * as Aglyn from "@aglyn/aglyn/server";
18
- import { findUserByUidAcrossPools, firebaseAdmin, getOrgForHost, meterHostEmail, notifyHostManagers, notifyStaff, renderHostEmailWithTokens, clearConnectPayoutFailure, recordConnectPayoutFailure, syncConnectAccountStatus, updateExisting, hostSendingIdentity } from "@aglyn/tenant-data-admin";
18
+ import { findUserByUidAcrossPools, firebaseAdmin, getOrgForHost, meterHostEmail, notifyHostManagers, notifyRiskEvent, notifyStaff, renderHostEmailWithTokens, clearConnectPayoutFailure, recordConnectPayoutFailure, syncConnectAccountStatus, updateExisting, hostSendingIdentity } from "@aglyn/tenant-data-admin";
19
19
  import { captureHostContact } from "@aglyn/tenant-runtime";
20
20
  import { createHmac } from "crypto";
21
21
  import { isEmailConfigured, sendEmail } from "@aglyn/shared-util-email";
@@ -3918,10 +3918,12 @@ async function findOrderForDispute(paymentIntentId) {
3918
3918
  if (outcome.kind === 'frozen-for-review') {
3919
3919
  await notifyGiftCardHold({
3920
3920
  hostId,
3921
- orderLabel: `Order ${snapshot.id}`,
3921
+ orderLabel: `order ${snapshot.id}`,
3922
+ orderPath: `/${hostId}/products/orders?order=${encodeURIComponent(snapshot.id)}`,
3923
+ orderId: snapshot.id,
3922
3924
  cards: outcome.cards,
3923
3925
  reason: 'refund-review'
3924
- }, notifyHostManagers);
3926
+ }, notifyRiskEvent);
3925
3927
  }
3926
3928
  }
3927
3929
  return {
@@ -3953,28 +3955,32 @@ async function findOrderForDispute(paymentIntentId) {
3953
3955
  ref: snapshot.ref,
3954
3956
  signal: risk.signal,
3955
3957
  hostId,
3956
- subjectLabel: `Order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
3957
- link: `/${hostId}/orders`,
3958
+ subjectLabel: `order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
3959
+ // The Orders section of the Products hub, with this order's dialog
3960
+ // open — where Refund lives (`siteRecordLinks().order`).
3961
+ link: `/${hostId}/products/orders?order=${encodeURIComponent(snapshot.id)}`,
3958
3962
  notificationType: 'content.order',
3959
3963
  extraUpdate: (data)=>({
3960
3964
  timeline: CommerceModel.appendOrderEvent(CommerceModel.liftLegacyOrder(data), risk.signal.kind === 'early-fraud-warning' ? 'fraud-warning' : 'payment-review', risk.signal.kind === 'early-fraud-warning' ? 'The card issuer reported this payment as possibly fraudulent' + (risk.signal.detail ? ` (${risk.signal.detail.replace(/_/g, ' ')})` : '') : 'Stripe Radar is holding this payment for review', risk.signal.atMs)
3961
3965
  })
3962
3966
  }, {
3963
3967
  firestore: firebaseAdmin.app().firestore(),
3964
- notify: notifyHostManagers
3968
+ notifyRisk: notifyRiskEvent
3965
3969
  });
3966
3970
  // The cards this order bought are frozen until the merchant releases them
3967
3971
  // (AGL-3363): a warning or review is the moment a stolen-card gift card
3968
3972
  // is still unspent.
3969
3973
  await notifyGiftCardHold({
3970
3974
  hostId,
3971
- orderLabel: `Order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
3975
+ orderLabel: `order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
3976
+ orderPath: `/${hostId}/products/orders?order=${encodeURIComponent(snapshot.id)}`,
3977
+ orderId: snapshot.id,
3972
3978
  cards: await applyOrderGiftCardRisk(snapshot, {
3973
3979
  kind: 'freeze',
3974
3980
  reason: risk.signal.kind
3975
3981
  }),
3976
3982
  reason: risk.signal.kind
3977
- }, notifyHostManagers);
3983
+ }, notifyRiskEvent);
3978
3984
  return {
3979
3985
  claimed: true,
3980
3986
  hostId
@@ -4038,33 +4044,46 @@ async function findOrderForDispute(paymentIntentId) {
4038
4044
  // A chargeback's gift cards are frozen while it is open (AGL-3363).
4039
4045
  await notifyGiftCardHold({
4040
4046
  hostId,
4041
- orderLabel: `Order ${snapshot.id}`,
4047
+ orderLabel: `order ${snapshot.id}`,
4048
+ orderPath: `/${hostId}/products/orders?order=${encodeURIComponent(snapshot.id)}`,
4049
+ orderId: snapshot.id,
4042
4050
  cards: await applyOrderGiftCardRisk(snapshot, {
4043
4051
  kind: 'freeze',
4044
4052
  reason: 'dispute'
4045
4053
  }),
4046
4054
  reason: 'dispute'
4047
- }, notifyHostManagers);
4055
+ }, notifyRiskEvent);
4048
4056
  const { opened, record } = await recordDisputeOpened(snapshot, dispute);
4049
4057
  if (opened && hostId) {
4058
+ var _snapshot_data1, _record_evidenceDueByMs, _ref88;
4050
4059
  // Time-critical — Stripe's evidence window is days, not weeks — so
4051
4060
  // this is awaited rather than fired off with `void`: the handler is
4052
4061
  // serverless and work left running past the response is work the
4053
- // container may be frozen before it finishes. `notifyHostManagers`
4054
- // never throws.
4055
- await notifyHostManagers(hostId, {
4056
- type: 'content.order',
4057
- title: `Chargeback opened — $${(record.amountCents / 100).toFixed(2)}`,
4058
- body: `Order ${snapshot.id} was disputed` + (record.reason ? ` (${record.reason.replace(/_/g, ' ')})` : '') + (record.evidenceDueByMs ? `. Evidence is due ${new Date(record.evidenceDueByMs).toISOString().slice(0, 10)}.` : '. Respond in Stripe.'),
4059
- link: `/${hostId}/orders`
4062
+ // container may be frozen before it finishes. The risk notice
4063
+ // (AGL-3368) tells the site's managers and the workspace's owners
4064
+ // what a dispute means and when the evidence is due; it never
4065
+ // throws.
4066
+ const order = CommerceModel.liftLegacyOrder((_snapshot_data1 = snapshot.data()) != null ? _snapshot_data1 : {});
4067
+ await notifyRiskEvent({
4068
+ kind: 'sale-dispute',
4069
+ orgId: null,
4070
+ hostId,
4071
+ item: {
4072
+ label: `order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
4073
+ path: `/${hostId}/products/orders?order=${encodeURIComponent(snapshot.id)}`
4074
+ },
4075
+ amount: `$${(record.amountCents / 100).toFixed(2)}`,
4076
+ evidenceDueByMs: (_record_evidenceDueByMs = record.evidenceDueByMs) != null ? _record_evidenceDueByMs : null,
4077
+ dedupeKey: `sale:${String((_ref88 = dispute == null ? void 0 : dispute.id) != null ? _ref88 : snapshot.id)}`,
4078
+ staffEvidence: record.reason ? `Reason: ${record.reason.replace(/_/g, ' ')}.` : null
4060
4079
  });
4061
4080
  }
4062
4081
  } else {
4063
- var _ref88, _ref89;
4082
+ var _ref89, _ref90;
4064
4083
  // Lost: the money went back, so the cards it bought are voided. Won
4065
4084
  // (or closed on a warning): the dispute's freeze lifts; a freeze a
4066
4085
  // fraud warning or review put on stays for the merchant (AGL-3363).
4067
- await applyOrderGiftCardRisk(snapshot, String((_ref88 = dispute == null ? void 0 : dispute.status) != null ? _ref88 : '') === 'lost' ? {
4086
+ await applyOrderGiftCardRisk(snapshot, String((_ref89 = dispute == null ? void 0 : dispute.status) != null ? _ref89 : '') === 'lost' ? {
4068
4087
  kind: 'void',
4069
4088
  reason: 'dispute-lost'
4070
4089
  } : {
@@ -4128,7 +4147,7 @@ async function findOrderForDispute(paymentIntentId) {
4128
4147
  // transiently-failed reversal gets its retry — and gated inside on
4129
4148
  // the order's own `reversedTransferCents` marker, so it runs at most
4130
4149
  // once per dispute however many times Stripe delivers.
4131
- if (String((_ref89 = dispute == null ? void 0 : dispute.status) != null ? _ref89 : '') === 'lost') {
4150
+ if (String((_ref90 = dispute == null ? void 0 : dispute.status) != null ? _ref90 : '') === 'lost') {
4132
4151
  const pulledBackCents = await reverseSellerShare(snapshot.ref, dispute);
4133
4152
  // The merchant-experience half of the AGL-1794 decision, and not an
4134
4153
  // optional extra: the reversal takes money out of the connected