@final-commerce/command-frame 0.5.0 → 0.6.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/README.md +5 -5
- package/dist/CommonTypes.d.ts +6 -6
- package/dist/CommonTypes.js +2 -2
- package/dist/actions/add-cart-discount/mock.d.ts +1 -1
- package/dist/actions/add-cart-discount/mock.js +8 -8
- package/dist/actions/add-cart-fee/mock.d.ts +1 -1
- package/dist/actions/add-cart-fee/mock.js +8 -8
- package/dist/actions/add-product-to-cart/mock.d.ts +1 -1
- package/dist/actions/add-product-to-cart/mock.js +24 -10
- package/dist/actions/add-product-to-cart/types.d.ts +13 -1
- package/dist/actions/adjust-inventory/mock.d.ts +1 -1
- package/dist/actions/adjust-inventory/mock.js +6 -6
- package/dist/actions/apply-transition/mock.d.ts +1 -1
- package/dist/actions/apply-transition/mock.js +8 -8
- package/dist/actions/apply-transition/types.d.ts +1 -1
- package/dist/actions/authenticate-user/mock.d.ts +1 -1
- package/dist/actions/authenticate-user/mock.js +3 -3
- package/dist/actions/calculate-refund-total/action.d.ts +1 -1
- package/dist/actions/calculate-refund-total/action.js +2 -2
- package/dist/actions/can-transition/types.d.ts +1 -1
- package/dist/actions/cash-payment/mock.d.ts +1 -1
- package/dist/actions/cash-payment/mock.js +10 -10
- package/dist/actions/cash-payment/types.d.ts +1 -1
- package/dist/actions/extension-payment/mock.d.ts +1 -1
- package/dist/actions/extension-payment/mock.js +3 -3
- package/dist/actions/extension-payment/types.d.ts +1 -1
- package/dist/actions/get-available-transitions/mock.d.ts +1 -1
- package/dist/actions/get-available-transitions/mock.js +19 -19
- package/dist/actions/get-final-context/mock.d.ts +1 -1
- package/dist/actions/get-final-context/mock.js +2 -2
- package/dist/actions/get-products/mock.d.ts +1 -1
- package/dist/actions/get-products/mock.js +26 -9
- package/dist/actions/get-refunds/types.d.ts +1 -1
- package/dist/actions/get-remaining-refundable-quantities/action.d.ts +1 -1
- package/dist/actions/get-remaining-refundable-quantities/action.js +2 -2
- package/dist/actions/get-remaining-refundable-quantities/mock.d.ts +1 -1
- package/dist/actions/get-remaining-refundable-quantities/mock.js +2 -2
- package/dist/actions/integration-payment/types.d.ts +1 -1
- package/dist/actions/park-order/types.d.ts +1 -1
- package/dist/actions/partial-payment/mock.d.ts +1 -1
- package/dist/actions/partial-payment/mock.js +8 -8
- package/dist/actions/partial-payment/types.d.ts +1 -1
- package/dist/actions/print/mock.d.ts +1 -1
- package/dist/actions/print/mock.js +9 -9
- package/dist/actions/print/types.d.ts +6 -6
- package/dist/actions/redeem-payment/types.d.ts +1 -1
- package/dist/actions/remove-cart-fee/mock.d.ts +1 -1
- package/dist/actions/remove-cart-fee/mock.js +7 -7
- package/dist/actions/remove-product-from-cart/mock.d.ts +1 -1
- package/dist/actions/remove-product-from-cart/mock.js +11 -8
- package/dist/actions/resume-parked-order/types.d.ts +1 -1
- package/dist/actions/select-all-refund-items/action.d.ts +1 -1
- package/dist/actions/select-all-refund-items/action.js +2 -2
- package/dist/actions/set-active-product/mock.d.ts +1 -1
- package/dist/actions/set-active-product/mock.js +19 -14
- package/dist/actions/set-active-refund/types.d.ts +1 -1
- package/dist/actions/tap-to-pay-payment/mock.d.ts +1 -1
- package/dist/actions/tap-to-pay-payment/mock.js +6 -6
- package/dist/actions/tap-to-pay-payment/types.d.ts +1 -1
- package/dist/actions/terminal-payment/mock.d.ts +1 -1
- package/dist/actions/terminal-payment/mock.js +6 -6
- package/dist/actions/terminal-payment/types.d.ts +2 -2
- package/dist/actions/update-cart-item-quantity/mock.d.ts +1 -1
- package/dist/actions/update-cart-item-quantity/mock.js +23 -15
- package/dist/actions/update-cart-item-quantity/types.d.ts +8 -1
- package/dist/actions/upsert-custom-table-data/mock.d.ts +1 -1
- package/dist/actions/upsert-custom-table-data/mock.js +3 -3
- package/dist/demo/database.js +30 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@ Command Frame provides a structured way to build integrations that run inside Fi
|
|
|
10
10
|
|
|
11
11
|
The library provides three main capabilities:
|
|
12
12
|
|
|
13
|
-
| Capability | Purpose
|
|
14
|
-
| ------------------- |
|
|
15
|
-
| **Commands** | Call host functions from the iframe (e.g. get products, open cash drawer)
|
|
16
|
-
| **Pub/Sub** | Subscribe to real-time events from the host (e.g. cart changes, payments)
|
|
17
|
-
| **Refund commands** | Refund payments to gift cards or redeem tenders via `redeemRefund`, or mixed-destination legs on `processPartialRefund`; query engine capacity with `getRefundPlan`; pre-gate UI with `checkPermission` (`issue_refunds` is enforced runtime-side) | Request/response per call
|
|
13
|
+
| Capability | Purpose | Scope |
|
|
14
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
15
|
+
| **Commands** | Call host functions from the iframe (e.g. get products, open cash drawer) | Request/response per call |
|
|
16
|
+
| **Pub/Sub** | Subscribe to real-time events from the host (e.g. cart changes, payments) | Page-scoped (while iframe is mounted) |
|
|
17
|
+
| **Refund commands** | Refund payments to gift cards or redeem tenders via `redeemRefund`, or mixed-destination legs on `processPartialRefund`; query engine capacity with `getRefundPlan`; pre-gate UI with `checkPermission` (`issue_refunds` is enforced runtime-side) | Request/response per call |
|
|
18
18
|
|
|
19
19
|
Domain models (orders, cart, customers, products, and related types) are documented in **[Types reference](./src/types/README.md)**.
|
|
20
20
|
|
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
import type { Tax, Tip, Address, MetadataItem, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment } from
|
|
3
|
-
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from
|
|
1
|
+
export * from './common-types';
|
|
2
|
+
import type { Tax, Tip, Address, MetadataItem, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment } from '@final-commerce/common/pos-types';
|
|
3
|
+
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from '@final-commerce/common';
|
|
4
4
|
/** Open record used as a base for active entities. */
|
|
5
5
|
export type CFActiveEntity = Record<string, unknown>;
|
|
6
6
|
export type CFDiscount = Discount;
|
|
@@ -52,7 +52,7 @@ export type CFActiveCart = ActiveCart;
|
|
|
52
52
|
export type CFActivePark = ActivePark;
|
|
53
53
|
export type CFActiveCompany = ActiveCompany;
|
|
54
54
|
/** Tile kinds a SmartGrid cell can represent. Mirrors common's `BaseTile['type']`. */
|
|
55
|
-
export type CFTileType =
|
|
55
|
+
export type CFTileType = 'empty' | 'product' | 'action' | 'category' | 'folder' | 'back';
|
|
56
56
|
/**
|
|
57
57
|
* A single positioned cell in a SmartGrid layout. The wire/extension-facing shape
|
|
58
58
|
* (Render's adapter maps this to/from common's `BaseTile`).
|
|
@@ -96,7 +96,7 @@ export interface CFActiveRefundDetails {
|
|
|
96
96
|
refundProcessingStatus?: CFRefundProcessingStatus | null;
|
|
97
97
|
sessionRefundedTotal?: number;
|
|
98
98
|
}
|
|
99
|
-
export type CFProjectName =
|
|
99
|
+
export type CFProjectName = 'kaching' | 'Manage';
|
|
100
100
|
export interface CFContextRender {
|
|
101
101
|
userId: string | null;
|
|
102
102
|
companyId: string | null;
|
|
@@ -126,7 +126,7 @@ export interface CFContextRender {
|
|
|
126
126
|
thousandSeparator: string | null;
|
|
127
127
|
decimalSeparator: string | null;
|
|
128
128
|
user: Record<string, unknown> | null;
|
|
129
|
-
company: Omit<Record<string, unknown>,
|
|
129
|
+
company: Omit<Record<string, unknown>, 'settings'> | null;
|
|
130
130
|
station: Record<string, unknown> | null;
|
|
131
131
|
outlet: Record<string, unknown> | null;
|
|
132
132
|
timestamp: string;
|
package/dist/CommonTypes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from './common-types';
|
|
2
2
|
// Enums — re-exported from common (single source). CurrencyCode keeps its name;
|
|
3
3
|
// CFProductType/CFUserTypes alias common's ProductType/UserTypes. Note: common's
|
|
4
4
|
// UserTypes uses `COMPANY_OWNER` where command-frame's enum previously had `OWNER`
|
|
5
5
|
// (same value `'owner'`).
|
|
6
|
-
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from
|
|
6
|
+
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from '@final-commerce/common';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddCartDiscount } from
|
|
1
|
+
import { AddCartDiscount } from './types';
|
|
2
2
|
export declare const mockAddCartDiscount: AddCartDiscount;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { MOCK_CART, mockPublishEvent } from
|
|
2
|
-
import { percentToFraction, requireMinorUnitsInteger } from
|
|
1
|
+
import { MOCK_CART, mockPublishEvent } from '../../demo/database';
|
|
2
|
+
import { percentToFraction, requireMinorUnitsInteger } from '../../demo/units';
|
|
3
3
|
export const mockAddCartDiscount = async (params) => {
|
|
4
|
-
console.log(
|
|
4
|
+
console.log('[Mock] addCartDiscount called', params);
|
|
5
5
|
if (params) {
|
|
6
6
|
// FI-6991: a fixed amount arrives as an INTEGER in MINOR units (500 =
|
|
7
7
|
// $5.00) and is stored directly; a percent arrives raw (50 = 50%) and is
|
|
8
8
|
// stored as a fraction (0.5). Same as the real handler.
|
|
9
9
|
const value = params.isPercent
|
|
10
10
|
? percentToFraction(params.amount)
|
|
11
|
-
: requireMinorUnitsInteger(params.amount,
|
|
11
|
+
: requireMinorUnitsInteger(params.amount, 'Discount amount');
|
|
12
12
|
MOCK_CART.discount = {
|
|
13
13
|
value,
|
|
14
14
|
isPercent: params.isPercent,
|
|
15
|
-
label: params.label
|
|
15
|
+
label: params.label,
|
|
16
16
|
};
|
|
17
17
|
if (params.isPercent) {
|
|
18
18
|
MOCK_CART.total = MOCK_CART.subtotal * (1 - value);
|
|
@@ -24,14 +24,14 @@ export const mockAddCartDiscount = async (params) => {
|
|
|
24
24
|
MOCK_CART.remainingBalance = MOCK_CART.total;
|
|
25
25
|
// Publish cart-discount-added event
|
|
26
26
|
mockPublishEvent('cart', 'cart-discount-added', {
|
|
27
|
-
discount: MOCK_CART.discount
|
|
27
|
+
discount: MOCK_CART.discount,
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
return {
|
|
31
31
|
success: true,
|
|
32
32
|
amount: params?.amount || 0,
|
|
33
33
|
isPercent: params?.isPercent || false,
|
|
34
|
-
label: params?.label ||
|
|
35
|
-
timestamp: new Date().toISOString()
|
|
34
|
+
label: params?.label || '',
|
|
35
|
+
timestamp: new Date().toISOString(),
|
|
36
36
|
};
|
|
37
37
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddCartFee } from
|
|
1
|
+
import { AddCartFee } from './types';
|
|
2
2
|
export declare const mockAddCartFee: AddCartFee;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { MOCK_CART } from
|
|
2
|
-
import { percentToFraction, requireMinorUnitsInteger } from
|
|
1
|
+
import { MOCK_CART } from '../../demo/database';
|
|
2
|
+
import { percentToFraction, requireMinorUnitsInteger } from '../../demo/units';
|
|
3
3
|
export const mockAddCartFee = async (params) => {
|
|
4
|
-
console.log(
|
|
4
|
+
console.log('[Mock] addCartFee called', params);
|
|
5
5
|
if (params) {
|
|
6
6
|
if (!MOCK_CART.customFee)
|
|
7
7
|
MOCK_CART.customFee = [];
|
|
@@ -10,13 +10,13 @@ export const mockAddCartFee = async (params) => {
|
|
|
10
10
|
// stored as a fraction (0.5). Same as the real handler.
|
|
11
11
|
const storedAmount = params.isPercent
|
|
12
12
|
? percentToFraction(params.amount)
|
|
13
|
-
: requireMinorUnitsInteger(params.amount,
|
|
13
|
+
: requireMinorUnitsInteger(params.amount, 'Fee amount');
|
|
14
14
|
MOCK_CART.customFee.push({
|
|
15
|
-
label: params.label ||
|
|
15
|
+
label: params.label || 'Fee',
|
|
16
16
|
amount: storedAmount,
|
|
17
17
|
isPercent: params.isPercent || false,
|
|
18
18
|
applyTaxes: params.applyTaxes || false,
|
|
19
|
-
taxTableId: params.taxTableId
|
|
19
|
+
taxTableId: params.taxTableId,
|
|
20
20
|
});
|
|
21
21
|
const feeAmount = params.isPercent ? MOCK_CART.subtotal * storedAmount : storedAmount;
|
|
22
22
|
MOCK_CART.total += feeAmount;
|
|
@@ -27,8 +27,8 @@ export const mockAddCartFee = async (params) => {
|
|
|
27
27
|
success: true,
|
|
28
28
|
amount: params?.amount || 0,
|
|
29
29
|
isPercent: params?.isPercent || false,
|
|
30
|
-
label: params?.label ||
|
|
30
|
+
label: params?.label || '',
|
|
31
31
|
applyTaxes: params?.applyTaxes || false,
|
|
32
|
-
timestamp: new Date().toISOString()
|
|
32
|
+
timestamp: new Date().toISOString(),
|
|
33
33
|
};
|
|
34
34
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AddProductToCart } from
|
|
1
|
+
import { AddProductToCart } from './types';
|
|
2
2
|
export declare const mockAddProductToCart: AddProductToCart;
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { MOCK_CART, MOCK_PRODUCTS, mockPublishEvent } from
|
|
1
|
+
import { MOCK_CART, MOCK_PRODUCTS, mockPublishEvent } from '../../demo/database';
|
|
2
|
+
import { extendPrice, isValidQuantity, resolveUnit } from '@final-commerce/common';
|
|
2
3
|
export const mockAddProductToCart = async (params) => {
|
|
3
|
-
console.log(
|
|
4
|
+
console.log('[Mock] addProductToCart called', params);
|
|
4
5
|
const variantId = params?.variantId;
|
|
5
6
|
const quantity = params?.quantity || 1;
|
|
7
|
+
if (!Number.isFinite(quantity) || quantity <= 0) {
|
|
8
|
+
throw new Error(`${quantity} is not a quantity`);
|
|
9
|
+
}
|
|
6
10
|
let product = MOCK_PRODUCTS[0]; // Default fallback
|
|
7
11
|
let variant = product.variants[0];
|
|
8
12
|
// Determine variant and product from variantId
|
|
9
13
|
if (variantId) {
|
|
10
14
|
// Search through all products to find the one containing this variant
|
|
11
15
|
for (const p of MOCK_PRODUCTS) {
|
|
12
|
-
const foundVariant = p.variants.find(v => v._id === variantId);
|
|
16
|
+
const foundVariant = p.variants.find((v) => v._id === variantId);
|
|
13
17
|
if (foundVariant) {
|
|
14
18
|
product = p;
|
|
15
19
|
variant = foundVariant;
|
|
@@ -17,12 +21,20 @@ export const mockAddProductToCart = async (params) => {
|
|
|
17
21
|
}
|
|
18
22
|
}
|
|
19
23
|
}
|
|
24
|
+
// A measured variant carries a resolved unit; the host does the same. What the unit can
|
|
25
|
+
// express is its precision — 1.5 of a kilogram is a sale, 1.5 of a piece is a typo.
|
|
26
|
+
const unit = variant.unitId ? resolveUnit(variant.unitId) : undefined;
|
|
27
|
+
if (!isValidQuantity(quantity, unit ?? { unitId: 'piece', ratioToBase: 1, precision: 0 })) {
|
|
28
|
+
throw new Error(unit
|
|
29
|
+
? `${quantity} is finer than ${unit.abbreviation} can express (${unit.precision} decimals)`
|
|
30
|
+
: `${product.name} is sold by the piece, so ${quantity} is not a quantity it can sell in`);
|
|
31
|
+
}
|
|
20
32
|
// Add to MOCK_CART
|
|
21
|
-
const internalId = product._id +
|
|
33
|
+
const internalId = product._id + '_' + Date.now();
|
|
22
34
|
// Process optional fields for mock
|
|
23
35
|
let note = undefined;
|
|
24
36
|
if (params?.notes) {
|
|
25
|
-
note = Array.isArray(params.notes) ? params.notes.join(
|
|
37
|
+
note = Array.isArray(params.notes) ? params.notes.join(', ') : params.notes;
|
|
26
38
|
}
|
|
27
39
|
const activeProduct = {
|
|
28
40
|
...product,
|
|
@@ -33,16 +45,18 @@ export const mockAddProductToCart = async (params) => {
|
|
|
33
45
|
price: Number(variant.price),
|
|
34
46
|
taxTableId: product.taxTable,
|
|
35
47
|
stock: variant.inventory?.[0]?.stock || 0,
|
|
48
|
+
...(unit ? { unit } : {}),
|
|
36
49
|
images: product.images || [],
|
|
37
50
|
localQuantity: quantity,
|
|
38
51
|
sku: variant.sku,
|
|
39
|
-
attributes: variant.attributes.map(a => `${a.name}: ${a.value}`).join(
|
|
40
|
-
note: note
|
|
52
|
+
attributes: variant.attributes.map((a) => `${a.name}: ${a.value}`).join(', '),
|
|
53
|
+
note: note,
|
|
41
54
|
// discount/fee could be added here to mock object if CFActiveProduct supports it
|
|
42
55
|
};
|
|
43
56
|
MOCK_CART.products.push(activeProduct);
|
|
44
|
-
// Recalculate totals
|
|
45
|
-
|
|
57
|
+
// Recalculate totals. extendPrice, not a raw multiply: a fractional quantity times an
|
|
58
|
+
// integer-minor price leaves fractional cents, which no order may carry.
|
|
59
|
+
const lineTotal = extendPrice(activeProduct.price, quantity);
|
|
46
60
|
MOCK_CART.subtotal += lineTotal;
|
|
47
61
|
// Simple total calculation (ignoring taxes/fees for mock simplicity unless needed)
|
|
48
62
|
MOCK_CART.total += lineTotal;
|
|
@@ -57,6 +71,6 @@ export const mockAddProductToCart = async (params) => {
|
|
|
57
71
|
internalId: activeProduct.internalId,
|
|
58
72
|
name: activeProduct.name,
|
|
59
73
|
quantity: quantity,
|
|
60
|
-
timestamp: new Date().toISOString()
|
|
74
|
+
timestamp: new Date().toISOString(),
|
|
61
75
|
};
|
|
62
76
|
};
|
|
@@ -3,7 +3,19 @@ import type { AddProductFeeParams } from "../add-product-fee/types";
|
|
|
3
3
|
export interface AddProductToCartParams {
|
|
4
4
|
/** ID of the variant to add. */
|
|
5
5
|
variantId: string;
|
|
6
|
-
/**
|
|
6
|
+
/**
|
|
7
|
+
* Defaults to 1. **May be fractional** — a variant sold by weight, volume or length is priced
|
|
8
|
+
* per its own unit and keyed in that unit, so `0.456` kg is a quantity, not a typo.
|
|
9
|
+
*
|
|
10
|
+
* How many decimals are allowed is the variant's own business: `variant.unit.precision` —
|
|
11
|
+
* `3` for a litre, `0` for anything sold by the piece. The engine refuses a quantity finer
|
|
12
|
+
* than that and says which unit it was measured against; do not round, floor or clamp before
|
|
13
|
+
* sending, and never key a quantity in base units to work around it (a per-100g price with a
|
|
14
|
+
* gram count is explicitly not supported).
|
|
15
|
+
*
|
|
16
|
+
* A quantity field should take its step and its decimal count from `variant.unit.precision`,
|
|
17
|
+
* not from a constant.
|
|
18
|
+
*/
|
|
7
19
|
quantity?: number;
|
|
8
20
|
/** Array of discounts to apply immediately. */
|
|
9
21
|
discounts?: AddProductDiscountParams[];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AdjustInventory } from
|
|
1
|
+
import { AdjustInventory } from './types';
|
|
2
2
|
export declare const mockAdjustInventory: AdjustInventory;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { MOCK_PRODUCTS } from
|
|
1
|
+
import { MOCK_PRODUCTS } from '../../demo/database';
|
|
2
2
|
export const mockAdjustInventory = async (params) => {
|
|
3
|
-
console.log(
|
|
3
|
+
console.log('[Mock] adjustInventory called', params);
|
|
4
4
|
let newStock = 0;
|
|
5
5
|
// Real handler keys off variantId (falling back to the active product's
|
|
6
6
|
// variant); mirror that here by finding the owning product for the variant.
|
|
@@ -8,7 +8,7 @@ export const mockAdjustInventory = async (params) => {
|
|
|
8
8
|
const variantId = params.variantId;
|
|
9
9
|
let variant;
|
|
10
10
|
for (const product of MOCK_PRODUCTS) {
|
|
11
|
-
const match = product.variants.find(v => v._id === variantId);
|
|
11
|
+
const match = product.variants.find((v) => v._id === variantId);
|
|
12
12
|
if (match) {
|
|
13
13
|
variant = match;
|
|
14
14
|
break;
|
|
@@ -32,9 +32,9 @@ export const mockAdjustInventory = async (params) => {
|
|
|
32
32
|
}
|
|
33
33
|
return {
|
|
34
34
|
success: true,
|
|
35
|
-
amount: params?.amount ||
|
|
36
|
-
stockType: params?.stockType ||
|
|
35
|
+
amount: params?.amount || '0',
|
|
36
|
+
stockType: params?.stockType || 'set',
|
|
37
37
|
newStock,
|
|
38
|
-
timestamp: new Date().toISOString()
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
39
|
};
|
|
40
40
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApplyTransitionParams, ApplyTransitionResponse } from
|
|
1
|
+
import type { ApplyTransitionParams, ApplyTransitionResponse } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Mock implementation: applies all transitions except a known-invalid one
|
|
4
4
|
* so the demo app can show both successful and blocked responses.
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
export const applyTransitionMock = (params) => {
|
|
6
6
|
const { targetFulfillmentState } = params;
|
|
7
|
-
if (targetFulfillmentState ===
|
|
7
|
+
if (targetFulfillmentState === 'cancelled') {
|
|
8
8
|
return Promise.resolve({
|
|
9
9
|
result: {
|
|
10
10
|
allowed: false,
|
|
11
|
-
blockedBy:
|
|
12
|
-
guard:
|
|
13
|
-
reason:
|
|
14
|
-
}
|
|
11
|
+
blockedBy: 'condition',
|
|
12
|
+
guard: 'no-cancel-open-order',
|
|
13
|
+
reason: 'Cannot cancel an order with open items',
|
|
14
|
+
},
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
17
|
return Promise.resolve({
|
|
18
18
|
result: { allowed: true },
|
|
19
|
-
from: { payment:
|
|
20
|
-
to: { payment:
|
|
21
|
-
displayState: `unpaid / ${targetFulfillmentState}
|
|
19
|
+
from: { payment: 'unpaid', fulfillment: 'draft' },
|
|
20
|
+
to: { payment: 'unpaid', fulfillment: targetFulfillmentState },
|
|
21
|
+
displayState: `unpaid / ${targetFulfillmentState}`,
|
|
22
22
|
});
|
|
23
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CFStatePair, CFTransitionResult } from
|
|
1
|
+
import type { CFStatePair, CFTransitionResult } from '../../common-types/order-state';
|
|
2
2
|
export interface ApplyTransitionParams {
|
|
3
3
|
/** Order to transition. Omit to target the active order — materializing one from the live cart if none exists. */
|
|
4
4
|
orderId?: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { AuthenticateUser } from
|
|
1
|
+
import { AuthenticateUser } from './types';
|
|
2
2
|
export declare const mockAuthenticateUser: AuthenticateUser;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const mockAuthenticateUser = async (params) => {
|
|
2
|
-
console.log(
|
|
2
|
+
console.log('[Mock] authenticateUser called', params);
|
|
3
3
|
// Headless path requires both userId and pin together (mirrors the handler guard).
|
|
4
4
|
if ((params?.userId || params?.pin) && !(params?.userId && params?.pin)) {
|
|
5
|
-
throw new Error(
|
|
5
|
+
throw new Error('userId and pin must be provided together');
|
|
6
6
|
}
|
|
7
7
|
return {
|
|
8
8
|
success: true,
|
|
9
9
|
roleIds: params?.roleIds || [],
|
|
10
|
-
timestamp: new Date().toISOString()
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
11
|
};
|
|
12
12
|
};
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Calculate refund total action
|
|
3
3
|
* Calls the calculateRefundTotal action on the parent window
|
|
4
4
|
*/
|
|
5
|
-
import type { CalculateRefundTotal } from
|
|
5
|
+
import type { CalculateRefundTotal } from './types';
|
|
6
6
|
export declare const calculateRefundTotal: CalculateRefundTotal;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Calculate refund total action
|
|
3
3
|
* Calls the calculateRefundTotal action on the parent window
|
|
4
4
|
*/
|
|
5
|
-
import { commandFrameClient } from
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
6
|
export const calculateRefundTotal = async (params) => {
|
|
7
|
-
return await commandFrameClient.call(
|
|
7
|
+
return await commandFrameClient.call('calculateRefundTotal', params);
|
|
8
8
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CFStatePair, CFTransitionResult } from
|
|
1
|
+
import type { CFStatePair, CFTransitionResult } from '../../common-types/order-state';
|
|
2
2
|
export interface CanTransitionParams {
|
|
3
3
|
/** Order to evaluate. Defaults to the active order; if there is no active order (or none matches), evaluates as a brand-new order (from = null). */
|
|
4
4
|
orderId?: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { CashPayment } from
|
|
1
|
+
import { CashPayment } from './types';
|
|
2
2
|
export declare const mockCashPayment: CashPayment;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { applyMockPayment, MOCK_CART } from
|
|
1
|
+
import { applyMockPayment, MOCK_CART } from '../../demo/database';
|
|
2
2
|
export const mockCashPayment = async (params) => {
|
|
3
|
-
console.log(
|
|
3
|
+
console.log('[Mock] cashPayment called', params);
|
|
4
4
|
const fail = (reason) => {
|
|
5
5
|
console.warn(`[Mock] cashPayment rejected: ${reason}`);
|
|
6
6
|
return {
|
|
@@ -9,17 +9,17 @@ export const mockCashPayment = async (params) => {
|
|
|
9
9
|
openChangeCalculator: params?.openChangeCalculator ?? false,
|
|
10
10
|
change: 0,
|
|
11
11
|
cashRounding: 0,
|
|
12
|
-
paymentType:
|
|
12
|
+
paymentType: 'cash',
|
|
13
13
|
order: null,
|
|
14
14
|
timestamp: new Date().toISOString(),
|
|
15
15
|
saleFinalized: false,
|
|
16
|
-
remainingBalance: 0
|
|
16
|
+
remainingBalance: 0,
|
|
17
17
|
};
|
|
18
18
|
};
|
|
19
19
|
// Contract: `amount` is required, integer MINOR currency units — same
|
|
20
20
|
// scale as the mock cart's totals, so comparisons are direct.
|
|
21
21
|
if (params?.amount === undefined || params.amount === null) {
|
|
22
|
-
return fail(
|
|
22
|
+
return fail('amount is required (integer minor currency units)');
|
|
23
23
|
}
|
|
24
24
|
const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
|
|
25
25
|
if (params.amount > balanceDue) {
|
|
@@ -38,16 +38,16 @@ export const mockCashPayment = async (params) => {
|
|
|
38
38
|
try {
|
|
39
39
|
const input = window.prompt(`Amount due: $${(params.amount / 100).toFixed(2)}\nEnter amount tendered (dollars):`, (params.amount / 100).toFixed(2));
|
|
40
40
|
if (input === null)
|
|
41
|
-
return fail(
|
|
41
|
+
return fail('cancelled');
|
|
42
42
|
const tendered = parseFloat(input);
|
|
43
43
|
if (!isNaN(tendered))
|
|
44
44
|
change = Math.round(tendered * 100) - params.amount;
|
|
45
45
|
}
|
|
46
46
|
catch (e) {
|
|
47
|
-
console.warn(
|
|
47
|
+
console.warn('Could not open prompt/alert (possibly in non-interactive environment)', e);
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
|
-
const order = applyMockPayment(params.amount,
|
|
50
|
+
const order = applyMockPayment(params.amount, 'cash', 'cash');
|
|
51
51
|
return {
|
|
52
52
|
success: true,
|
|
53
53
|
amount: params.amount,
|
|
@@ -55,10 +55,10 @@ export const mockCashPayment = async (params) => {
|
|
|
55
55
|
change,
|
|
56
56
|
tenderedAmount: params.tenderedAmount,
|
|
57
57
|
cashRounding: 0,
|
|
58
|
-
paymentType:
|
|
58
|
+
paymentType: 'cash',
|
|
59
59
|
order,
|
|
60
60
|
timestamp: new Date().toISOString(),
|
|
61
61
|
saleFinalized: true,
|
|
62
|
-
remainingBalance: 0
|
|
62
|
+
remainingBalance: 0,
|
|
63
63
|
};
|
|
64
64
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ExtensionPayment } from
|
|
1
|
+
import { ExtensionPayment } from './types';
|
|
2
2
|
export declare const mockExtensionPayment: ExtensionPayment;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { MOCK_ORDERS } from
|
|
1
|
+
import { MOCK_ORDERS } from '../../demo/database';
|
|
2
2
|
export const mockExtensionPayment = async (params) => {
|
|
3
|
-
const paymentType = params?.paymentType ??
|
|
3
|
+
const paymentType = params?.paymentType ?? 'redeem';
|
|
4
4
|
return {
|
|
5
5
|
success: true,
|
|
6
6
|
amount: params?.amount ?? null,
|
|
@@ -10,6 +10,6 @@ export const mockExtensionPayment = async (params) => {
|
|
|
10
10
|
change: 0,
|
|
11
11
|
cashRounding: 0,
|
|
12
12
|
saleFinalized: true,
|
|
13
|
-
remainingBalance: 0
|
|
13
|
+
remainingBalance: 0,
|
|
14
14
|
};
|
|
15
15
|
};
|
|
@@ -7,32 +7,32 @@
|
|
|
7
7
|
export const getAvailableTransitionsMock = () => Promise.resolve({
|
|
8
8
|
transitions: [
|
|
9
9
|
{
|
|
10
|
-
to: { payment:
|
|
11
|
-
displayLabel:
|
|
12
|
-
conditions: [{ met: true, description:
|
|
10
|
+
to: { payment: 'unpaid', fulfillment: 'in_progress' },
|
|
11
|
+
displayLabel: 'Start Preparing',
|
|
12
|
+
conditions: [{ met: true, description: 'Order has items' }],
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
|
-
to: { payment:
|
|
16
|
-
displayLabel:
|
|
17
|
-
conditions: [{ met: true, description:
|
|
15
|
+
to: { payment: 'unpaid', fulfillment: 'fulfilled' },
|
|
16
|
+
displayLabel: 'Mark Fulfilled',
|
|
17
|
+
conditions: [{ met: true, description: 'Order has items' }],
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
|
-
to: { payment:
|
|
21
|
-
displayLabel:
|
|
22
|
-
conditions: [{ met: true, description:
|
|
20
|
+
to: { payment: 'unpaid', fulfillment: 'on_hold' },
|
|
21
|
+
displayLabel: 'Park Order',
|
|
22
|
+
conditions: [{ met: true, description: 'Order is open' }],
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
|
-
to: { payment:
|
|
26
|
-
displayLabel:
|
|
27
|
-
conditions: [{ met: true, description:
|
|
25
|
+
to: { payment: 'paid', fulfillment: 'fulfilled' },
|
|
26
|
+
displayLabel: 'Complete Payment',
|
|
27
|
+
conditions: [{ met: true, description: 'Balance due > 0' }],
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
|
-
to: { payment:
|
|
31
|
-
displayLabel:
|
|
30
|
+
to: { payment: 'voided', fulfillment: 'cancelled' },
|
|
31
|
+
displayLabel: 'Void Order',
|
|
32
32
|
conditions: [
|
|
33
|
-
{ met: true, description:
|
|
34
|
-
{ met: false, description:
|
|
35
|
-
]
|
|
36
|
-
}
|
|
37
|
-
]
|
|
33
|
+
{ met: true, description: 'Order exists' },
|
|
34
|
+
{ met: false, description: 'No payments captured (mock: skipped)' },
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
38
|
});
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GetFinalContext } from
|
|
1
|
+
import { GetFinalContext } from './types';
|
|
2
2
|
export declare const mockGetFinalContext: GetFinalContext;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GetProducts } from
|
|
1
|
+
import { GetProducts } from './types';
|
|
2
2
|
export declare const mockGetProducts: GetProducts;
|