@final-commerce/command-frame 0.11.1-online.1 → 0.12.0-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommonTypes.d.ts +1 -21
- package/dist/actions/get-current-cart/mock.js +0 -3
- package/dist/actions/get-current-cart/types.d.ts +0 -6
- package/dist/actions/get-orders/action.d.ts +1 -1
- package/dist/actions/get-orders/action.js +2 -2
- package/dist/actions/get-orders/mock.d.ts +1 -1
- package/dist/actions/get-orders/mock.js +19 -74
- package/dist/actions/get-orders/types.d.ts +2 -33
- package/dist/actions/get-outlets/action.js +2 -2
- package/dist/actions/get-outlets/mock.d.ts +0 -12
- package/dist/actions/get-outlets/mock.js +4 -28
- package/dist/actions/get-outlets/types.d.ts +1 -19
- package/dist/actions/get-product-modifier-selections/mock.js +0 -7
- package/dist/actions/get-product-modifier-selections/types.d.ts +0 -4
- package/dist/actions/get-products/types.d.ts +8 -8
- package/dist/actions/get-refund-plan/mockRows.js +1 -1
- package/dist/actions/get-refund-plan/types.d.ts +6 -9
- package/dist/actions/get-remaining-refundable-quantities/mock.js +0 -1
- package/dist/actions/get-remaining-refundable-quantities/types.d.ts +0 -5
- package/dist/actions/process-partial-refund/types.d.ts +1 -1
- package/dist/actions/resume-parked-order/mock.d.ts +0 -5
- package/dist/actions/resume-parked-order/mock.js +24 -25
- package/dist/actions/void-order/mock.js +7 -17
- package/dist/actions/void-order/types.d.ts +2 -6
- package/dist/common-types/order-state.d.ts +1 -20
- package/dist/demo/database.d.ts +0 -4
- package/dist/demo/database.js +0 -29
- package/dist/index.d.ts +1 -41
- package/dist/index.js +0 -39
- package/dist/projects/render/mocks.js +0 -40
- package/dist/projects/render/types.d.ts +1 -33
- package/dist/pubsub/topics/index.d.ts +17 -18
- package/dist/pubsub/topics/index.js +17 -18
- package/dist/pubsub/topics/types.d.ts +0 -8
- package/package.json +2 -2
- package/dist/actions/assign-order-user/action.d.ts +0 -6
- package/dist/actions/assign-order-user/action.js +0 -8
- package/dist/actions/assign-order-user/mock.d.ts +0 -2
- package/dist/actions/assign-order-user/mock.js +0 -30
- package/dist/actions/assign-order-user/types.d.ts +0 -15
- package/dist/actions/assign-order-user/types.js +0 -1
- package/dist/actions/attach-checkout-contact/action.d.ts +0 -6
- package/dist/actions/attach-checkout-contact/action.js +0 -8
- package/dist/actions/attach-checkout-contact/mock.d.ts +0 -15
- package/dist/actions/attach-checkout-contact/mock.js +0 -22
- package/dist/actions/attach-checkout-contact/types.d.ts +0 -35
- package/dist/actions/attach-checkout-contact/types.js +0 -16
- package/dist/actions/get-address-options/action.d.ts +0 -6
- package/dist/actions/get-address-options/action.js +0 -8
- package/dist/actions/get-address-options/mock.d.ts +0 -3
- package/dist/actions/get-address-options/mock.js +0 -15
- package/dist/actions/get-address-options/types.d.ts +0 -25
- package/dist/actions/get-address-options/types.js +0 -8
- package/dist/actions/get-checkout-status/action.d.ts +0 -6
- package/dist/actions/get-checkout-status/action.js +0 -8
- package/dist/actions/get-checkout-status/mock.d.ts +0 -3
- package/dist/actions/get-checkout-status/mock.js +0 -11
- package/dist/actions/get-checkout-status/types.d.ts +0 -20
- package/dist/actions/get-checkout-status/types.js +0 -12
- package/dist/actions/get-moto-config/action.d.ts +0 -6
- package/dist/actions/get-moto-config/action.js +0 -8
- package/dist/actions/get-moto-config/mock.d.ts +0 -7
- package/dist/actions/get-moto-config/mock.js +0 -9
- package/dist/actions/get-moto-config/types.d.ts +0 -34
- package/dist/actions/get-moto-config/types.js +0 -5
- package/dist/actions/get-order-statuses/action.d.ts +0 -6
- package/dist/actions/get-order-statuses/action.js +0 -8
- package/dist/actions/get-order-statuses/mock.d.ts +0 -2
- package/dist/actions/get-order-statuses/mock.js +0 -5
- package/dist/actions/get-order-statuses/types.d.ts +0 -8
- package/dist/actions/get-order-statuses/types.js +0 -1
- package/dist/actions/get-shipping-options/action.d.ts +0 -6
- package/dist/actions/get-shipping-options/action.js +0 -8
- package/dist/actions/get-shipping-options/mock.d.ts +0 -3
- package/dist/actions/get-shipping-options/mock.js +0 -15
- package/dist/actions/get-shipping-options/types.d.ts +0 -43
- package/dist/actions/get-shipping-options/types.js +0 -1
- package/dist/actions/record-external-payment/action.d.ts +0 -6
- package/dist/actions/record-external-payment/action.js +0 -8
- package/dist/actions/record-external-payment/mock.d.ts +0 -2
- package/dist/actions/record-external-payment/mock.js +0 -36
- package/dist/actions/record-external-payment/types.d.ts +0 -37
- package/dist/actions/record-external-payment/types.js +0 -1
- package/dist/actions/release-from-cart/action.d.ts +0 -6
- package/dist/actions/release-from-cart/action.js +0 -8
- package/dist/actions/release-from-cart/mock.d.ts +0 -2
- package/dist/actions/release-from-cart/mock.js +0 -26
- package/dist/actions/release-from-cart/types.d.ts +0 -8
- package/dist/actions/release-from-cart/types.js +0 -1
- package/dist/actions/resume-checkout/action.d.ts +0 -6
- package/dist/actions/resume-checkout/action.js +0 -8
- package/dist/actions/resume-checkout/mock.d.ts +0 -16
- package/dist/actions/resume-checkout/mock.js +0 -51
- package/dist/actions/resume-checkout/types.d.ts +0 -59
- package/dist/actions/resume-checkout/types.js +0 -13
- package/dist/actions/resume-order/action.d.ts +0 -6
- package/dist/actions/resume-order/action.js +0 -8
- package/dist/actions/resume-order/mock.d.ts +0 -2
- package/dist/actions/resume-order/mock.js +0 -55
- package/dist/actions/resume-order/types.d.ts +0 -17
- package/dist/actions/resume-order/types.js +0 -1
- package/dist/actions/select-shipping-option/action.d.ts +0 -6
- package/dist/actions/select-shipping-option/action.js +0 -8
- package/dist/actions/select-shipping-option/mock.d.ts +0 -3
- package/dist/actions/select-shipping-option/mock.js +0 -31
- package/dist/actions/select-shipping-option/types.d.ts +0 -15
- package/dist/actions/select-shipping-option/types.js +0 -1
- package/dist/actions/set-order-address/action.d.ts +0 -6
- package/dist/actions/set-order-address/action.js +0 -8
- package/dist/actions/set-order-address/mock.d.ts +0 -7
- package/dist/actions/set-order-address/mock.js +0 -29
- package/dist/actions/set-order-address/types.d.ts +0 -19
- package/dist/actions/set-order-address/types.js +0 -1
- package/dist/actions/set-order-metadata/action.d.ts +0 -6
- package/dist/actions/set-order-metadata/action.js +0 -8
- package/dist/actions/set-order-metadata/mock.d.ts +0 -5
- package/dist/actions/set-order-metadata/mock.js +0 -38
- package/dist/actions/set-order-metadata/types.d.ts +0 -20
- package/dist/actions/set-order-metadata/types.js +0 -1
- package/dist/actions/set-order-status/action.d.ts +0 -6
- package/dist/actions/set-order-status/action.js +0 -8
- package/dist/actions/set-order-status/mock.d.ts +0 -3
- package/dist/actions/set-order-status/mock.js +0 -44
- package/dist/actions/set-order-status/types.d.ts +0 -25
- package/dist/actions/set-order-status/types.js +0 -1
- package/dist/actions/set-order-type/action.d.ts +0 -6
- package/dist/actions/set-order-type/action.js +0 -8
- package/dist/actions/set-order-type/mock.d.ts +0 -3
- package/dist/actions/set-order-type/mock.js +0 -27
- package/dist/actions/set-order-type/types.d.ts +0 -17
- package/dist/actions/set-order-type/types.js +0 -1
- package/dist/actions/set-outlet/action.d.ts +0 -6
- package/dist/actions/set-outlet/action.js +0 -8
- package/dist/actions/set-outlet/mock.d.ts +0 -13
- package/dist/actions/set-outlet/mock.js +0 -24
- package/dist/actions/set-outlet/types.d.ts +0 -31
- package/dist/actions/set-outlet/types.js +0 -21
- package/dist/actions/set-scheduled-for/action.d.ts +0 -6
- package/dist/actions/set-scheduled-for/action.js +0 -8
- package/dist/actions/set-scheduled-for/mock.d.ts +0 -4
- package/dist/actions/set-scheduled-for/mock.js +0 -45
- package/dist/actions/set-scheduled-for/types.d.ts +0 -22
- package/dist/actions/set-scheduled-for/types.js +0 -1
- package/dist/actions/start-checkout/action.d.ts +0 -6
- package/dist/actions/start-checkout/action.js +0 -8
- package/dist/actions/start-checkout/mock.d.ts +0 -16
- package/dist/actions/start-checkout/mock.js +0 -80
- package/dist/actions/start-checkout/types.d.ts +0 -90
- package/dist/actions/start-checkout/types.js +0 -10
- package/dist/demo/shipping.d.ts +0 -8
- package/dist/demo/shipping.js +0 -69
- package/dist/pubsub/topics/checkout/checkout-started/types.d.ts +0 -26
- package/dist/pubsub/topics/checkout/checkout-started/types.js +0 -1
- package/dist/pubsub/topics/checkout/index.d.ts +0 -7
- package/dist/pubsub/topics/checkout/index.js +0 -28
- package/dist/pubsub/topics/checkout/payment-completed/types.d.ts +0 -31
- package/dist/pubsub/topics/checkout/payment-completed/types.js +0 -1
- package/dist/pubsub/topics/checkout/payment-failed/types.d.ts +0 -20
- package/dist/pubsub/topics/checkout/payment-failed/types.js +0 -1
- package/dist/pubsub/topics/checkout/types.d.ts +0 -12
- package/dist/pubsub/topics/checkout/types.js +0 -8
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { isFulfillmentState } from '@final-commerce/common';
|
|
2
|
-
import { applyMockPayment, MOCK_CART } from '../../demo/database';
|
|
3
|
-
export const mockRecordExternalPayment = async (params) => {
|
|
4
|
-
console.log('[Mock] recordExternalPayment called', params);
|
|
5
|
-
const label = typeof params?.label === 'string' ? params.label.trim() : '';
|
|
6
|
-
if (!label) {
|
|
7
|
-
throw new Error('recordExternalPayment: label is required');
|
|
8
|
-
}
|
|
9
|
-
const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
10
|
-
const amount = params.amount ?? balanceDue;
|
|
11
|
-
// Same rule as the host: positive, except on a zero-balance checkout.
|
|
12
|
-
if (!Number.isFinite(amount) || amount < 0 || (amount === 0 && balanceDue > 0)) {
|
|
13
|
-
throw new Error('recordExternalPayment: amount must be a positive integer (minor units)');
|
|
14
|
-
}
|
|
15
|
-
const target = params.checkoutFulfillmentTarget;
|
|
16
|
-
if (target !== undefined && !isFulfillmentState(target)) {
|
|
17
|
-
throw new Error(`recordExternalPayment: invalid checkoutFulfillmentTarget "${String(target)}"`);
|
|
18
|
-
}
|
|
19
|
-
if (amount > balanceDue) {
|
|
20
|
-
throw new Error(`recordExternalPayment: amount ${amount} exceeds the balance due ${balanceDue}`);
|
|
21
|
-
}
|
|
22
|
-
const order = applyMockPayment(amount, 'external', label);
|
|
23
|
-
const remainingBalance = MOCK_CART.remainingBalance ?? 0;
|
|
24
|
-
return {
|
|
25
|
-
success: true,
|
|
26
|
-
amount,
|
|
27
|
-
label,
|
|
28
|
-
paymentType: 'external',
|
|
29
|
-
change: 0,
|
|
30
|
-
cashRounding: 0,
|
|
31
|
-
order,
|
|
32
|
-
saleFinalized: !!order,
|
|
33
|
-
remainingBalance: order ? 0 : remainingBalance,
|
|
34
|
-
timestamp: new Date().toISOString(),
|
|
35
|
-
};
|
|
36
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { CFOrder } from '../../CommonTypes';
|
|
2
|
-
export interface RecordExternalPaymentParams {
|
|
3
|
-
/**
|
|
4
|
-
* What the payment was — shown on the order and in reports, e.g. 'Paid online',
|
|
5
|
-
* 'Uber Eats', 'Voucher'. Required; trimmed. Not checked against a list, so keep
|
|
6
|
-
* labels consistent across flows.
|
|
7
|
-
*/
|
|
8
|
-
label: string;
|
|
9
|
-
/**
|
|
10
|
-
* Amount to record, in integer MINOR currency units. Omit to record the full balance
|
|
11
|
-
* due (completing the order). Below the balance due it records a partial payment —
|
|
12
|
-
* the rest can be taken with any other tender. Above the balance due is an error.
|
|
13
|
-
*/
|
|
14
|
-
amount?: number;
|
|
15
|
-
/** Fulfillment state to land on after full payment, e.g. 'pending' to keep the order going to the kitchen. */
|
|
16
|
-
checkoutFulfillmentTarget?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface RecordExternalPaymentResponse {
|
|
19
|
-
success: boolean;
|
|
20
|
-
/** The amount recorded, in integer MINOR currency units. */
|
|
21
|
-
amount: number;
|
|
22
|
-
/** The label, as recorded. */
|
|
23
|
-
label: string;
|
|
24
|
-
paymentType: 'external';
|
|
25
|
-
/** Always 0 — no money changes hands at the terminal. */
|
|
26
|
-
change: number;
|
|
27
|
-
/** Always 0 — cash rounding applies to cash only. */
|
|
28
|
-
cashRounding: number;
|
|
29
|
-
/** The order once the sale completes; null for a partial (split) leg. */
|
|
30
|
-
order: CFOrder | null;
|
|
31
|
-
/** True when this payment settled the remaining balance. */
|
|
32
|
-
saleFinalized: boolean;
|
|
33
|
-
/** Balance still due after this payment, in integer MINOR currency units. */
|
|
34
|
-
remainingBalance: number;
|
|
35
|
-
timestamp: string;
|
|
36
|
-
}
|
|
37
|
-
export type RecordExternalPayment = (params: RecordExternalPaymentParams) => Promise<RecordExternalPaymentResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Release from cart action
|
|
3
|
-
* Calls the releaseFromCart action on the parent window
|
|
4
|
-
*/
|
|
5
|
-
import { commandFrameClient } from '../../client';
|
|
6
|
-
export const releaseFromCart = async () => {
|
|
7
|
-
return await commandFrameClient.call('releaseFromCart', undefined);
|
|
8
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { MOCK_CART, MOCK_ORDERS, resetMockCart, mockPublishEvent } from '../../demo/database';
|
|
2
|
-
export const mockReleaseFromCart = async () => {
|
|
3
|
-
console.log('[Mock] releaseFromCart called');
|
|
4
|
-
if (!MOCK_CART.products.length) {
|
|
5
|
-
throw new Error('releaseFromCart: the cart is empty');
|
|
6
|
-
}
|
|
7
|
-
const now = new Date().toISOString();
|
|
8
|
-
// Best-effort: the demo has no live-cart order, so the cart becomes a new unpaid draft.
|
|
9
|
-
const order = {
|
|
10
|
-
_id: `order_released_${Date.now()}`,
|
|
11
|
-
receiptId: `REL-${MOCK_ORDERS.length + 1}`,
|
|
12
|
-
status: 'in-cart',
|
|
13
|
-
paymentState: 'unpaid',
|
|
14
|
-
fulfillmentState: 'draft',
|
|
15
|
-
inCart: { active: false, stationId: null, since: now },
|
|
16
|
-
lineItems: [],
|
|
17
|
-
customSales: [],
|
|
18
|
-
paymentMethods: [],
|
|
19
|
-
summary: { total: MOCK_CART.total },
|
|
20
|
-
createdAt: now,
|
|
21
|
-
};
|
|
22
|
-
MOCK_ORDERS.push(order);
|
|
23
|
-
resetMockCart();
|
|
24
|
-
mockPublishEvent('orders', 'order-updated', { order });
|
|
25
|
-
return { success: true, order, timestamp: now };
|
|
26
|
-
};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { CFOrder } from '../../CommonTypes';
|
|
2
|
-
export interface ReleaseFromCartResponse {
|
|
3
|
-
success: boolean;
|
|
4
|
-
/** The order that left the cart, as saved — its state is unchanged and `inCart.active` is false. */
|
|
5
|
-
order: CFOrder;
|
|
6
|
-
timestamp: string;
|
|
7
|
-
}
|
|
8
|
-
export type ReleaseFromCart = () => Promise<ReleaseFromCartResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Resume Checkout action
|
|
3
|
-
* Calls the resumeCheckout action on the parent window
|
|
4
|
-
*/
|
|
5
|
-
import { commandFrameClient } from '../../client';
|
|
6
|
-
export const resumeCheckout = async (params) => {
|
|
7
|
-
return await commandFrameClient.call('resumeCheckout', params ?? {});
|
|
8
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { ResumeCheckout } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Standalone mock of the checkout return leg.
|
|
4
|
-
*
|
|
5
|
-
* It reads the SAME query parameters the real provider sends a shopper back
|
|
6
|
-
* with, so a builder can exercise the redirect path in preview by appending
|
|
7
|
-
* them by hand:
|
|
8
|
-
*
|
|
9
|
-
* ?sessionId=CS_MOCK&redirectResult=MOCK
|
|
10
|
-
*
|
|
11
|
-
* Without them it answers `{ resumed: false }` and does nothing, which is what
|
|
12
|
-
* the real command does on an ordinary page load. That is the branch a
|
|
13
|
-
* checkout screen hits on every normal visit, so it is the one worth getting
|
|
14
|
-
* right in a mock.
|
|
15
|
-
*/
|
|
16
|
-
export declare const mockResumeCheckout: ResumeCheckout;
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { mockPublishEvent } from '../../demo/database';
|
|
2
|
-
/**
|
|
3
|
-
* Standalone mock of the checkout return leg.
|
|
4
|
-
*
|
|
5
|
-
* It reads the SAME query parameters the real provider sends a shopper back
|
|
6
|
-
* with, so a builder can exercise the redirect path in preview by appending
|
|
7
|
-
* them by hand:
|
|
8
|
-
*
|
|
9
|
-
* ?sessionId=CS_MOCK&redirectResult=MOCK
|
|
10
|
-
*
|
|
11
|
-
* Without them it answers `{ resumed: false }` and does nothing, which is what
|
|
12
|
-
* the real command does on an ordinary page load. That is the branch a
|
|
13
|
-
* checkout screen hits on every normal visit, so it is the one worth getting
|
|
14
|
-
* right in a mock.
|
|
15
|
-
*/
|
|
16
|
-
export const mockResumeCheckout = async (params) => {
|
|
17
|
-
console.log('[Mock] resumeCheckout called', params);
|
|
18
|
-
const href = params?.url ?? (typeof window === 'undefined' ? '' : window.location.href);
|
|
19
|
-
let redirectResult = null;
|
|
20
|
-
try {
|
|
21
|
-
redirectResult = new URL(href).searchParams.get('redirectResult');
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
redirectResult = null;
|
|
25
|
-
}
|
|
26
|
-
if (!redirectResult) {
|
|
27
|
-
return {
|
|
28
|
-
success: true,
|
|
29
|
-
timestamp: new Date().toISOString(),
|
|
30
|
-
checkout: { resumed: false },
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
const suffix = String(Date.now()).slice(-6);
|
|
34
|
-
const checkout = {
|
|
35
|
-
resumed: true,
|
|
36
|
-
orderId: `mock-order-${suffix}`,
|
|
37
|
-
receiptId: `ON-001-${suffix}`,
|
|
38
|
-
// `Authorised` is what the real provider reports for a completed redirect.
|
|
39
|
-
// It is NOT settlement — see the checkout topic docs.
|
|
40
|
-
resultCode: 'Authorised',
|
|
41
|
-
sessionResult: `mock-session-result-${suffix}`,
|
|
42
|
-
orderPassword: `mock-pw-${suffix}`,
|
|
43
|
-
};
|
|
44
|
-
mockPublishEvent('checkout', 'payment-completed', {
|
|
45
|
-
orderId: checkout.orderId,
|
|
46
|
-
receiptId: checkout.receiptId,
|
|
47
|
-
resultCode: checkout.resultCode,
|
|
48
|
-
sessionResult: checkout.sessionResult,
|
|
49
|
-
});
|
|
50
|
-
return { success: true, timestamp: new Date().toISOString(), checkout };
|
|
51
|
-
};
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
export interface ResumeCheckoutParams {
|
|
2
|
-
/**
|
|
3
|
-
* Where to read the provider's return data from. Defaults to the current
|
|
4
|
-
* page URL, which is where the shopper has just landed.
|
|
5
|
-
*
|
|
6
|
-
* Only override this if you moved the query string somewhere else before
|
|
7
|
-
* calling — for example if your router strips it on mount.
|
|
8
|
-
*/
|
|
9
|
-
url?: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* What the return leg produced. Every field past `resumed` is absent when
|
|
13
|
-
* `resumed` is `false`.
|
|
14
|
-
*/
|
|
15
|
-
export interface ResumeCheckoutResult {
|
|
16
|
-
/**
|
|
17
|
-
* `false` means THIS WAS AN ORDINARY PAGE LOAD — no provider return data was
|
|
18
|
-
* in the URL, so there was nothing to finish and nothing happened. It is not
|
|
19
|
-
* an error, and it is the answer on every normal visit to the page. Call this
|
|
20
|
-
* unconditionally when your checkout or confirmation screen mounts and branch
|
|
21
|
-
* on this field.
|
|
22
|
-
*/
|
|
23
|
-
resumed: boolean;
|
|
24
|
-
orderId?: string;
|
|
25
|
-
receiptId?: string;
|
|
26
|
-
/**
|
|
27
|
-
* The provider's result code for the completed attempt, e.g. `Authorised` or
|
|
28
|
-
* `Refused`. As everywhere else in this topic, `Authorised` is an
|
|
29
|
-
* authorisation and NOT a settlement.
|
|
30
|
-
*/
|
|
31
|
-
resultCode?: string;
|
|
32
|
-
/** Opaque proof of the payment — see `PaymentCompletedPayload.sessionResult`. */
|
|
33
|
-
sessionResult?: string;
|
|
34
|
-
/**
|
|
35
|
-
* The one-time order password from the original checkout, recovered from
|
|
36
|
-
* browser storage. The page that held it in memory is gone, so this is the
|
|
37
|
-
* only way back to the order's status after a redirect.
|
|
38
|
-
*/
|
|
39
|
-
orderPassword?: string;
|
|
40
|
-
}
|
|
41
|
-
export interface ResumeCheckoutResponse {
|
|
42
|
-
success: boolean;
|
|
43
|
-
timestamp: string;
|
|
44
|
-
checkout: ResumeCheckoutResult;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Finish a checkout the shopper was redirected away from.
|
|
48
|
-
*
|
|
49
|
-
* SAFE TO CALL ON EVERY PAGE LOAD, and that is how it is meant to be used: on
|
|
50
|
-
* an ordinary visit it finds no return data and answers `{ resumed: false }`
|
|
51
|
-
* without touching the network. Calling it twice for one return is also safe —
|
|
52
|
-
* the return data is consumed the first time.
|
|
53
|
-
*
|
|
54
|
-
* The outcome is ALSO published on the `checkout` topic (`payment-completed` or
|
|
55
|
-
* `payment-failed`), exactly as it would have been had the shopper never left,
|
|
56
|
-
* so a page that already subscribes needs no second code path. Subscribe first,
|
|
57
|
-
* then call this, or the event fires before you are listening.
|
|
58
|
-
*/
|
|
59
|
-
export type ResumeCheckout = (params?: ResumeCheckoutParams) => Promise<ResumeCheckoutResponse>;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Resume Checkout Types
|
|
2
|
-
//
|
|
3
|
-
// The RETURN LEG of an online checkout. Some payment methods — and 3-D Secure
|
|
4
|
-
// on a card — take the shopper away to their bank or wallet and send them back
|
|
5
|
-
// to `returnUrl` on a FRESH PAGE LOAD. The payment is not finished at that
|
|
6
|
-
// point: the provider hands the browser a one-time result in the URL, and it
|
|
7
|
-
// has to be handed back to the provider to complete the charge.
|
|
8
|
-
//
|
|
9
|
-
// `startCheckout` cannot do this. It ran in the page that is now gone.
|
|
10
|
-
//
|
|
11
|
-
// Served ONLY by the storefront runtime (a published website), like
|
|
12
|
-
// `startCheckout`. On a register it does not exist.
|
|
13
|
-
export {};
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, mockPublishEvent } from '../../demo/database';
|
|
2
|
-
import { restoreMockCartFromOrder } from '../resume-parked-order/mock';
|
|
3
|
-
// Mirrors the host's rule (see README): anything not already in a cart and not finished.
|
|
4
|
-
const BLOCKED_PAYMENT = new Set(['refunded', 'partially_refunded', 'voided', 'payment_pending']);
|
|
5
|
-
const FINISHED_FULFILLMENT = new Set(['cancelled', 'returned', 'partially_returned']);
|
|
6
|
-
export const mockResumeOrder = async (params) => {
|
|
7
|
-
console.log('[Mock] resumeOrder called', params);
|
|
8
|
-
const orderId = params?.orderId;
|
|
9
|
-
if (!orderId) {
|
|
10
|
-
throw new Error('Order ID is required');
|
|
11
|
-
}
|
|
12
|
-
const order = [...MOCK_PARKED_ORDERS, ...MOCK_ORDERS].find((o) => o._id === orderId);
|
|
13
|
-
if (!order) {
|
|
14
|
-
throw new Error(`Order with ID ${orderId} not found`);
|
|
15
|
-
}
|
|
16
|
-
const from = { payment: order.paymentState ?? 'unpaid', fulfillment: order.fulfillmentState ?? 'draft' };
|
|
17
|
-
const inCart = order.inCart != null ? order.inCart.active : from.fulfillment === 'draft';
|
|
18
|
-
if (inCart) {
|
|
19
|
-
throw new Error(`Order ${orderId} is already in a cart`);
|
|
20
|
-
}
|
|
21
|
-
if (BLOCKED_PAYMENT.has(from.payment) ||
|
|
22
|
-
FINISHED_FULFILLMENT.has(from.fulfillment) ||
|
|
23
|
-
(from.payment === 'paid' && from.fulfillment === 'fulfilled')) {
|
|
24
|
-
throw new Error(`Order ${orderId} cannot be resumed from ${from.payment} × ${from.fulfillment}`);
|
|
25
|
-
}
|
|
26
|
-
// Keeps the state; only parked (on_hold) / draft move.
|
|
27
|
-
const leavesParked = from.fulfillment === 'on_hold' || from.fulfillment === 'draft';
|
|
28
|
-
const to = {
|
|
29
|
-
payment: from.payment,
|
|
30
|
-
fulfillment: !leavesParked ? from.fulfillment : from.payment === 'unpaid' ? 'draft' : 'in_progress',
|
|
31
|
-
};
|
|
32
|
-
restoreMockCartFromOrder(order);
|
|
33
|
-
const parkedIndex = MOCK_PARKED_ORDERS.findIndex((o) => o._id === orderId);
|
|
34
|
-
if (parkedIndex !== -1)
|
|
35
|
-
MOCK_PARKED_ORDERS.splice(parkedIndex, 1);
|
|
36
|
-
mockPublishEvent('cart', 'cart-created', { orderId });
|
|
37
|
-
mockPublishEvent('order-state', 'state-transition-completed', {
|
|
38
|
-
orderId,
|
|
39
|
-
from,
|
|
40
|
-
to,
|
|
41
|
-
timestamp: new Date().toISOString(),
|
|
42
|
-
});
|
|
43
|
-
return {
|
|
44
|
-
success: true,
|
|
45
|
-
order: {
|
|
46
|
-
...order,
|
|
47
|
-
paymentState: to.payment,
|
|
48
|
-
fulfillmentState: to.fulfillment,
|
|
49
|
-
inCart: { active: true, stationId: null, since: new Date().toISOString() },
|
|
50
|
-
},
|
|
51
|
-
from,
|
|
52
|
-
to,
|
|
53
|
-
timestamp: new Date().toISOString(),
|
|
54
|
-
};
|
|
55
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { CFOrder } from '../../CommonTypes';
|
|
2
|
-
import type { CFStatePair } from '../../common-types/order-state';
|
|
3
|
-
export interface ResumeOrderParams {
|
|
4
|
-
/** The order to load back into the cart. Must be open — see the README for which states resume. */
|
|
5
|
-
orderId: string;
|
|
6
|
-
}
|
|
7
|
-
export interface ResumeOrderResponse {
|
|
8
|
-
success: boolean;
|
|
9
|
-
/** The resumed order, re-read after the transition. */
|
|
10
|
-
order: CFOrder;
|
|
11
|
-
/** State before resuming. */
|
|
12
|
-
from: CFStatePair;
|
|
13
|
-
/** State after resuming — `draft` when nothing was paid, otherwise the order stays out of the cart states. */
|
|
14
|
-
to: CFStatePair;
|
|
15
|
-
timestamp: string;
|
|
16
|
-
}
|
|
17
|
-
export type ResumeOrder = (params: ResumeOrderParams) => Promise<ResumeOrderResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SelectShippingOption action
|
|
3
|
-
* Calls the selectShippingOption action on the parent window
|
|
4
|
-
*/
|
|
5
|
-
import { commandFrameClient } from '../../client';
|
|
6
|
-
export const selectShippingOption = async (params) => {
|
|
7
|
-
return await commandFrameClient.call('selectShippingOption', params);
|
|
8
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { MOCK_CART, mockPublishEvent } from '../../demo/database';
|
|
2
|
-
import { mockShippingOptions } from '../../demo/shipping';
|
|
3
|
-
/** Standalone mock: refuses an option the cart isn't offered, like the runtime does. */
|
|
4
|
-
export const mockSelectShippingOption = async (params) => {
|
|
5
|
-
console.log('[Mock] selectShippingOption called', params);
|
|
6
|
-
if (!params)
|
|
7
|
-
throw new Error('Params required');
|
|
8
|
-
const previous = MOCK_CART.shippingTotal ?? 0;
|
|
9
|
-
if (params.optionId === null) {
|
|
10
|
-
MOCK_CART.shipping = null;
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
const option = mockShippingOptions().resolution.options.find((o) => o.optionId === params.optionId);
|
|
14
|
-
if (!option)
|
|
15
|
-
throw new Error('selectShippingOption: this option is not offered for this cart');
|
|
16
|
-
MOCK_CART.shipping = {
|
|
17
|
-
zoneId: option.zoneId,
|
|
18
|
-
optionId: option.optionId,
|
|
19
|
-
type: option.type,
|
|
20
|
-
name: option.name,
|
|
21
|
-
amount: option.amount,
|
|
22
|
-
minDays: option.minDays,
|
|
23
|
-
maxDays: option.maxDays,
|
|
24
|
-
outletId: option.outletId,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
MOCK_CART.shippingTotal = MOCK_CART.shipping?.amount ?? 0;
|
|
28
|
-
MOCK_CART.total += MOCK_CART.shippingTotal - previous;
|
|
29
|
-
mockPublishEvent('cart', 'cart-updated', { shipping: MOCK_CART.shipping });
|
|
30
|
-
return { shipping: MOCK_CART.shipping, cart: MOCK_CART, timestamp: new Date().toISOString() };
|
|
31
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { CFActiveCart, CFCartShipping } from '../../CommonTypes';
|
|
2
|
-
export interface SelectShippingOptionParams {
|
|
3
|
-
/** An `optionId` from `getShippingOptions`. `null` takes shipping off the cart. */
|
|
4
|
-
optionId: string | null;
|
|
5
|
-
}
|
|
6
|
-
export interface SelectShippingOptionResponse {
|
|
7
|
-
shipping: CFCartShipping | null;
|
|
8
|
-
cart: CFActiveCart;
|
|
9
|
-
timestamp: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* THROWS for an option this cart isn't offered: one from another address, a
|
|
13
|
-
* website-only option at the till, or one the store has since removed.
|
|
14
|
-
*/
|
|
15
|
-
export type SelectShippingOption = (params: SelectShippingOptionParams) => Promise<SelectShippingOptionResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SetOrderAddress action
|
|
3
|
-
* Calls the setOrderAddress action on the parent window
|
|
4
|
-
*/
|
|
5
|
-
import { commandFrameClient } from '../../client';
|
|
6
|
-
export const setOrderAddress = async (params) => {
|
|
7
|
-
return await commandFrameClient.call('setOrderAddress', params);
|
|
8
|
-
};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { SetOrderAddress } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Standalone mock of putting an address on the cart. It refuses what the runtime refuses (no
|
|
4
|
-
* country, an unreadable one, a shipping address without street and city) so a checkout form
|
|
5
|
-
* that looks finished in preview doesn't lose orders on the published site.
|
|
6
|
-
*/
|
|
7
|
-
export declare const mockSetOrderAddress: SetOrderAddress;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { normalizeAddress } from '@final-commerce/common';
|
|
2
|
-
import { MOCK_CART, mockPublishEvent } from '../../demo/database';
|
|
3
|
-
/**
|
|
4
|
-
* Standalone mock of putting an address on the cart. It refuses what the runtime refuses (no
|
|
5
|
-
* country, an unreadable one, a shipping address without street and city) so a checkout form
|
|
6
|
-
* that looks finished in preview doesn't lose orders on the published site.
|
|
7
|
-
*/
|
|
8
|
-
export const mockSetOrderAddress = async (params) => {
|
|
9
|
-
console.log('[Mock] setOrderAddress called', params);
|
|
10
|
-
if (!params || (params.type !== 'shipping' && params.type !== 'billing')) {
|
|
11
|
-
throw new Error("setOrderAddress: type must be 'shipping' or 'billing'");
|
|
12
|
-
}
|
|
13
|
-
const key = params.type === 'shipping' ? 'shippingAddress' : 'billingAddress';
|
|
14
|
-
let address = params.address;
|
|
15
|
-
if (address) {
|
|
16
|
-
const read = normalizeAddress(address);
|
|
17
|
-
if (!read.country)
|
|
18
|
-
throw new Error('setOrderAddress: choose a country');
|
|
19
|
-
if (params.type === 'shipping' && (!address.address1?.trim() || !address.city?.trim())) {
|
|
20
|
-
throw new Error('setOrderAddress: a shipping address needs a street and a city');
|
|
21
|
-
}
|
|
22
|
-
address = { ...address, country: read.country, state: read.province ?? address.state, fromCustomer: false };
|
|
23
|
-
}
|
|
24
|
-
MOCK_CART[key] = address;
|
|
25
|
-
if (params.type === 'shipping')
|
|
26
|
-
MOCK_CART.shipping = null;
|
|
27
|
-
mockPublishEvent('cart', 'cart-updated', { [key]: address });
|
|
28
|
-
return { address, cart: MOCK_CART, timestamp: new Date().toISOString() };
|
|
29
|
-
};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { CFActiveCart, CFCartAddress } from '../../CommonTypes';
|
|
2
|
-
export type OrderAddressType = 'shipping' | 'billing';
|
|
3
|
-
export interface SetOrderAddressParams {
|
|
4
|
-
type: OrderAddressType;
|
|
5
|
-
/** `null` clears it. Country and province may be codes or names; the runtime stores codes. */
|
|
6
|
-
address: CFCartAddress | null;
|
|
7
|
-
}
|
|
8
|
-
export interface SetOrderAddressResponse {
|
|
9
|
-
/** As stored: country as ISO-2, province as its code, postal code tidied. */
|
|
10
|
-
address: CFCartAddress | null;
|
|
11
|
-
/** The cart after the change. A new shipping address re-checks the chosen shipping option. */
|
|
12
|
-
cart: CFActiveCart;
|
|
13
|
-
timestamp: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* THROWS when the address can't be used: no country, a country we can't read, or a
|
|
17
|
-
* shipping address without a street and city. The message says which, for the form.
|
|
18
|
-
*/
|
|
19
|
-
export type SetOrderAddress = (params: SetOrderAddressParams) => Promise<SetOrderAddressResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Set order metadata action
|
|
3
|
-
* Calls the setOrderMetadata action on the parent window
|
|
4
|
-
*/
|
|
5
|
-
import { commandFrameClient } from '../../client';
|
|
6
|
-
export const setOrderMetadata = async (params) => {
|
|
7
|
-
return await commandFrameClient.call('setOrderMetadata', params);
|
|
8
|
-
};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { CFMetadataItem } from '../../CommonTypes';
|
|
2
|
-
import type { SetOrderMetadata } from './types';
|
|
3
|
-
/** Set/remove keys; untouched items (and extra fields such as `externalId`) are kept as-is. */
|
|
4
|
-
export declare const mergeMetadata: <T extends CFMetadataItem>(current: T[] | undefined, changes: Record<string, string | null>) => T[];
|
|
5
|
-
export declare const mockSetOrderMetadata: SetOrderMetadata;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, mockPublishEvent } from '../../demo/database';
|
|
2
|
-
/** Metadata for the demo's live cart, which has no order until it is paid or parked. */
|
|
3
|
-
let mockCartMetadata = [];
|
|
4
|
-
/** Set/remove keys; untouched items (and extra fields such as `externalId`) are kept as-is. */
|
|
5
|
-
export const mergeMetadata = (current, changes) => {
|
|
6
|
-
const byKey = new Map((current ?? []).map((m) => [m.key, m]));
|
|
7
|
-
for (const [key, value] of Object.entries(changes)) {
|
|
8
|
-
if (value === null)
|
|
9
|
-
byKey.delete(key);
|
|
10
|
-
else
|
|
11
|
-
byKey.set(key, { ...byKey.get(key), key, value });
|
|
12
|
-
}
|
|
13
|
-
return [...byKey.values()];
|
|
14
|
-
};
|
|
15
|
-
export const mockSetOrderMetadata = async (params) => {
|
|
16
|
-
console.log('[Mock] setOrderMetadata called', params);
|
|
17
|
-
if (!params?.metadata || Object.keys(params.metadata).length === 0) {
|
|
18
|
-
throw new Error('setOrderMetadata: metadata must set or remove at least one key');
|
|
19
|
-
}
|
|
20
|
-
for (const [key, value] of Object.entries(params.metadata)) {
|
|
21
|
-
if (!key.trim())
|
|
22
|
-
throw new Error('setOrderMetadata: metadata keys must be non-empty');
|
|
23
|
-
if (value !== null && typeof value !== 'string') {
|
|
24
|
-
throw new Error(`setOrderMetadata: value for "${key}" must be a string or null`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
if (!params.orderId) {
|
|
28
|
-
mockCartMetadata = mergeMetadata(mockCartMetadata, params.metadata);
|
|
29
|
-
return { success: true, orderId: null, metadata: mockCartMetadata, timestamp: new Date().toISOString() };
|
|
30
|
-
}
|
|
31
|
-
const order = [...MOCK_ORDERS, ...MOCK_PARKED_ORDERS].find((o) => o._id === params.orderId);
|
|
32
|
-
if (!order) {
|
|
33
|
-
throw new Error(`Order with ID ${params.orderId} not found`);
|
|
34
|
-
}
|
|
35
|
-
order.metadata = mergeMetadata(order.metadata, params.metadata);
|
|
36
|
-
mockPublishEvent('orders', 'order-updated', { order });
|
|
37
|
-
return { success: true, orderId: order._id, metadata: order.metadata, timestamp: new Date().toISOString() };
|
|
38
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { CFMetadataItem } from '../../CommonTypes';
|
|
2
|
-
export interface SetOrderMetadataParams {
|
|
3
|
-
/**
|
|
4
|
-
* Order to update. Omit to target the live cart's order — including a cart
|
|
5
|
-
* that hasn't become an order yet (the metadata is carried onto the order
|
|
6
|
-
* when it is created).
|
|
7
|
-
*/
|
|
8
|
-
orderId?: string;
|
|
9
|
-
/** Keys to set (string) or remove (null). Keys not listed are left as they are. */
|
|
10
|
-
metadata: Record<string, string | null>;
|
|
11
|
-
}
|
|
12
|
-
export interface SetOrderMetadataResponse {
|
|
13
|
-
success: boolean;
|
|
14
|
-
/** The order that was updated, or null when the live cart has no order yet. */
|
|
15
|
-
orderId: string | null;
|
|
16
|
-
/** The full metadata after the update. */
|
|
17
|
-
metadata: CFMetadataItem[];
|
|
18
|
-
timestamp: string;
|
|
19
|
-
}
|
|
20
|
-
export type SetOrderMetadata = (params: SetOrderMetadataParams) => Promise<SetOrderMetadataResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|