@final-commerce/command-frame 0.1.73 → 0.1.75
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/README.md +50 -28
- package/dist/CommonTypes.d.ts +124 -7
- package/dist/CommonTypes.js +112 -0
- package/dist/actions/add-cart-discount/mock.js +6 -3
- package/dist/actions/add-cart-fee/mock.js +6 -6
- package/dist/actions/add-custom-sale/mock.js +7 -2
- package/dist/actions/add-order-note/mock.js +3 -1
- package/dist/actions/add-product-discount/mock.js +10 -3
- package/dist/actions/add-product-fee/mock.js +10 -1
- package/dist/actions/apply-transition/action.d.ts +2 -0
- package/dist/actions/apply-transition/action.js +4 -0
- package/dist/actions/apply-transition/mock.d.ts +6 -0
- package/dist/actions/apply-transition/mock.js +33 -0
- package/dist/actions/apply-transition/types.d.ts +17 -0
- package/dist/actions/apply-transition/types.js +1 -0
- package/dist/actions/can-transition/action.d.ts +2 -0
- package/dist/actions/can-transition/action.js +4 -0
- package/dist/actions/can-transition/mock.d.ts +6 -0
- package/dist/actions/can-transition/mock.js +28 -0
- package/dist/actions/can-transition/types.d.ts +11 -0
- package/dist/actions/can-transition/types.js +1 -0
- package/dist/actions/cash-payment/mock.js +12 -18
- package/dist/actions/cash-payment/types.d.ts +5 -0
- package/dist/actions/delete-parked-order/mock.js +3 -1
- package/dist/actions/delete-parked-order/types.d.ts +3 -0
- package/dist/actions/extension-payment/types.d.ts +5 -0
- package/dist/actions/get-available-transitions/action.d.ts +2 -0
- package/dist/actions/get-available-transitions/action.js +4 -0
- package/dist/actions/get-available-transitions/mock.d.ts +6 -0
- package/dist/actions/get-available-transitions/mock.js +26 -0
- package/dist/actions/get-available-transitions/types.d.ts +9 -0
- package/dist/actions/get-available-transitions/types.js +1 -0
- package/dist/actions/get-context/mock.js +1 -1
- package/dist/actions/get-orders/mock.js +3 -3
- package/dist/actions/initiate-refund/types.d.ts +3 -0
- package/dist/actions/open-extension-overlay/mock.d.ts +2 -0
- package/dist/actions/open-extension-overlay/mock.js +1 -0
- package/dist/actions/open-extension-overlay/types.d.ts +9 -0
- package/dist/actions/open-extension-overlay/types.js +1 -0
- package/dist/actions/park-order/mock.js +4 -1
- package/dist/actions/park-order/types.d.ts +3 -0
- package/dist/actions/partial-payment/mock.js +21 -3
- package/dist/actions/partial-payment/types.d.ts +5 -0
- package/dist/actions/process-partial-refund/types.d.ts +3 -0
- package/dist/actions/remove-custom-sale/mock.d.ts +2 -0
- package/dist/actions/remove-custom-sale/mock.js +29 -0
- package/dist/actions/remove-customer-from-cart/mock.js +3 -1
- package/dist/actions/remove-order-note/mock.d.ts +2 -0
- package/dist/actions/remove-order-note/mock.js +12 -0
- package/dist/actions/remove-product-discount/mock.d.ts +2 -0
- package/dist/actions/remove-product-discount/mock.js +17 -0
- package/dist/actions/remove-product-fee/mock.d.ts +2 -0
- package/dist/actions/remove-product-fee/mock.js +17 -0
- package/dist/actions/remove-product-from-cart/mock.js +5 -5
- package/dist/actions/resolve-extension-overlay/mock.d.ts +2 -0
- package/dist/actions/resolve-extension-overlay/mock.js +1 -0
- package/dist/actions/resolve-extension-overlay/types.d.ts +9 -0
- package/dist/actions/resolve-extension-overlay/types.js +1 -0
- package/dist/actions/resume-parked-order/mock.js +4 -1
- package/dist/actions/resume-parked-order/types.d.ts +3 -0
- package/dist/actions/tap-to-pay-payment/mock.js +5 -3
- package/dist/actions/tap-to-pay-payment/types.d.ts +5 -0
- package/dist/actions/terminal-payment/mock.js +4 -5
- package/dist/actions/terminal-payment/types.d.ts +5 -0
- package/dist/actions/update-cart-item-quantity/mock.js +9 -9
- package/dist/actions/vendara-payment/types.d.ts +5 -0
- package/dist/common-types/index.d.ts +1 -0
- package/dist/common-types/index.js +1 -0
- package/dist/common-types/order-state.d.ts +32 -0
- package/dist/common-types/order-state.js +6 -0
- package/dist/common-types/state-fragment.d.ts +77 -0
- package/dist/common-types/state-fragment.js +10 -0
- package/dist/demo/database.d.ts +10 -0
- package/dist/demo/database.js +169 -3
- package/dist/fragments/index.d.ts +1 -0
- package/dist/fragments/index.js +1 -0
- package/dist/fragments/preorder-no-deposit.d.ts +26 -0
- package/dist/fragments/preorder-no-deposit.js +166 -0
- package/dist/index.d.ts +14 -4
- package/dist/index.js +13 -3
- package/dist/interceptors/index.d.ts +21 -0
- package/dist/interceptors/index.js +53 -0
- package/dist/interceptors/types.d.ts +26 -0
- package/dist/interceptors/types.js +1 -0
- package/dist/projects/render/mocks.js +16 -4
- package/dist/projects/render/types.d.ts +7 -1
- package/dist/pubsub/topics/orders/index.js +10 -0
- package/dist/pubsub/topics/orders/state-transition-blocked/types.d.ts +16 -0
- package/dist/pubsub/topics/orders/state-transition-blocked/types.js +1 -0
- package/dist/pubsub/topics/orders/state-transition-completed/types.d.ts +15 -0
- package/dist/pubsub/topics/orders/state-transition-completed/types.js +1 -0
- package/dist/pubsub/topics/orders/types.d.ts +6 -2
- package/dist/pubsub/topics/orders/types.js +2 -0
- package/package.json +1 -1
- package/dist/actions/extension-refund/constants.d.ts +0 -2
- package/dist/actions/extension-refund/constants.js +0 -2
- package/dist/actions/extension-refund/extension-refund-listener.d.ts +0 -11
- package/dist/actions/extension-refund/extension-refund-listener.js +0 -60
- package/dist/actions/extension-refund/types.d.ts +0 -32
- package/dist/actions/extension-refund/types.js +0 -5
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CanTransitionParams, CanTransitionResponse } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementation: allows all transitions except a few known-invalid ones
|
|
4
|
+
* so the demo app can show both allowed and blocked responses.
|
|
5
|
+
*/
|
|
6
|
+
export declare const canTransitionMock: (params: CanTransitionParams) => Promise<CanTransitionResponse>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementation: allows all transitions except a few known-invalid ones
|
|
3
|
+
* so the demo app can show both allowed and blocked responses.
|
|
4
|
+
*/
|
|
5
|
+
export const canTransitionMock = async (params) => {
|
|
6
|
+
const to = params.to;
|
|
7
|
+
if (to.payment === "refunded" && to.fulfillment === "draft") {
|
|
8
|
+
return {
|
|
9
|
+
result: {
|
|
10
|
+
allowed: false,
|
|
11
|
+
blockedBy: "financial_invariant",
|
|
12
|
+
guard: "no-refund-in-draft",
|
|
13
|
+
reason: "Cannot refund an order that is still in draft",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (to.payment === "paid" && to.fulfillment === "cancelled") {
|
|
18
|
+
return {
|
|
19
|
+
result: {
|
|
20
|
+
allowed: false,
|
|
21
|
+
blockedBy: "cross_axis_rule",
|
|
22
|
+
guard: "no-pay-cancelled",
|
|
23
|
+
reason: "Cannot mark a cancelled order as paid",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { result: { allowed: true } };
|
|
28
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CFStatePair, CFTransitionResult } from "../../common-types/order-state";
|
|
2
|
+
export interface CanTransitionParams {
|
|
3
|
+
/** Order to evaluate. If omitted, evaluates against a new order (from = null). */
|
|
4
|
+
orderId?: string;
|
|
5
|
+
/** Target state pair to transition to. */
|
|
6
|
+
to: CFStatePair;
|
|
7
|
+
}
|
|
8
|
+
export interface CanTransitionResponse {
|
|
9
|
+
result: CFTransitionResult;
|
|
10
|
+
}
|
|
11
|
+
export type CanTransition = (params: CanTransitionParams) => Promise<CanTransitionResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { applyMockPayment, MOCK_CART } from "../../demo/database";
|
|
2
2
|
export const mockCashPayment = async (params) => {
|
|
3
3
|
console.log("[Mock] cashPayment called", params);
|
|
4
|
-
// Default to true to match action behavior
|
|
4
|
+
// Default to true to match action behavior.
|
|
5
5
|
const openChangeCalculator = params?.openChangeCalculator ?? true;
|
|
6
|
-
|
|
6
|
+
// Amount due for THIS tender (the queued amount-to-be-charged), in minor units.
|
|
7
|
+
const due = params?.amount ?? MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
7
8
|
if (openChangeCalculator) {
|
|
8
9
|
try {
|
|
9
|
-
const input = window.prompt(`
|
|
10
|
+
const input = window.prompt(`Amount due: $${(due / 100).toFixed(2)}\nEnter amount tendered:`, (due / 100).toFixed(2));
|
|
10
11
|
if (input === null) {
|
|
11
|
-
// User cancelled
|
|
12
12
|
return {
|
|
13
13
|
success: false,
|
|
14
14
|
amount: 0,
|
|
@@ -18,28 +18,22 @@ export const mockCashPayment = async (params) => {
|
|
|
18
18
|
timestamp: new Date().toISOString()
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
-
const tendered = parseFloat(input);
|
|
21
|
+
const tendered = parseFloat(input); // dollars
|
|
22
22
|
if (!isNaN(tendered)) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
window.alert(`Warning: Tendered amount is less than total. Short by: $${Math.abs(change).toFixed(2)}`);
|
|
30
|
-
}
|
|
23
|
+
const change = tendered - due / 100;
|
|
24
|
+
window.alert(change >= 0
|
|
25
|
+
? `Change Due: $${change.toFixed(2)}`
|
|
26
|
+
: `Warning: Tendered is short by: $${Math.abs(change).toFixed(2)}`);
|
|
31
27
|
}
|
|
32
28
|
}
|
|
33
29
|
catch (e) {
|
|
34
30
|
console.warn("Could not open prompt/alert (possibly in non-interactive environment)", e);
|
|
35
31
|
}
|
|
36
32
|
}
|
|
37
|
-
const order =
|
|
38
|
-
// Publish payment-done event
|
|
39
|
-
mockPublishEvent('payments', 'payment-done', { order });
|
|
33
|
+
const order = applyMockPayment(due, "cash", "cash");
|
|
40
34
|
return {
|
|
41
35
|
success: true,
|
|
42
|
-
amount,
|
|
36
|
+
amount: due,
|
|
43
37
|
openChangeCalculator,
|
|
44
38
|
paymentType: "cash",
|
|
45
39
|
order,
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
export interface CashPaymentParams {
|
|
3
4
|
/** If not provided, uses the cart total. */
|
|
4
5
|
amount?: number;
|
|
5
6
|
/** Defaults to false. */
|
|
6
7
|
openChangeCalculator?: boolean;
|
|
8
|
+
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
9
|
+
checkoutFulfillmentTarget?: string;
|
|
7
10
|
}
|
|
8
11
|
export interface CashPaymentResponse {
|
|
9
12
|
success: boolean;
|
|
@@ -12,5 +15,7 @@ export interface CashPaymentResponse {
|
|
|
12
15
|
paymentType: string;
|
|
13
16
|
order: CFOrder | null;
|
|
14
17
|
timestamp: string;
|
|
18
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
19
|
+
transitionResult?: CFTransitionResult;
|
|
15
20
|
}
|
|
16
21
|
export type CashPayment = (params?: CashPaymentParams) => Promise<CashPaymentResponse>;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { MOCK_PARKED_ORDERS } from "../../demo/database";
|
|
1
|
+
import { MOCK_PARKED_ORDERS, mockPublishEvent } from "../../demo/database";
|
|
2
2
|
export const mockDeleteParkedOrder = async (params) => {
|
|
3
3
|
console.log("[Mock] deleteParkedOrder called", params);
|
|
4
4
|
if (params?.orderId) {
|
|
5
5
|
const index = MOCK_PARKED_ORDERS.findIndex(o => o._id === params.orderId);
|
|
6
6
|
if (index !== -1) {
|
|
7
7
|
MOCK_PARKED_ORDERS.splice(index, 1);
|
|
8
|
+
// Refresh order lists (the parked-order modal reads getOrders).
|
|
9
|
+
mockPublishEvent("orders", "parked-order-deleted", { orderId: params.orderId });
|
|
8
10
|
}
|
|
9
11
|
}
|
|
10
12
|
return {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
1
2
|
export interface DeleteParkedOrderParams {
|
|
2
3
|
orderId: string;
|
|
3
4
|
}
|
|
@@ -5,5 +6,7 @@ export interface DeleteParkedOrderResponse {
|
|
|
5
6
|
success: boolean;
|
|
6
7
|
orderId: string;
|
|
7
8
|
timestamp: string;
|
|
9
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
10
|
+
transitionResult?: CFTransitionResult;
|
|
8
11
|
}
|
|
9
12
|
export type DeleteParkedOrder = (params?: DeleteParkedOrderParams) => Promise<DeleteParkedOrderResponse>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
/** Params for extension-initiated payments; host routes by `paymentType`. */
|
|
3
4
|
export interface ExtensionPaymentParams {
|
|
4
5
|
paymentType: string;
|
|
@@ -8,6 +9,8 @@ export interface ExtensionPaymentParams {
|
|
|
8
9
|
referenceId?: string;
|
|
9
10
|
extensionId?: string;
|
|
10
11
|
metadata?: Record<string, unknown>;
|
|
12
|
+
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
13
|
+
checkoutFulfillmentTarget?: string;
|
|
11
14
|
/** EMV data when the underlying payment carries one (typed as `IntegrationEmvData` by the integration wrapper). */
|
|
12
15
|
emvData?: unknown;
|
|
13
16
|
/** Processor fee in minor units; recorded on the order's paymentMethod.processorFee. */
|
|
@@ -19,5 +22,7 @@ export interface ExtensionPaymentResponse {
|
|
|
19
22
|
paymentType: string;
|
|
20
23
|
order: CFOrder | null;
|
|
21
24
|
timestamp: string;
|
|
25
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
26
|
+
transitionResult?: CFTransitionResult;
|
|
22
27
|
}
|
|
23
28
|
export type ExtensionPayment = (params?: ExtensionPaymentParams) => Promise<ExtensionPaymentResponse>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { GetAvailableTransitionsParams, GetAvailableTransitionsResponse } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementation: returns a fixed set of plausible transitions
|
|
4
|
+
* so the demo app has data to render.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getAvailableTransitionsMock: (_params: GetAvailableTransitionsParams) => Promise<GetAvailableTransitionsResponse>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementation: returns a fixed set of plausible transitions
|
|
3
|
+
* so the demo app has data to render.
|
|
4
|
+
*/
|
|
5
|
+
export const getAvailableTransitionsMock = async (_params) => ({
|
|
6
|
+
transitions: [
|
|
7
|
+
{
|
|
8
|
+
to: { payment: "refunded", fulfillment: "returned" },
|
|
9
|
+
displayLabel: "Full Refund",
|
|
10
|
+
conditions: [{ met: true, description: "Order is paid" }],
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
to: { payment: "partially_refunded", fulfillment: "partially_returned" },
|
|
14
|
+
displayLabel: "Partial Refund",
|
|
15
|
+
conditions: [{ met: true, description: "Order is paid" }],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
to: { payment: "voided", fulfillment: "cancelled" },
|
|
19
|
+
displayLabel: "Void Order",
|
|
20
|
+
conditions: [
|
|
21
|
+
{ met: true, description: "Order exists" },
|
|
22
|
+
{ met: false, description: "No payments captured (mock: skipped)" },
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CFAvailableTransition } from "../../common-types/order-state";
|
|
2
|
+
export interface GetAvailableTransitionsParams {
|
|
3
|
+
/** Order to evaluate. Required — we need the current state. */
|
|
4
|
+
orderId: string;
|
|
5
|
+
}
|
|
6
|
+
export interface GetAvailableTransitionsResponse {
|
|
7
|
+
transitions: CFAvailableTransition[];
|
|
8
|
+
}
|
|
9
|
+
export type GetAvailableTransitions = (params: GetAvailableTransitionsParams) => Promise<GetAvailableTransitionsResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -24,7 +24,7 @@ export const mockGetContext = () => {
|
|
|
24
24
|
thousandSeparator: ",",
|
|
25
25
|
decimalSeparator: ".",
|
|
26
26
|
user: null,
|
|
27
|
-
company:
|
|
27
|
+
company: { _id: MOCK_COMPANY.id, name: MOCK_COMPANY.name, logo: MOCK_COMPANY.logo },
|
|
28
28
|
station: null,
|
|
29
29
|
outlet: null,
|
|
30
30
|
timestamp: new Date().toISOString()
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { MOCK_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize } from "../../demo/database";
|
|
1
|
+
import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize } from "../../demo/database";
|
|
2
2
|
export const mockGetOrders = async (params) => {
|
|
3
3
|
console.log("[Mock] getOrders called", params);
|
|
4
|
-
// Start with a safe copy of mock orders
|
|
5
|
-
let orders = safeSerialize(MOCK_ORDERS);
|
|
4
|
+
// Start with a safe copy of mock orders, including parked (status: "parked").
|
|
5
|
+
let orders = safeSerialize([...MOCK_ORDERS, ...MOCK_PARKED_ORDERS]);
|
|
6
6
|
// Filter simulation
|
|
7
7
|
if (params) {
|
|
8
8
|
const { customerId, status, sessionId, searchValue, limit, offset, sortBy, sortDirection } = params;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
1
2
|
export interface InitiateRefundParams {
|
|
2
3
|
/** The ID of the order to refund. If not provided, uses the currently active order. */
|
|
3
4
|
orderId?: string;
|
|
@@ -6,5 +7,7 @@ export interface InitiateRefundResponse {
|
|
|
6
7
|
success: boolean;
|
|
7
8
|
orderId: string;
|
|
8
9
|
timestamp: string;
|
|
10
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
11
|
+
transitionResult?: CFTransitionResult;
|
|
9
12
|
}
|
|
10
13
|
export type InitiateRefund = (params?: InitiateRefundParams) => Promise<InitiateRefundResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const mockOpenExtensionOverlay = async (_params) => true;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InterceptorPoint, InterceptorReturn } from "../../interceptors/types";
|
|
2
|
+
export interface OpenExtensionOverlayParams {
|
|
3
|
+
point: InterceptorPoint;
|
|
4
|
+
payload?: any;
|
|
5
|
+
/** Owning extension id. Injected by the host for interceptor-originated calls; optional for direct calls. */
|
|
6
|
+
extensionId?: string;
|
|
7
|
+
}
|
|
8
|
+
export type OpenExtensionOverlayResponse = InterceptorReturn;
|
|
9
|
+
export type OpenExtensionOverlay = (params: OpenExtensionOverlayParams) => Promise<OpenExtensionOverlayResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MOCK_PARKED_ORDERS, createOrderFromCart, MOCK_ORDERS } from "../../demo/database";
|
|
1
|
+
import { MOCK_PARKED_ORDERS, createOrderFromCart, MOCK_ORDERS, mockPublishEvent } from "../../demo/database";
|
|
2
2
|
export const mockParkOrder = async () => {
|
|
3
3
|
console.log("[Mock] parkOrder called");
|
|
4
4
|
// Create a temporary order to capture cart state
|
|
@@ -13,6 +13,9 @@ export const mockParkOrder = async () => {
|
|
|
13
13
|
MOCK_ORDERS.splice(foundIndex, 1);
|
|
14
14
|
}
|
|
15
15
|
MOCK_PARKED_ORDERS.push(tempOrder);
|
|
16
|
+
// Refresh order lists so the new parked order appears (createOrderFromCart
|
|
17
|
+
// already published the cart-created event that clears the cart).
|
|
18
|
+
mockPublishEvent("orders", "order-parked", { order: tempOrder });
|
|
16
19
|
return {
|
|
17
20
|
success: true,
|
|
18
21
|
order: tempOrder,
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
export interface ParkOrderResponse {
|
|
3
4
|
success: boolean;
|
|
4
5
|
order: CFOrder;
|
|
5
6
|
timestamp: string;
|
|
7
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
8
|
+
transitionResult?: CFTransitionResult;
|
|
6
9
|
}
|
|
7
10
|
export type ParkOrder = () => Promise<ParkOrderResponse>;
|
|
@@ -1,17 +1,35 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
2
|
export const mockPartialPayment = async (params) => {
|
|
3
3
|
console.log("[Mock] partialPayment called", params);
|
|
4
4
|
const openUI = params?.openUI ?? true;
|
|
5
5
|
if (openUI) {
|
|
6
|
-
//
|
|
6
|
+
// Split-payment UI is host-owned; nothing to simulate here.
|
|
7
7
|
window.alert("Demo: Split Payment UI would open here.");
|
|
8
|
+
return {
|
|
9
|
+
success: true,
|
|
10
|
+
amount: params?.amount,
|
|
11
|
+
isPercent: params?.isPercent || false,
|
|
12
|
+
openUI,
|
|
13
|
+
order: null,
|
|
14
|
+
timestamp: new Date().toISOString()
|
|
15
|
+
};
|
|
8
16
|
}
|
|
17
|
+
// Queue a partial amount as the next tender. The remaining balance is left
|
|
18
|
+
// untouched until the payment is actually taken (see applyMockPayment).
|
|
19
|
+
const remaining = MOCK_CART.remainingBalance ?? MOCK_CART.total;
|
|
20
|
+
const raw = params?.amount ?? 0;
|
|
21
|
+
// Mirror render: fixed amount is raw dollars (render does toMinorUnits), so
|
|
22
|
+
// convert to minor units here; percent is a percentage of the remaining total.
|
|
23
|
+
const minorFactor = 10 ** (MOCK_CART.minorUnits ?? 2);
|
|
24
|
+
const charge = params?.isPercent ? Math.round((remaining * raw) / 100) : Math.round(raw * minorFactor);
|
|
25
|
+
MOCK_CART.amountToBeCharged = Math.min(Math.max(0, charge), remaining);
|
|
26
|
+
mockPublishEvent("cart", "partial-payment-set", { amountToBeCharged: MOCK_CART.amountToBeCharged });
|
|
9
27
|
return {
|
|
10
28
|
success: true,
|
|
11
29
|
amount: params?.amount,
|
|
12
30
|
isPercent: params?.isPercent || false,
|
|
13
31
|
openUI,
|
|
14
|
-
order:
|
|
32
|
+
order: null,
|
|
15
33
|
timestamp: new Date().toISOString()
|
|
16
34
|
};
|
|
17
35
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
export interface PartialPaymentParams {
|
|
3
4
|
/** The payment amount (required if openUI is false). */
|
|
4
5
|
amount?: number;
|
|
@@ -6,6 +7,8 @@ export interface PartialPaymentParams {
|
|
|
6
7
|
isPercent?: boolean;
|
|
7
8
|
/** If true, opens the split payment UI. */
|
|
8
9
|
openUI?: boolean;
|
|
10
|
+
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
11
|
+
checkoutFulfillmentTarget?: string;
|
|
9
12
|
}
|
|
10
13
|
export interface PartialPaymentResponse {
|
|
11
14
|
success: boolean;
|
|
@@ -14,5 +17,7 @@ export interface PartialPaymentResponse {
|
|
|
14
17
|
openUI: boolean;
|
|
15
18
|
order: CFOrder | null;
|
|
16
19
|
timestamp: string;
|
|
20
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
21
|
+
transitionResult?: CFTransitionResult;
|
|
17
22
|
}
|
|
18
23
|
export type PartialPayment = (params?: PartialPaymentParams) => Promise<PartialPaymentResponse>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
1
2
|
export interface ProcessPartialRefundParams {
|
|
2
3
|
/** Optional refund reason. */
|
|
3
4
|
reason?: string;
|
|
@@ -15,5 +16,7 @@ export interface ProcessPartialRefundResponse {
|
|
|
15
16
|
success: boolean;
|
|
16
17
|
refundId: string;
|
|
17
18
|
timestamp: string;
|
|
19
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
20
|
+
transitionResult?: CFTransitionResult;
|
|
18
21
|
}
|
|
19
22
|
export type ProcessPartialRefund = (params?: ProcessPartialRefundParams) => Promise<ProcessPartialRefundResponse>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
export const mockRemoveCustomSale = (params) => {
|
|
3
|
+
console.log("[Mock] removeCustomSale called", params);
|
|
4
|
+
if (!params?.id) {
|
|
5
|
+
throw new Error("id is required");
|
|
6
|
+
}
|
|
7
|
+
const { id } = params;
|
|
8
|
+
const sales = MOCK_CART.customSales ?? [];
|
|
9
|
+
const index = sales.findIndex(s => s.id === id);
|
|
10
|
+
if (index === -1) {
|
|
11
|
+
throw new Error(`Custom sale with id ${id} not found`);
|
|
12
|
+
}
|
|
13
|
+
const sale = sales[index];
|
|
14
|
+
// Remove from cart
|
|
15
|
+
sales.splice(index, 1);
|
|
16
|
+
// Recalculate totals
|
|
17
|
+
const lineTotal = sale.price * sale.quantity;
|
|
18
|
+
MOCK_CART.subtotal -= lineTotal;
|
|
19
|
+
MOCK_CART.total -= lineTotal;
|
|
20
|
+
MOCK_CART.amountToBeCharged = MOCK_CART.total;
|
|
21
|
+
MOCK_CART.remainingBalance = MOCK_CART.total;
|
|
22
|
+
// Publish custom-sale-removed event so cart subscribers refresh
|
|
23
|
+
mockPublishEvent("cart", "custom-sale-removed", { customSale: sale, id });
|
|
24
|
+
return Promise.resolve({
|
|
25
|
+
success: true,
|
|
26
|
+
id,
|
|
27
|
+
timestamp: new Date().toISOString()
|
|
28
|
+
});
|
|
29
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { MOCK_CART } from "../../demo/database";
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
2
|
export const mockRemoveCustomerFromCart = async () => {
|
|
3
3
|
console.log("[Mock] removeCustomerFromCart called");
|
|
4
4
|
// Actually remove the customer from the mock cart
|
|
5
5
|
MOCK_CART.customer = null;
|
|
6
|
+
// Publish customer-removed event so cart subscribers refresh
|
|
7
|
+
mockPublishEvent('cart', 'customer-removed', {});
|
|
6
8
|
return {
|
|
7
9
|
success: true,
|
|
8
10
|
timestamp: new Date().toISOString()
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
export const mockRemoveOrderNote = () => {
|
|
3
|
+
console.log("[Mock] removeOrderNote called");
|
|
4
|
+
// Clear the active cart's note.
|
|
5
|
+
MOCK_CART.orderNotes = undefined;
|
|
6
|
+
// Publish order-note-removed event so cart subscribers refresh.
|
|
7
|
+
mockPublishEvent("cart", "order-note-removed", {});
|
|
8
|
+
return Promise.resolve({
|
|
9
|
+
success: true,
|
|
10
|
+
timestamp: new Date().toISOString()
|
|
11
|
+
});
|
|
12
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
export const mockRemoveProductDiscount = (params) => {
|
|
3
|
+
console.log("[Mock] removeProductDiscount called", params);
|
|
4
|
+
const item = params?.internalId
|
|
5
|
+
? MOCK_CART.products.find(p => p.internalId === params.internalId)
|
|
6
|
+
: MOCK_CART.products[MOCK_CART.products.length - 1];
|
|
7
|
+
if (item) {
|
|
8
|
+
delete item.discount;
|
|
9
|
+
// Publish so cart subscribers refresh.
|
|
10
|
+
mockPublishEvent("cart", "product-discount-removed", { internalId: params?.internalId });
|
|
11
|
+
}
|
|
12
|
+
return Promise.resolve({
|
|
13
|
+
success: true,
|
|
14
|
+
internalId: params?.internalId,
|
|
15
|
+
timestamp: new Date().toISOString()
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
export const mockRemoveProductFee = (params) => {
|
|
3
|
+
console.log("[Mock] removeProductFee called", params);
|
|
4
|
+
const item = params?.internalId
|
|
5
|
+
? MOCK_CART.products.find(p => p.internalId === params.internalId)
|
|
6
|
+
: MOCK_CART.products[MOCK_CART.products.length - 1];
|
|
7
|
+
if (item) {
|
|
8
|
+
delete item.fee;
|
|
9
|
+
// Publish so cart subscribers refresh.
|
|
10
|
+
mockPublishEvent("cart", "product-fee-removed", { internalId: params?.internalId });
|
|
11
|
+
}
|
|
12
|
+
return Promise.resolve({
|
|
13
|
+
success: true,
|
|
14
|
+
internalId: params?.internalId,
|
|
15
|
+
timestamp: new Date().toISOString()
|
|
16
|
+
});
|
|
17
|
+
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MOCK_CART, mockPublishEvent } from "../../demo/database";
|
|
2
|
-
export const mockRemoveProductFromCart =
|
|
2
|
+
export const mockRemoveProductFromCart = (params) => {
|
|
3
3
|
console.log("[Mock] removeProductFromCart called", params);
|
|
4
4
|
if (!params?.internalId) {
|
|
5
|
-
throw new Error(
|
|
5
|
+
throw new Error("internalId is required");
|
|
6
6
|
}
|
|
7
7
|
const { internalId } = params;
|
|
8
8
|
// Find the product in the cart
|
|
@@ -20,13 +20,13 @@ export const mockRemoveProductFromCart = async (params) => {
|
|
|
20
20
|
MOCK_CART.amountToBeCharged = MOCK_CART.total;
|
|
21
21
|
MOCK_CART.remainingBalance = MOCK_CART.total;
|
|
22
22
|
// Publish product-deleted event
|
|
23
|
-
mockPublishEvent(
|
|
23
|
+
mockPublishEvent("cart", "product-deleted", {
|
|
24
24
|
product: product,
|
|
25
25
|
internalId: internalId
|
|
26
26
|
});
|
|
27
|
-
return {
|
|
27
|
+
return Promise.resolve({
|
|
28
28
|
success: true,
|
|
29
29
|
internalId: internalId,
|
|
30
30
|
timestamp: new Date().toISOString()
|
|
31
|
-
};
|
|
31
|
+
});
|
|
32
32
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const mockResolveExtensionOverlay = async (_params) => ({ success: true });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { InterceptorReturn } from "../../interceptors/types";
|
|
2
|
+
export interface ResolveExtensionOverlayParams {
|
|
3
|
+
overlayId: string;
|
|
4
|
+
result: InterceptorReturn;
|
|
5
|
+
}
|
|
6
|
+
export interface ResolveExtensionOverlayResponse {
|
|
7
|
+
success: boolean;
|
|
8
|
+
}
|
|
9
|
+
export type ResolveExtensionOverlay = (params: ResolveExtensionOverlayParams) => Promise<ResolveExtensionOverlayResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MOCK_PARKED_ORDERS, MOCK_CART, resetMockCart } from "../../demo/database";
|
|
1
|
+
import { MOCK_PARKED_ORDERS, MOCK_CART, resetMockCart, mockPublishEvent } from "../../demo/database";
|
|
2
2
|
export const mockResumeParkedOrder = async (params) => {
|
|
3
3
|
console.log("[Mock] resumeParkedOrder called", params);
|
|
4
4
|
const orderId = params?.orderId;
|
|
@@ -45,6 +45,9 @@ export const mockResumeParkedOrder = async (params) => {
|
|
|
45
45
|
MOCK_CART.remainingBalance = MOCK_CART.total;
|
|
46
46
|
// Remove from parked
|
|
47
47
|
MOCK_PARKED_ORDERS.splice(index, 1);
|
|
48
|
+
// Refresh the restored cart and the order lists.
|
|
49
|
+
mockPublishEvent("cart", "parked-order-resumed", { orderId });
|
|
50
|
+
mockPublishEvent("orders", "parked-order-resumed", { orderId });
|
|
48
51
|
return {
|
|
49
52
|
success: true,
|
|
50
53
|
order: orderToResume,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
export interface ResumeParkedOrderParams {
|
|
3
4
|
orderId: string;
|
|
4
5
|
}
|
|
@@ -6,5 +7,7 @@ export interface ResumeParkedOrderResponse {
|
|
|
6
7
|
success: boolean;
|
|
7
8
|
order: CFOrder;
|
|
8
9
|
timestamp: string;
|
|
10
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
11
|
+
transitionResult?: CFTransitionResult;
|
|
9
12
|
}
|
|
10
13
|
export type ResumeParkedOrder = (params?: ResumeParkedOrderParams) => Promise<ResumeParkedOrderResponse>;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { applyMockPayment, MOCK_CART } from "../../demo/database";
|
|
2
2
|
export const mockTapToPayPayment = async (params) => {
|
|
3
3
|
console.log("[Mock] tapToPayPayment called", params);
|
|
4
4
|
// Simulate Tap to Pay interaction
|
|
5
5
|
window.alert("Demo: Processing Tap to Pay...\n(Please tap card or device on screen)");
|
|
6
|
+
const due = params?.amount ?? MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
7
|
+
const order = applyMockPayment(due, "card", "tapToPay");
|
|
6
8
|
return {
|
|
7
9
|
success: true,
|
|
8
|
-
amount:
|
|
10
|
+
amount: due,
|
|
9
11
|
paymentType: "tapToPay",
|
|
10
|
-
order
|
|
12
|
+
order,
|
|
11
13
|
timestamp: new Date().toISOString()
|
|
12
14
|
};
|
|
13
15
|
};
|