@aglyn/plugins-commerce 1.0.0-beta.199 → 1.0.0-beta.201
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 +13 -13
- package/src/lib/components/console/catalog-organization-card.component.js +48 -3
- package/src/lib/components/console/catalog-organization-card.component.js.map +1 -1
- package/src/lib/components/console/gift-cards-card.component.d.ts +9 -0
- package/src/lib/components/console/gift-cards-card.component.js +53 -28
- package/src/lib/components/console/gift-cards-card.component.js.map +1 -1
- package/src/lib/components/console/host-orders-card.component.d.ts +26 -0
- package/src/lib/components/console/host-orders-card.component.js +264 -194
- package/src/lib/components/console/host-orders-card.component.js.map +1 -1
- package/src/lib/components/console/order-detail-dialog.component.js +12 -0
- package/src/lib/components/console/order-detail-dialog.component.js.map +1 -1
- package/src/lib/components/console/pos-page.component.d.ts +14 -0
- package/src/lib/components/console/pos-page.component.js +86 -45
- package/src/lib/components/console/pos-page.component.js.map +1 -1
- package/src/lib/components/console/product-editor-dialog.component.js +30 -6
- package/src/lib/components/console/product-editor-dialog.component.js.map +1 -1
- package/src/lib/components/console/product-slugs.d.ts +43 -0
- package/src/lib/components/console/product-slugs.js +60 -0
- package/src/lib/components/console/product-slugs.js.map +1 -0
- package/src/lib/components/console/products-hub-card.component.d.ts +2 -2
- package/src/lib/components/console/products-hub-card.component.js +229 -282
- package/src/lib/components/console/products-hub-card.component.js.map +1 -1
- package/src/lib/components/console/products-hub-zone.component.d.ts +10 -5
- package/src/lib/components/console/products-hub-zone.component.js +32 -9
- package/src/lib/components/console/products-hub-zone.component.js.map +1 -1
- package/src/lib/components/console/recovery-queue-card.component.d.ts +37 -5
- package/src/lib/components/console/recovery-queue-card.component.js +107 -86
- package/src/lib/components/console/recovery-queue-card.component.js.map +1 -1
- package/src/lib/components/console/reservations-card.component.js +15 -3
- package/src/lib/components/console/reservations-card.component.js.map +1 -1
- package/src/lib/components/console/smart-collections.d.ts +32 -0
- package/src/lib/components/console/smart-collections.js +57 -0
- package/src/lib/components/console/smart-collections.js.map +1 -0
- package/src/lib/components/console/stock-movements-card.component.d.ts +13 -4
- package/src/lib/components/console/stock-movements-card.component.js +142 -180
- package/src/lib/components/console/stock-movements-card.component.js.map +1 -1
- package/src/lib/components/product-grid.d.ts +5 -0
- package/src/lib/components/product-grid.js +95 -34
- package/src/lib/components/product-grid.js.map +1 -1
- package/src/lib/constants/orders-list-query.d.ts +40 -0
- package/src/lib/constants/orders-list-query.js +205 -0
- package/src/lib/constants/orders-list-query.js.map +1 -0
- package/src/lib/constants/product-list-query.d.ts +42 -0
- package/src/lib/constants/product-list-query.js +217 -0
- package/src/lib/constants/product-list-query.js.map +1 -0
- package/src/lib/constants/stock-movement-query.d.ts +27 -0
- package/src/lib/constants/stock-movement-query.js +110 -0
- package/src/lib/constants/stock-movement-query.js.map +1 -0
- package/src/lib/constants/storefront-catalog-query.d.ts +103 -0
- package/src/lib/constants/storefront-catalog-query.js +312 -0
- package/src/lib/constants/storefront-catalog-query.js.map +1 -0
- package/src/lib/model/checkout-recovery.d.ts +37 -0
- package/src/lib/model/checkout-recovery.js +44 -0
- package/src/lib/model/checkout-recovery.js.map +1 -0
- package/src/lib/model/commerce-orders.d.ts +7 -0
- package/src/lib/model/commerce-orders.js.map +1 -1
- package/src/lib/model/commerce.d.ts +80 -0
- package/src/lib/model/commerce.js +67 -6
- package/src/lib/model/commerce.js.map +1 -1
- package/src/lib/model/gift-card-search.d.ts +24 -0
- package/src/lib/model/gift-card-search.js +48 -0
- package/src/lib/model/gift-card-search.js.map +1 -0
- package/src/lib/model/index.d.ts +1 -0
- package/src/lib/model/index.js +1 -0
- package/src/lib/model/index.js.map +1 -1
- package/src/lib/model/order-list-fields.d.ts +80 -0
- package/src/lib/model/order-list-fields.js +112 -0
- package/src/lib/model/order-list-fields.js.map +1 -0
- package/src/lib/server/billing-webhook.js +180 -99
- package/src/lib/server/billing-webhook.js.map +1 -1
- package/src/lib/server/cancel-order.js +6 -6
- package/src/lib/server/cancel-order.js.map +1 -1
- package/src/lib/server/cart-checkout.js +9 -2
- package/src/lib/server/cart-checkout.js.map +1 -1
- package/src/lib/server/catalog.d.ts +46 -30
- package/src/lib/server/catalog.js +507 -170
- package/src/lib/server/catalog.js.map +1 -1
- package/src/lib/server/checkout.js +3 -1
- package/src/lib/server/checkout.js.map +1 -1
- package/src/lib/server/collection-membership.d.ts +35 -0
- package/src/lib/server/collection-membership.js +172 -0
- package/src/lib/server/collection-membership.js.map +1 -0
- package/src/lib/server/draft-order.js +5 -3
- package/src/lib/server/draft-order.js.map +1 -1
- package/src/lib/server/gift-cards.js +7 -1
- package/src/lib/server/gift-cards.js.map +1 -1
- package/src/lib/server/member-name-search.d.ts +17 -0
- package/src/lib/server/member-name-search.js +23 -1
- package/src/lib/server/member-name-search.js.map +1 -1
- package/src/lib/server/membership-account.js +7 -3
- package/src/lib/server/membership-account.js.map +1 -1
- package/src/lib/server/membership-admin-password.js +8 -2
- package/src/lib/server/membership-admin-password.js.map +1 -1
- package/src/lib/server/membership-recover.js +4 -1
- package/src/lib/server/membership-recover.js.map +1 -1
- package/src/lib/server/membership-register.js +3 -1
- package/src/lib/server/membership-register.js.map +1 -1
- package/src/lib/server/pos-order.js +9 -5
- package/src/lib/server/pos-order.js.map +1 -1
- package/src/lib/server/process-abandoned.js +20 -7
- package/src/lib/server/process-abandoned.js.map +1 -1
- package/src/lib/server/process-restock.js +6 -2
- package/src/lib/server/process-restock.js.map +1 -1
- package/src/lib/server/reserve-stock.js +3 -4
- package/src/lib/server/reserve-stock.js.map +1 -1
- package/src/lib/server/reserve.js +3 -1
- package/src/lib/server/reserve.js.map +1 -1
- package/src/lib/server/site-page-enricher.js +3 -3
- package/src/lib/server/site-page-enricher.js.map +1 -1
- package/src/lib/server.js +4 -0
- package/src/lib/server.js.map +1 -1
|
@@ -25,9 +25,12 @@ import { recordContactRefund } from "./contact-refund.js";
|
|
|
25
25
|
// specs in this library mock `@aglyn/tenant-data-admin` wholesale, and a
|
|
26
26
|
// permissive stub would turn a reversal that never happened green.
|
|
27
27
|
import { reverseEmailAttributedRevenue } from "@aglyn/tenant-data-admin/server/email-revenue-attribution";
|
|
28
|
+
import { paymentRiskEventFrom } from "@aglyn/aglyn/app-utils/payment-risk";
|
|
29
|
+
import { recordPaymentRiskOnRecord } from "@aglyn/tenant-data-admin/server/payment-risk-record";
|
|
28
30
|
import { mintDownloadToken, tokenSigningSecret } from "./download.js";
|
|
29
31
|
import { alertLowStockCrossing } from "./low-stock.js";
|
|
30
32
|
import { decrementVariantStock } from "./reserve-stock.js";
|
|
33
|
+
import { giftCardSearchTokens } from "../model/gift-card-search.js";
|
|
31
34
|
import { releaseStockHold } from "./stock-hold.js";
|
|
32
35
|
import { releasePromotionHold, settlePromotionSlot } from "./promotion-hold.js";
|
|
33
36
|
import { flagOrderRestock } from "./restock-flag.js";
|
|
@@ -326,7 +329,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
326
329
|
*/ async function recordDisputeOpened(snapshot, dispute) {
|
|
327
330
|
const record = disputeFromEvent(dispute);
|
|
328
331
|
const opened = await firebaseAdmin.app().firestore().runTransaction(async (transaction)=>{
|
|
329
|
-
var _fresh_data;
|
|
332
|
+
var _fresh_data, _fresh_data1;
|
|
330
333
|
var _order_dispute;
|
|
331
334
|
const fresh = await transaction.get(snapshot.ref);
|
|
332
335
|
if (!fresh.exists) return false;
|
|
@@ -347,10 +350,12 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
347
350
|
// the same charge and does replace it.
|
|
348
351
|
if (((_order_dispute = order.dispute) == null ? void 0 : _order_dispute.id) === record.id) return false;
|
|
349
352
|
const amount = `$${(record.amountCents / 100).toFixed(2)}`;
|
|
350
|
-
transaction.update(snapshot.ref, {
|
|
353
|
+
transaction.update(snapshot.ref, _extends({}, CommerceModel.orderListFields(_extends({}, (_fresh_data1 = fresh.data()) != null ? _fresh_data1 : {}, {
|
|
354
|
+
dispute: record
|
|
355
|
+
}), snapshot.id), {
|
|
351
356
|
dispute: record,
|
|
352
357
|
timeline: CommerceModel.appendOrderEvent(order, 'dispute', `Chargeback opened for ${amount}` + (record.reason ? ` (${record.reason.replace(/_/g, ' ')})` : '') + (record.evidenceDueByMs ? ` — evidence due ${new Date(record.evidenceDueByMs).toISOString().slice(0, 10)}` : ''), record.openedAtMs)
|
|
353
|
-
});
|
|
358
|
+
}));
|
|
354
359
|
return true;
|
|
355
360
|
});
|
|
356
361
|
return {
|
|
@@ -407,7 +412,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
407
412
|
const outcome = String((_ref = dispute == null ? void 0 : dispute.status) != null ? _ref : '');
|
|
408
413
|
const lost = outcome === 'lost';
|
|
409
414
|
return firebaseAdmin.app().firestore().runTransaction(async (transaction)=>{
|
|
410
|
-
var _fresh_data, _ref, _order_amountCents, _order_refundedCents;
|
|
415
|
+
var _fresh_data, _ref, _order_amountCents, _order_refundedCents, _fresh_data1;
|
|
411
416
|
var _order_totals;
|
|
412
417
|
const idle = {
|
|
413
418
|
recorded: false,
|
|
@@ -430,19 +435,24 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
430
435
|
const closedTheOrder = fullyReversed && CommerceModel.canTransitionOrder(order.status, 'refunded');
|
|
431
436
|
const closedAtMs = Date.now();
|
|
432
437
|
const amount = `$${(reversedCents / 100).toFixed(2)}`;
|
|
433
|
-
|
|
438
|
+
const settled = _extends({}, event, (stored == null ? void 0 : stored.id) === event.id && stored.openedAtMs ? {
|
|
439
|
+
openedAtMs: stored.openedAtMs
|
|
440
|
+
} : {}, {
|
|
441
|
+
status: outcome,
|
|
442
|
+
outcome,
|
|
443
|
+
closedAtMs,
|
|
444
|
+
reversedCents
|
|
445
|
+
});
|
|
446
|
+
transaction.update(snapshot.ref, _extends({}, CommerceModel.orderListFields(_extends({}, (_fresh_data1 = fresh.data()) != null ? _fresh_data1 : {}, closedTheOrder ? {
|
|
447
|
+
status: 'refunded'
|
|
448
|
+
} : {}, {
|
|
449
|
+
dispute: settled
|
|
450
|
+
}), snapshot.id), reversedCents > 0 ? {
|
|
434
451
|
refundedCents: reversedTotal
|
|
435
452
|
} : {}, closedTheOrder ? {
|
|
436
453
|
status: 'refunded'
|
|
437
454
|
} : {}, {
|
|
438
|
-
dispute:
|
|
439
|
-
openedAtMs: stored.openedAtMs
|
|
440
|
-
} : {}, {
|
|
441
|
-
status: outcome,
|
|
442
|
-
outcome,
|
|
443
|
-
closedAtMs,
|
|
444
|
-
reversedCents
|
|
445
|
-
}),
|
|
455
|
+
dispute: settled,
|
|
446
456
|
timeline: CommerceModel.appendOrderEvent(order, 'dispute', lost ? `${amount} charged back (dispute lost)` + (closedTheOrder ? ' (full)' : '') : `Dispute ${outcome.replace(/_/g, ' ')} — no money reversed`, closedAtMs)
|
|
447
457
|
}));
|
|
448
458
|
return {
|
|
@@ -1394,7 +1404,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
1394
1404
|
* this far. A notification is not idempotent by any doc key of its own.
|
|
1395
1405
|
*/ const settle = async (reversedTransferCents, transferReversalId, note)=>{
|
|
1396
1406
|
return firebaseAdmin.app().firestore().runTransaction(async (transaction)=>{
|
|
1397
|
-
var _fresh_data;
|
|
1407
|
+
var _fresh_data, _fresh_data1;
|
|
1398
1408
|
const fresh = await transaction.get(orderRef);
|
|
1399
1409
|
if (!fresh.exists) return false;
|
|
1400
1410
|
const current = CommerceModel.liftLegacyOrder((_fresh_data = fresh.data()) != null ? _fresh_data : {});
|
|
@@ -1402,15 +1412,18 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
1402
1412
|
if ((record == null ? void 0 : record.id) !== disputeId || record.reversedTransferCents != null) {
|
|
1403
1413
|
return false;
|
|
1404
1414
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1415
|
+
// Written whole, the field's own rule — see `OrderDispute`.
|
|
1416
|
+
const dispute = _extends({}, record, {
|
|
1417
|
+
reversedTransferCents
|
|
1418
|
+
}, transferReversalId ? {
|
|
1419
|
+
transferReversalId
|
|
1420
|
+
} : {});
|
|
1421
|
+
transaction.update(orderRef, _extends({}, CommerceModel.orderListFields(_extends({}, (_fresh_data1 = fresh.data()) != null ? _fresh_data1 : {}, {
|
|
1422
|
+
dispute
|
|
1423
|
+
}), orderRef.id), {
|
|
1424
|
+
dispute,
|
|
1412
1425
|
timeline: CommerceModel.appendOrderEvent(current, 'dispute', note)
|
|
1413
|
-
});
|
|
1426
|
+
}));
|
|
1414
1427
|
return true;
|
|
1415
1428
|
});
|
|
1416
1429
|
};
|
|
@@ -2215,7 +2228,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2215
2228
|
}, {
|
|
2216
2229
|
merge: true
|
|
2217
2230
|
});
|
|
2218
|
-
|
|
2231
|
+
// With the fields the orders list queries by (AGL-3321).
|
|
2232
|
+
transaction.set(orderRef, CommerceModel.withOrderListFields(orderRef.id, _extends({
|
|
2219
2233
|
number: orderNumber,
|
|
2220
2234
|
status: 'paid',
|
|
2221
2235
|
channel: 'subscription',
|
|
@@ -2256,7 +2270,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2256
2270
|
feeCents: Number((_invoiceTotals_feeCents = invoiceTotals.feeCents) != null ? _invoiceTotals_feeCents : 0),
|
|
2257
2271
|
createdAtMs: paidAtMs,
|
|
2258
2272
|
createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp()
|
|
2259
|
-
}));
|
|
2273
|
+
})));
|
|
2260
2274
|
}
|
|
2261
2275
|
return true;
|
|
2262
2276
|
});
|
|
@@ -2579,7 +2593,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2579
2593
|
fromName: (await brandFor(hostId)).fromName,
|
|
2580
2594
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
2581
2595
|
audience: 'tenant',
|
|
2582
|
-
context: 'reservation confirmation'
|
|
2596
|
+
context: 'reservation confirmation',
|
|
2597
|
+
// Owed to the recipient by their own booking: the phishing
|
|
2598
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
2599
|
+
owedFor: 'booking'
|
|
2583
2600
|
}));
|
|
2584
2601
|
// Cost meter (AGL-1438). Transactional: the guest has paid, and a
|
|
2585
2602
|
// confirmation a quota refused reads as a failed reservation.
|
|
@@ -2681,7 +2698,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2681
2698
|
const totals = CommerceModel.computeCheckoutSessionTotals(lineItems, object, {
|
|
2682
2699
|
feeCents: Number(feeCents != null ? feeCents : 0)
|
|
2683
2700
|
});
|
|
2684
|
-
|
|
2701
|
+
// With the fields the orders list queries by (AGL-3321).
|
|
2702
|
+
transaction.set(orderRef, CommerceModel.withOrderListFields(orderRef.id, _extends({
|
|
2685
2703
|
number,
|
|
2686
2704
|
status: 'paid',
|
|
2687
2705
|
channel: 'online',
|
|
@@ -2735,7 +2753,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2735
2753
|
feeCents: Number(feeCents != null ? feeCents : 0),
|
|
2736
2754
|
createdAtMs: Date.now(),
|
|
2737
2755
|
createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp()
|
|
2738
|
-
}));
|
|
2756
|
+
})));
|
|
2739
2757
|
return true;
|
|
2740
2758
|
});
|
|
2741
2759
|
// Redelivery/replay guard (AGL-498): only fulfil when the order was
|
|
@@ -2855,7 +2873,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
2855
2873
|
fromName: (await brandFor(hostId)).fromName,
|
|
2856
2874
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
2857
2875
|
audience: 'tenant',
|
|
2858
|
-
context: 'cart receipt'
|
|
2876
|
+
context: 'cart receipt',
|
|
2877
|
+
// Owed to the recipient by their own order: the phishing
|
|
2878
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
2879
|
+
owedFor: 'order'
|
|
2859
2880
|
}));
|
|
2860
2881
|
// Cost meter (AGL-1438). Transactional: a dropped receipt looks to
|
|
2861
2882
|
// the buyer like an order that did not go through.
|
|
@@ -3042,8 +3063,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3042
3063
|
const lineProduct = productsById.get(line.productId);
|
|
3043
3064
|
if (!(lineProduct == null ? void 0 : lineProduct.giftCard)) continue;
|
|
3044
3065
|
for(let unit = 0; unit < line.quantity; unit += 1){
|
|
3045
|
-
var _ref53;
|
|
3046
|
-
var _object_customer_details12, _object_customer_details13;
|
|
3066
|
+
var _ref53, _ref54;
|
|
3067
|
+
var _object_customer_details12, _object_customer_details13, _object_customer_details14;
|
|
3047
3068
|
const code = `GC-${createHmac('sha256', String(object.id)).update(`${line.productId}:${unit}:${Date.now()}`).digest('hex').slice(0, 12).toUpperCase()}`;
|
|
3048
3069
|
// THE EMAIL IS GATED ON THE WRITE (AGL-2161). This `.set()` used
|
|
3049
3070
|
// to `.catch(() => undefined)` and fall straight through to the
|
|
@@ -3063,6 +3084,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3063
3084
|
balanceCents: line.unitAmountCents,
|
|
3064
3085
|
recipientEmail: (_ref53 = object == null ? void 0 : (_object_customer_details12 = object.customer_details) == null ? void 0 : _object_customer_details12.email) != null ? _ref53 : null,
|
|
3065
3086
|
orderId: String(object.id),
|
|
3087
|
+
// What the console's Gift cards search asks (AGL-3321).
|
|
3088
|
+
searchTokens: giftCardSearchTokens(code, (_ref54 = object == null ? void 0 : (_object_customer_details13 = object.customer_details) == null ? void 0 : _object_customer_details13.email) != null ? _ref54 : null),
|
|
3066
3089
|
createdAtMs: Date.now()
|
|
3067
3090
|
}).then(()=>true).catch((error)=>{
|
|
3068
3091
|
console.error('Gift card issuance failed', hostId, code, error);
|
|
@@ -3088,9 +3111,9 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3088
3111
|
});
|
|
3089
3112
|
continue;
|
|
3090
3113
|
}
|
|
3091
|
-
const giftTo = object == null ? void 0 : (
|
|
3114
|
+
const giftTo = object == null ? void 0 : (_object_customer_details14 = object.customer_details) == null ? void 0 : _object_customer_details14.email;
|
|
3092
3115
|
if (giftTo) {
|
|
3093
|
-
var
|
|
3116
|
+
var _ref55;
|
|
3094
3117
|
const giftValue = `$${(line.unitAmountCents / 100).toFixed(2)}`;
|
|
3095
3118
|
const fallbackText = `Gift card code: ${code}\n` + `Value: ${giftValue}\n\n` + 'Enter it at checkout to apply the balance.';
|
|
3096
3119
|
// Site-owner-designed template when published (AGL-771).
|
|
@@ -3100,7 +3123,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3100
3123
|
});
|
|
3101
3124
|
await sendEmail(_extends({
|
|
3102
3125
|
to: giftTo,
|
|
3103
|
-
subject: (
|
|
3126
|
+
subject: (_ref55 = designed == null ? void 0 : designed.subject) != null ? _ref55 : 'Your gift card',
|
|
3104
3127
|
text: (designed == null ? void 0 : designed.text) || fallbackText
|
|
3105
3128
|
}, (designed == null ? void 0 : designed.html) ? {
|
|
3106
3129
|
html: designed.html
|
|
@@ -3108,7 +3131,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3108
3131
|
fromName: (await brandFor(hostId)).fromName,
|
|
3109
3132
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
3110
3133
|
audience: 'tenant',
|
|
3111
|
-
context: 'gift card'
|
|
3134
|
+
context: 'gift card',
|
|
3135
|
+
// Owed to the recipient by their own order: the phishing
|
|
3136
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
3137
|
+
owedFor: 'order'
|
|
3112
3138
|
}));
|
|
3113
3139
|
// Cost meter (AGL-1438). Transactional: this email IS the
|
|
3114
3140
|
// purchased goods.
|
|
@@ -3118,12 +3144,12 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3118
3144
|
}
|
|
3119
3145
|
// Discounts engine redemptions (AGL-305).
|
|
3120
3146
|
if ((_object_metadata22 = object.metadata) == null ? void 0 : _object_metadata22.discountId) {
|
|
3121
|
-
var
|
|
3147
|
+
var _ref56;
|
|
3122
3148
|
var _object_metadata26;
|
|
3123
3149
|
await settleRedemption({
|
|
3124
3150
|
firestore,
|
|
3125
3151
|
ref: hostRef.collection('discounts').doc(String(object.metadata.discountId)),
|
|
3126
|
-
holdKey: String((
|
|
3152
|
+
holdKey: String((_ref56 = (_object_metadata26 = object.metadata) == null ? void 0 : _object_metadata26.discountHoldKey) != null ? _ref56 : ''),
|
|
3127
3153
|
orderRef,
|
|
3128
3154
|
label: `discount ${object.metadata.discountId}`,
|
|
3129
3155
|
detail: `Discount ${object.metadata.discountId} was applied to this ` + 'order but no longer exists, so the redemption is uncounted ' + 'against its limit.'
|
|
@@ -3137,7 +3163,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3137
3163
|
var _object_metadata27;
|
|
3138
3164
|
const { hostId, orderId, productId } = (_object_metadata27 = object.metadata) != null ? _object_metadata27 : {};
|
|
3139
3165
|
if (hostId && orderId) {
|
|
3140
|
-
var
|
|
3166
|
+
var _ref57, _ref58, _ref59;
|
|
3141
3167
|
var _object_total_details, _object_total_details1;
|
|
3142
3168
|
const firestore = firebaseAdmin.app().firestore();
|
|
3143
3169
|
const hostRef = firestore.collection('hosts').doc(String(hostId));
|
|
@@ -3176,7 +3202,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3176
3202
|
//
|
|
3177
3203
|
// The whole map is written rather than one field of it, so a
|
|
3178
3204
|
// `merge`-set's nested-map merge and a plain replace agree.
|
|
3179
|
-
const shippingCents = Math.max(0, Math.round(Number((
|
|
3205
|
+
const shippingCents = Math.max(0, Math.round(Number((_ref57 = object == null ? void 0 : (_object_total_details = object.total_details) == null ? void 0 : _object_total_details.amount_shipping) != null ? _ref57 : 0) || 0));
|
|
3180
3206
|
// Tax joins shipping in the fold (AGL-1953). `draft-order.ts` now
|
|
3181
3207
|
// declares tax — a Stripe Tax Rate for a `manual` store, whose figure
|
|
3182
3208
|
// it already froze into `totals`, or `automatic_tax` for a `stripe`
|
|
@@ -3189,8 +3215,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3189
3215
|
// `amount_tax` 0 here (its own figure stays on the order, and its
|
|
3190
3216
|
// AGL-1953 witness is metadata, not this field), and a draft composed
|
|
3191
3217
|
// by a store with no tax reports 0 too.
|
|
3192
|
-
const stripeTaxCents = Math.max(0, Math.round(Number((
|
|
3193
|
-
const chargedTotalCents = Number((
|
|
3218
|
+
const stripeTaxCents = Math.max(0, Math.round(Number((_ref58 = object == null ? void 0 : (_object_total_details1 = object.total_details) == null ? void 0 : _object_total_details1.amount_tax) != null ? _ref58 : 0) || 0));
|
|
3219
|
+
const chargedTotalCents = Number((_ref59 = object == null ? void 0 : object.amount_total) != null ? _ref59 : NaN);
|
|
3194
3220
|
// `shipping_details` ONLY, unlike the cart branch's
|
|
3195
3221
|
// `?? customer_details` fallback: that address is the BILLING one, and
|
|
3196
3222
|
// a card sale rung up at a register completes here too — it must not
|
|
@@ -3203,8 +3229,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3203
3229
|
// the transaction commits.
|
|
3204
3230
|
let paidAfterCancel = false;
|
|
3205
3231
|
const flipped = await firestore.runTransaction(async (transaction)=>{
|
|
3206
|
-
var _snapshot_data, _ref, _ref1, _ref2, _ref3, _lifted_totals,
|
|
3207
|
-
var _object_metadata,
|
|
3232
|
+
var _snapshot_data, _snapshot_data1, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _lifted_totals, _ref6, _shipTo_name, _shipTo_address_line1, _shipTo_address_line2, _shipTo_address_city, _shipTo_address_state, _shipTo_address_postal_code, _shipTo_address_country;
|
|
3233
|
+
var _object_customer_details, _object_metadata, _object_customer_details1, _lifted_totals1;
|
|
3208
3234
|
const snapshot = await transaction.get(orderRef);
|
|
3209
3235
|
if (!snapshot.exists) return false;
|
|
3210
3236
|
const lifted = CommerceModel.liftLegacyOrder((_snapshot_data = snapshot.data()) != null ? _snapshot_data : {});
|
|
@@ -3241,7 +3267,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3241
3267
|
return false;
|
|
3242
3268
|
}
|
|
3243
3269
|
paidOrder = lifted;
|
|
3244
|
-
transaction.set(orderRef, _extends({
|
|
3270
|
+
transaction.set(orderRef, _extends({}, CommerceModel.orderListFields(_extends({}, (_snapshot_data1 = snapshot.data()) != null ? _snapshot_data1 : {}, {
|
|
3271
|
+
status: 'paid',
|
|
3272
|
+
customerEmail: (_ref = (_ref1 = object == null ? void 0 : (_object_customer_details = object.customer_details) == null ? void 0 : _object_customer_details.email) != null ? _ref1 : lifted.customerEmail) != null ? _ref : null
|
|
3273
|
+
}), orderRef.id), {
|
|
3245
3274
|
status: 'paid',
|
|
3246
3275
|
// WHICH TAX THIS ORDER CARRIED (AGL-2451), resolved from the
|
|
3247
3276
|
// session that actually charged it rather than from the draft's
|
|
@@ -3258,9 +3287,9 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3258
3287
|
// record that any of the charge was tax (AGL-1953). Without it
|
|
3259
3288
|
// every register card sale would stamp `none` beside an order
|
|
3260
3289
|
// plainly carrying tax.
|
|
3261
|
-
taxMode: storefrontTaxModeOf(object, Number((
|
|
3262
|
-
paymentIntentId: String((
|
|
3263
|
-
customerEmail: (
|
|
3290
|
+
taxMode: storefrontTaxModeOf(object, Number((_ref2 = object == null ? void 0 : (_object_metadata = object.metadata) == null ? void 0 : _object_metadata.taxCents) != null ? _ref2 : 0)),
|
|
3291
|
+
paymentIntentId: String((_ref3 = object == null ? void 0 : object.payment_intent) != null ? _ref3 : '') || null,
|
|
3292
|
+
customerEmail: (_ref4 = (_ref5 = object == null ? void 0 : (_object_customer_details1 = object.customer_details) == null ? void 0 : _object_customer_details1.email) != null ? _ref5 : lifted.customerEmail) != null ? _ref4 : null,
|
|
3264
3293
|
timeline: CommerceModel.appendOrderEvent(lifted, 'paid')
|
|
3265
3294
|
}, shippingCents > 0 || stripeTaxCents > 0 ? {
|
|
3266
3295
|
totals: _extends({}, (_lifted_totals = lifted.totals) != null ? _lifted_totals : {}, shippingCents > 0 ? {
|
|
@@ -3271,7 +3300,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3271
3300
|
// Stripe's own figure, for the AGL-1698 reason: the
|
|
3272
3301
|
// frozen total is what the draft was priced at, and only
|
|
3273
3302
|
// `amount_total` is the money that moved.
|
|
3274
|
-
totalCents: Number.isFinite(chargedTotalCents) ? chargedTotalCents : Number((
|
|
3303
|
+
totalCents: Number.isFinite(chargedTotalCents) ? chargedTotalCents : Number((_ref6 = (_lifted_totals1 = lifted.totals) == null ? void 0 : _lifted_totals1.totalCents) != null ? _ref6 : 0) + shippingCents
|
|
3275
3304
|
})
|
|
3276
3305
|
} : {}, (shipTo == null ? void 0 : shipTo.address) ? {
|
|
3277
3306
|
shippingAddress: {
|
|
@@ -3301,8 +3330,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3301
3330
|
});
|
|
3302
3331
|
}
|
|
3303
3332
|
if (flipped) {
|
|
3304
|
-
var
|
|
3305
|
-
var _object_metadata28,
|
|
3333
|
+
var _ref60, _ref61;
|
|
3334
|
+
var _object_metadata28, _object_customer_details15;
|
|
3306
3335
|
const order = paidOrder;
|
|
3307
3336
|
// Discounts engine redemptions (AGL-305), for this branch's BOTH
|
|
3308
3337
|
// tenants: a console draft order and a POS card sale, which carry the
|
|
@@ -3317,12 +3346,12 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3317
3346
|
// the hold existed, which Stripe's at-least-once delivery would run
|
|
3318
3347
|
// twice. The transition is what makes it once.
|
|
3319
3348
|
if ((_object_metadata28 = object.metadata) == null ? void 0 : _object_metadata28.discountId) {
|
|
3320
|
-
var
|
|
3349
|
+
var _ref62;
|
|
3321
3350
|
var _object_metadata29;
|
|
3322
3351
|
await settleRedemption({
|
|
3323
3352
|
firestore,
|
|
3324
3353
|
ref: hostRef.collection('discounts').doc(String(object.metadata.discountId)),
|
|
3325
|
-
holdKey: String((
|
|
3354
|
+
holdKey: String((_ref62 = (_object_metadata29 = object.metadata) == null ? void 0 : _object_metadata29.discountHoldKey) != null ? _ref62 : ''),
|
|
3326
3355
|
orderRef,
|
|
3327
3356
|
label: `discount ${object.metadata.discountId}`,
|
|
3328
3357
|
detail: `Discount ${object.metadata.discountId} was applied to this ` + 'order but no longer exists, so the redemption is uncounted ' + 'against its limit.'
|
|
@@ -3345,15 +3374,15 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3345
3374
|
// figure the draft was priced at, and the two agree by construction,
|
|
3346
3375
|
// but only one of them is the money that moved. Stored totals remain
|
|
3347
3376
|
// the fallback for a session shape that reports no total.
|
|
3348
|
-
const draftEmail = (
|
|
3377
|
+
const draftEmail = (_ref60 = (_ref61 = object == null ? void 0 : (_object_customer_details15 = object.customer_details) == null ? void 0 : _object_customer_details15.email) != null ? _ref61 : order.customerEmail) != null ? _ref60 : null;
|
|
3349
3378
|
if (draftEmail) {
|
|
3350
|
-
var
|
|
3351
|
-
var _order_totals,
|
|
3352
|
-
const chargedCents = Number((
|
|
3379
|
+
var _ref63, _ref64, _ref65;
|
|
3380
|
+
var _order_totals, _object_customer_details16;
|
|
3381
|
+
const chargedCents = Number((_ref63 = object == null ? void 0 : object.amount_total) != null ? _ref63 : 0) || Number((_ref64 = (_order_totals = order.totals) == null ? void 0 : _order_totals.totalCents) != null ? _ref64 : 0);
|
|
3353
3382
|
await captureHostContact(_extends({
|
|
3354
3383
|
hostId: String(hostId),
|
|
3355
3384
|
email: draftEmail,
|
|
3356
|
-
name: (
|
|
3385
|
+
name: (_ref65 = object == null ? void 0 : (_object_customer_details16 = object.customer_details) == null ? void 0 : _object_customer_details16.name) != null ? _ref65 : undefined,
|
|
3357
3386
|
source: 'order',
|
|
3358
3387
|
initialLifecycleStage: 'customer'
|
|
3359
3388
|
}, chargedCents > 0 ? {
|
|
@@ -3366,15 +3395,15 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3366
3395
|
}));
|
|
3367
3396
|
}
|
|
3368
3397
|
if (productId) {
|
|
3369
|
-
var _productSnapshot_data,
|
|
3398
|
+
var _productSnapshot_data, _ref66, _ref67;
|
|
3370
3399
|
var _object_metadata30, _lifted_variants_, _order_lineItems_, _order_lineItems;
|
|
3371
3400
|
const productRef = hostRef.collection('products').doc(String(productId));
|
|
3372
3401
|
const productSnapshot = await productRef.get();
|
|
3373
3402
|
const lifted = CommerceModel.liftLegacyProduct((_productSnapshot_data = productSnapshot.data()) != null ? _productSnapshot_data : {
|
|
3374
3403
|
name: 'Product'
|
|
3375
3404
|
});
|
|
3376
|
-
const soldVariantId = String((
|
|
3377
|
-
const quantity = (
|
|
3405
|
+
const soldVariantId = String((_ref66 = (_object_metadata30 = object.metadata) == null ? void 0 : _object_metadata30.variantId) != null ? _ref66 : '') || ((_lifted_variants_ = lifted.variants[0]) == null ? void 0 : _lifted_variants_.id);
|
|
3406
|
+
const quantity = (_ref67 = (_order_lineItems = order.lineItems) == null ? void 0 : (_order_lineItems_ = _order_lineItems[0]) == null ? void 0 : _order_lineItems_.quantity) != null ? _ref67 : 1;
|
|
3378
3407
|
if (soldVariantId) {
|
|
3379
3408
|
// Atomic since AGL-2320.
|
|
3380
3409
|
const moved = await decrementVariantStock({
|
|
@@ -3426,10 +3455,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3426
3455
|
// would decrement it twice.
|
|
3427
3456
|
const paidProducts = new Map();
|
|
3428
3457
|
for (const line of (_order_lineItems1 = order.lineItems) != null ? _order_lineItems1 : []){
|
|
3429
|
-
var
|
|
3458
|
+
var _ref68, _ref69, _line_variantId1;
|
|
3430
3459
|
var _lineProduct_variants_;
|
|
3431
|
-
const lineProductId = String((
|
|
3432
|
-
const soldQty = Math.round(Number((
|
|
3460
|
+
const lineProductId = String((_ref68 = line == null ? void 0 : line.productId) != null ? _ref68 : '');
|
|
3461
|
+
const soldQty = Math.round(Number((_ref69 = line == null ? void 0 : line.quantity) != null ? _ref69 : 0));
|
|
3433
3462
|
if (!lineProductId || !(soldQty > 0)) continue;
|
|
3434
3463
|
// Firestore reserves `__…__` ids and `.doc()` throws
|
|
3435
3464
|
// synchronously on one; a corrupt line must not fail the
|
|
@@ -3492,8 +3521,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3492
3521
|
var _object_metadata31;
|
|
3493
3522
|
const { hostId, productId, feeCents, couponCode } = (_object_metadata31 = object.metadata) != null ? _object_metadata31 : {};
|
|
3494
3523
|
if (hostId && productId) {
|
|
3495
|
-
var
|
|
3496
|
-
var _object_metadata32, _buyNowLineItems_,
|
|
3524
|
+
var _ref70, _productForSnapshot_get1, _productForSnapshot_data1, _ref71, _ref72, _ref73, _ref74, _ref75, _ref76, _ref77;
|
|
3525
|
+
var _object_metadata32, _buyNowLineItems_, _object_customer_details17, _object_customer_details18, _object_customer_details19, _object_metadata33;
|
|
3497
3526
|
const firestore = firebaseAdmin.app().firestore();
|
|
3498
3527
|
const hostRef = firestore.collection('hosts').doc(String(hostId));
|
|
3499
3528
|
// Orders v1 (AGL-283): line-item snapshot + totals + timeline with
|
|
@@ -3503,7 +3532,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3503
3532
|
// is bounded to Stripe's at-least-once edge).
|
|
3504
3533
|
const orderRef = hostRef.collection('orders').doc(String(object.id));
|
|
3505
3534
|
const counterRef = hostRef.collection('counters').doc('orders');
|
|
3506
|
-
const amountCents = Number((
|
|
3535
|
+
const amountCents = Number((_ref70 = object == null ? void 0 : object.amount_total) != null ? _ref70 : 0);
|
|
3507
3536
|
const productForSnapshot = await hostRef.collection('products').doc(String(productId)).get();
|
|
3508
3537
|
const snapshotName = String((_productForSnapshot_get1 = productForSnapshot.get('name')) != null ? _productForSnapshot_get1 : 'Product');
|
|
3509
3538
|
// AGL-1711: the line item and totals used to be fabricated from
|
|
@@ -3516,7 +3545,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3516
3545
|
name: snapshotName
|
|
3517
3546
|
});
|
|
3518
3547
|
const soldVariant = ((_object_metadata32 = object.metadata) == null ? void 0 : _object_metadata32.variantId) ? liftedForSnapshot.variants.find((item)=>item.id === String(object.metadata.variantId)) : liftedForSnapshot.variants[0];
|
|
3519
|
-
const variantOptions = Object.values((
|
|
3548
|
+
const variantOptions = Object.values((_ref71 = soldVariant == null ? void 0 : soldVariant.options) != null ? _ref71 : {});
|
|
3520
3549
|
const { lineItems: buyNowLineItems, totals: buyNowTotals } = CommerceModel.computeBuyNowOrder(object, _extends({
|
|
3521
3550
|
name: snapshotName
|
|
3522
3551
|
}, variantOptions.length ? {
|
|
@@ -3528,7 +3557,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3528
3557
|
} : {}, liftedForSnapshot.supplierId ? {
|
|
3529
3558
|
supplierId: liftedForSnapshot.supplierId
|
|
3530
3559
|
} : {}));
|
|
3531
|
-
const soldQuantity = (
|
|
3560
|
+
const soldQuantity = (_ref72 = (_buyNowLineItems_ = buyNowLineItems[0]) == null ? void 0 : _buyNowLineItems_.quantity) != null ? _ref72 : 1;
|
|
3532
3561
|
const created = await firestore.runTransaction(async (transaction)=>{
|
|
3533
3562
|
var _counter_get, _ref, _ref1, _ref2, _ref3;
|
|
3534
3563
|
var _object_metadata, _object_customer_details, _object_customer_details1;
|
|
@@ -3543,7 +3572,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3543
3572
|
}, {
|
|
3544
3573
|
merge: true
|
|
3545
3574
|
});
|
|
3546
|
-
|
|
3575
|
+
// With the fields the orders list queries by (AGL-3321).
|
|
3576
|
+
transaction.set(orderRef, CommerceModel.withOrderListFields(orderRef.id, _extends({
|
|
3547
3577
|
number,
|
|
3548
3578
|
status: 'paid',
|
|
3549
3579
|
channel: 'online',
|
|
@@ -3577,7 +3607,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3577
3607
|
couponCode
|
|
3578
3608
|
} : {}, {
|
|
3579
3609
|
createdAt: firebaseAdmin.firestore.FieldValue.serverTimestamp()
|
|
3580
|
-
}));
|
|
3610
|
+
})));
|
|
3581
3611
|
return true;
|
|
3582
3612
|
});
|
|
3583
3613
|
// Redelivery guard (AGL-498): skip the notification + fulfilment side
|
|
@@ -3587,8 +3617,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3587
3617
|
// in the bell, not just the owner's email.
|
|
3588
3618
|
void notifyHostManagers(String(hostId), _extends({
|
|
3589
3619
|
type: 'content.order',
|
|
3590
|
-
title: `New order — $${(Number((
|
|
3591
|
-
}, (object == null ? void 0 : (
|
|
3620
|
+
title: `New order — $${(Number((_ref73 = object == null ? void 0 : object.amount_total) != null ? _ref73 : 0) / 100).toFixed(2)}`
|
|
3621
|
+
}, (object == null ? void 0 : (_object_customer_details17 = object.customer_details) == null ? void 0 : _object_customer_details17.email) ? {
|
|
3592
3622
|
body: `From ${object.customer_details.email}`
|
|
3593
3623
|
} : {}, {
|
|
3594
3624
|
link: `/${hostId}/products`
|
|
@@ -3679,7 +3709,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3679
3709
|
fromName: (await brandFor(hostId)).fromName,
|
|
3680
3710
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
3681
3711
|
audience: 'tenant',
|
|
3682
|
-
context: 'dropship supplier notice'
|
|
3712
|
+
context: 'dropship supplier notice',
|
|
3713
|
+
// Owed to the recipient by their own order: the phishing
|
|
3714
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
3715
|
+
owedFor: 'order'
|
|
3683
3716
|
});
|
|
3684
3717
|
// Cost meter (AGL-1438). Transactional: without it the order is
|
|
3685
3718
|
// never fulfilled.
|
|
@@ -3692,14 +3725,14 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3692
3725
|
// Contacts ingestion (AGL-197): buyers become contacts.
|
|
3693
3726
|
await captureHostContact({
|
|
3694
3727
|
hostId: String(hostId),
|
|
3695
|
-
email: object == null ? void 0 : (
|
|
3696
|
-
name: (
|
|
3728
|
+
email: object == null ? void 0 : (_object_customer_details18 = object.customer_details) == null ? void 0 : _object_customer_details18.email,
|
|
3729
|
+
name: (_ref74 = object == null ? void 0 : (_object_customer_details19 = object.customer_details) == null ? void 0 : _object_customer_details19.name) != null ? _ref74 : undefined,
|
|
3697
3730
|
source: 'order',
|
|
3698
3731
|
initialLifecycleStage: 'customer',
|
|
3699
|
-
purchaseCents: Number((
|
|
3732
|
+
purchaseCents: Number((_ref75 = object == null ? void 0 : object.amount_total) != null ? _ref75 : 0),
|
|
3700
3733
|
interaction: {
|
|
3701
3734
|
refId: String(object.id),
|
|
3702
|
-
summary: `Placed an order ($${(Number((
|
|
3735
|
+
summary: `Placed an order ($${(Number((_ref76 = object == null ? void 0 : object.amount_total) != null ? _ref76 : 0) / 100).toFixed(2)})`
|
|
3703
3736
|
}
|
|
3704
3737
|
});
|
|
3705
3738
|
const productRef = hostRef.collection('products').doc(String(productId));
|
|
@@ -3717,12 +3750,12 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3717
3750
|
// serialize; the snapshot above is still read, for the product NAME on
|
|
3718
3751
|
// the receipt below, and no longer decides any count.
|
|
3719
3752
|
{
|
|
3720
|
-
var _productSnapshot_data2,
|
|
3753
|
+
var _productSnapshot_data2, _ref78;
|
|
3721
3754
|
var _object_metadata34, _lifted_variants_1;
|
|
3722
3755
|
const lifted = CommerceModel.liftLegacyProduct((_productSnapshot_data2 = productSnapshot.data()) != null ? _productSnapshot_data2 : {
|
|
3723
3756
|
name: 'Product'
|
|
3724
3757
|
});
|
|
3725
|
-
const soldVariantId = String((
|
|
3758
|
+
const soldVariantId = String((_ref78 = (_object_metadata34 = object.metadata) == null ? void 0 : _object_metadata34.variantId) != null ? _ref78 : '') || ((_lifted_variants_1 = lifted.variants[0]) == null ? void 0 : _lifted_variants_1.id);
|
|
3726
3759
|
if (soldVariantId) {
|
|
3727
3760
|
// AGL-1711: `-1` regardless of how many units were bought, so a
|
|
3728
3761
|
// 3-unit buy-now sale decremented stock by one and the difference
|
|
@@ -3753,14 +3786,14 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3753
3786
|
// Settlement, the same way round and for the same reason as the cart
|
|
3754
3787
|
// branch above (AGL-2356): the decrement lands first, then the
|
|
3755
3788
|
// reservation is dropped.
|
|
3756
|
-
await releaseStockHold(hostRef, String((
|
|
3789
|
+
await releaseStockHold(hostRef, String((_ref77 = (_object_metadata33 = object.metadata) == null ? void 0 : _object_metadata33.stockHoldKey) != null ? _ref77 : ''));
|
|
3757
3790
|
if (couponCode) {
|
|
3758
|
-
var
|
|
3791
|
+
var _ref79;
|
|
3759
3792
|
var _object_metadata35;
|
|
3760
3793
|
await settleRedemption({
|
|
3761
3794
|
firestore,
|
|
3762
3795
|
ref: hostRef.collection('coupons').doc(String(couponCode)),
|
|
3763
|
-
holdKey: String((
|
|
3796
|
+
holdKey: String((_ref79 = (_object_metadata35 = object.metadata) == null ? void 0 : _object_metadata35.couponHoldKey) != null ? _ref79 : ''),
|
|
3764
3797
|
orderRef,
|
|
3765
3798
|
label: `coupon ${couponCode}`,
|
|
3766
3799
|
detail: `Coupon ${couponCode} was applied to this order but no longer ` + 'exists, so the redemption is uncounted against its limit.'
|
|
@@ -3769,14 +3802,14 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3769
3802
|
// Receipt + seller notification (AGL-96): env-gated like every
|
|
3770
3803
|
// other outbound email; failures never fail the webhook.
|
|
3771
3804
|
if (isEmailConfigured()) {
|
|
3772
|
-
var _productSnapshot_get,
|
|
3773
|
-
var
|
|
3805
|
+
var _productSnapshot_get, _ref80;
|
|
3806
|
+
var _object_customer_details20, _org, _this3;
|
|
3774
3807
|
const productName = String((_productSnapshot_get = productSnapshot.get('name')) != null ? _productSnapshot_get : 'your purchase');
|
|
3775
|
-
const amount = (Number((
|
|
3776
|
-
const buyerEmail = object == null ? void 0 : (
|
|
3808
|
+
const amount = (Number((_ref80 = object == null ? void 0 : object.amount_total) != null ? _ref80 : 0) / 100).toFixed(2);
|
|
3809
|
+
const buyerEmail = object == null ? void 0 : (_object_customer_details20 = object.customer_details) == null ? void 0 : _object_customer_details20.email;
|
|
3777
3810
|
const orderTotal = `$${amount}`;
|
|
3778
3811
|
if (buyerEmail) {
|
|
3779
|
-
var
|
|
3812
|
+
var _ref81;
|
|
3780
3813
|
const fallbackText = `Thanks for your purchase!\n\n${productName} — $${amount}` + `\nOrder reference: ${object.id}`;
|
|
3781
3814
|
// Site-owner-designed template when published (AGL-771).
|
|
3782
3815
|
const designed = await renderHostEmailWithTokens(firebaseAdmin.app().firestore(), String(hostId), 'order-receipt', {
|
|
@@ -3786,7 +3819,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3786
3819
|
});
|
|
3787
3820
|
await sendEmail(_extends({
|
|
3788
3821
|
to: String(buyerEmail),
|
|
3789
|
-
subject: (
|
|
3822
|
+
subject: (_ref81 = designed == null ? void 0 : designed.subject) != null ? _ref81 : `Receipt: ${productName}`,
|
|
3790
3823
|
text: (designed == null ? void 0 : designed.text) || fallbackText
|
|
3791
3824
|
}, (designed == null ? void 0 : designed.html) ? {
|
|
3792
3825
|
html: designed.html
|
|
@@ -3794,7 +3827,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3794
3827
|
fromName: (await brandFor(hostId)).fromName,
|
|
3795
3828
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
3796
3829
|
audience: 'tenant',
|
|
3797
|
-
context: 'receipt'
|
|
3830
|
+
context: 'receipt',
|
|
3831
|
+
// Owed to the recipient by their own order: the phishing
|
|
3832
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
3833
|
+
owedFor: 'order'
|
|
3798
3834
|
}));
|
|
3799
3835
|
// Cost meter (AGL-1438). Transactional, as the cart receipt above.
|
|
3800
3836
|
await meterHostEmail(String(hostId));
|
|
@@ -3817,7 +3853,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3817
3853
|
// SSO.
|
|
3818
3854
|
const seller = (_this4 = await findUserByUidAcrossPools(sellerUid).catch(()=>null)) == null ? void 0 : _this4.record;
|
|
3819
3855
|
if (seller == null ? void 0 : seller.email) {
|
|
3820
|
-
var _hostSnapshot_get,
|
|
3856
|
+
var _hostSnapshot_get, _ref82;
|
|
3821
3857
|
const siteName = String((_hostSnapshot_get = hostSnapshot.get('displayName')) != null ? _hostSnapshot_get : hostId);
|
|
3822
3858
|
const fallbackText = `You made a sale on ${siteName}!\n\n${productName} — $${amount}` + (buyerEmail ? `\nBuyer: ${buyerEmail}` : '') + `\nOrder reference: ${object.id}`;
|
|
3823
3859
|
// Site-owner-designed template when published (AGL-771).
|
|
@@ -3830,7 +3866,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3830
3866
|
});
|
|
3831
3867
|
await sendEmail(_extends({
|
|
3832
3868
|
to: seller.email,
|
|
3833
|
-
subject: (
|
|
3869
|
+
subject: (_ref82 = designed == null ? void 0 : designed.subject) != null ? _ref82 : `New order: ${productName}`,
|
|
3834
3870
|
text: (designed == null ? void 0 : designed.text) || fallbackText
|
|
3835
3871
|
}, (designed == null ? void 0 : designed.html) ? {
|
|
3836
3872
|
html: designed.html
|
|
@@ -3838,7 +3874,10 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3838
3874
|
fromName: (await brandFor(hostId)).fromName,
|
|
3839
3875
|
sendingIdentity: await hostSendingIdentity(String(hostId)),
|
|
3840
3876
|
audience: 'tenant',
|
|
3841
|
-
context: 'seller order notice'
|
|
3877
|
+
context: 'seller order notice',
|
|
3878
|
+
// Owed to the recipient by their own order: the phishing
|
|
3879
|
+
// screen's soft rules never hold it (AGL-3356).
|
|
3880
|
+
owedFor: 'order'
|
|
3842
3881
|
}));
|
|
3843
3882
|
// Cost meter (AGL-1438). Transactional: the seller learns about
|
|
3844
3883
|
// the order here.
|
|
@@ -3848,6 +3887,45 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3848
3887
|
}
|
|
3849
3888
|
}
|
|
3850
3889
|
}
|
|
3890
|
+
// Fraud signals on a store's sale (AGL-3360): an issuer's early fraud
|
|
3891
|
+
// warning and a Radar review. The merchant decides what to do for their
|
|
3892
|
+
// own customer, so the signal lands on the ORDER — a timeline line and the
|
|
3893
|
+
// shared `paymentRisk` chip — and the site's managers are told once.
|
|
3894
|
+
// Nothing is refunded or canceled. Found by the same payment-intent join a
|
|
3895
|
+
// dispute uses; a signal on anything else is not commerce's and stays
|
|
3896
|
+
// silent here (the platform route and the other plugins answer it).
|
|
3897
|
+
// Disputes keep their own branch below, which has always told the
|
|
3898
|
+
// merchant; both report the site so the seller's fraud ledger can name it.
|
|
3899
|
+
const risk = paymentRiskEventFrom(type, object);
|
|
3900
|
+
if (risk && risk.signal.kind !== 'dispute') {
|
|
3901
|
+
var _ref83, _snapshot_data;
|
|
3902
|
+
var _snapshot_ref_parent_parent;
|
|
3903
|
+
const lookup = risk.paymentIntentId ? await findOrderForDispute(risk.paymentIntentId) : {
|
|
3904
|
+
kind: 'not-ours'
|
|
3905
|
+
};
|
|
3906
|
+
if (lookup.kind !== 'order') return;
|
|
3907
|
+
const snapshot = lookup.snapshot;
|
|
3908
|
+
const hostId = String((_ref83 = (_snapshot_ref_parent_parent = snapshot.ref.parent.parent) == null ? void 0 : _snapshot_ref_parent_parent.id) != null ? _ref83 : '');
|
|
3909
|
+
const order = CommerceModel.liftLegacyOrder((_snapshot_data = snapshot.data()) != null ? _snapshot_data : {});
|
|
3910
|
+
await recordPaymentRiskOnRecord({
|
|
3911
|
+
ref: snapshot.ref,
|
|
3912
|
+
signal: risk.signal,
|
|
3913
|
+
hostId,
|
|
3914
|
+
subjectLabel: `Order ${CommerceModel.formatOrderNumber(order, snapshot.id)}`,
|
|
3915
|
+
link: `/${hostId}/orders`,
|
|
3916
|
+
notificationType: 'content.order',
|
|
3917
|
+
extraUpdate: (data)=>({
|
|
3918
|
+
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)
|
|
3919
|
+
})
|
|
3920
|
+
}, {
|
|
3921
|
+
firestore: firebaseAdmin.app().firestore(),
|
|
3922
|
+
notify: notifyHostManagers
|
|
3923
|
+
});
|
|
3924
|
+
return {
|
|
3925
|
+
claimed: true,
|
|
3926
|
+
hostId
|
|
3927
|
+
};
|
|
3928
|
+
}
|
|
3851
3929
|
// Card disputes against a merchant's store (AGL-1787).
|
|
3852
3930
|
//
|
|
3853
3931
|
// Commerce subscribed no `charge.dispute.*` event at all, so a shopper
|
|
@@ -3873,7 +3951,8 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3873
3951
|
// finds). AGL-1554 will add its own `closed` branch for the marketplace
|
|
3874
3952
|
// side; the two coexist because each self-selects by finding its own record.
|
|
3875
3953
|
if (type === 'charge.dispute.created' || type === 'charge.dispute.closed') {
|
|
3876
|
-
var _dispute_payment_intent;
|
|
3954
|
+
var _dispute_payment_intent, _ref84;
|
|
3955
|
+
var _snapshot_ref_parent_parent1;
|
|
3877
3956
|
const dispute = object != null ? object : {};
|
|
3878
3957
|
const paymentIntentId = String((_dispute_payment_intent = dispute.payment_intent) != null ? _dispute_payment_intent : '');
|
|
3879
3958
|
const lookup = paymentIntentId ? await findOrderForDispute(paymentIntentId) : {
|
|
@@ -3898,9 +3977,9 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3898
3977
|
const claimed = lookup.kind === 'order' || lookup.kind === 'unresolved';
|
|
3899
3978
|
const snapshot = lookup.kind === 'order' ? lookup.snapshot : null;
|
|
3900
3979
|
if (snapshot) {
|
|
3901
|
-
var
|
|
3902
|
-
var
|
|
3903
|
-
const hostId = String((
|
|
3980
|
+
var _ref85;
|
|
3981
|
+
var _snapshot_ref_parent_parent2;
|
|
3982
|
+
const hostId = String((_ref85 = (_snapshot_ref_parent_parent2 = snapshot.ref.parent.parent) == null ? void 0 : _snapshot_ref_parent_parent2.id) != null ? _ref85 : '');
|
|
3904
3983
|
if (type === 'charge.dispute.created') {
|
|
3905
3984
|
const { opened, record } = await recordDisputeOpened(snapshot, dispute);
|
|
3906
3985
|
if (opened && hostId) {
|
|
@@ -3917,7 +3996,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3917
3996
|
});
|
|
3918
3997
|
}
|
|
3919
3998
|
} else {
|
|
3920
|
-
var
|
|
3999
|
+
var _ref86;
|
|
3921
4000
|
const settled = await recordDisputeClosed(snapshot, dispute);
|
|
3922
4001
|
if (settled.recorded && hostId) {
|
|
3923
4002
|
await notifyHostManagers(hostId, {
|
|
@@ -3975,7 +4054,7 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
3975
4054
|
// transiently-failed reversal gets its retry — and gated inside on
|
|
3976
4055
|
// the order's own `reversedTransferCents` marker, so it runs at most
|
|
3977
4056
|
// once per dispute however many times Stripe delivers.
|
|
3978
|
-
if (String((
|
|
4057
|
+
if (String((_ref86 = dispute == null ? void 0 : dispute.status) != null ? _ref86 : '') === 'lost') {
|
|
3979
4058
|
const pulledBackCents = await reverseSellerShare(snapshot.ref, dispute);
|
|
3980
4059
|
// The merchant-experience half of the AGL-1794 decision, and not an
|
|
3981
4060
|
// optional extra: the reversal takes money out of the connected
|
|
@@ -4002,9 +4081,11 @@ async function findOrderForDispute(paymentIntentId) {
|
|
|
4002
4081
|
}
|
|
4003
4082
|
}
|
|
4004
4083
|
}
|
|
4005
|
-
return {
|
|
4084
|
+
return _extends({
|
|
4006
4085
|
claimed
|
|
4007
|
-
}
|
|
4086
|
+
}, snapshot ? {
|
|
4087
|
+
hostId: String((_ref84 = (_snapshot_ref_parent_parent1 = snapshot.ref.parent.parent) == null ? void 0 : _snapshot_ref_parent_parent1.id) != null ? _ref84 : '')
|
|
4088
|
+
} : {});
|
|
4008
4089
|
}
|
|
4009
4090
|
};
|
|
4010
4091
|
|