@final-commerce/command-frame 0.5.1 → 0.6.0-preprod.2

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.
Files changed (88) hide show
  1. package/dist/CommonTypes.d.ts +6 -6
  2. package/dist/CommonTypes.js +2 -2
  3. package/dist/actions/add-cart-discount/mock.d.ts +1 -1
  4. package/dist/actions/add-cart-discount/mock.js +8 -8
  5. package/dist/actions/add-cart-fee/mock.d.ts +1 -1
  6. package/dist/actions/add-cart-fee/mock.js +8 -8
  7. package/dist/actions/add-product-to-cart/mock.d.ts +1 -1
  8. package/dist/actions/add-product-to-cart/mock.js +24 -10
  9. package/dist/actions/add-product-to-cart/types.d.ts +15 -3
  10. package/dist/actions/adjust-inventory/mock.d.ts +1 -1
  11. package/dist/actions/adjust-inventory/mock.js +6 -6
  12. package/dist/actions/apply-transition/mock.d.ts +1 -1
  13. package/dist/actions/apply-transition/mock.js +8 -8
  14. package/dist/actions/apply-transition/types.d.ts +1 -1
  15. package/dist/actions/authenticate-user/mock.d.ts +1 -1
  16. package/dist/actions/authenticate-user/mock.js +3 -3
  17. package/dist/actions/calculate-refund-total/action.d.ts +1 -1
  18. package/dist/actions/calculate-refund-total/action.js +2 -2
  19. package/dist/actions/can-transition/types.d.ts +1 -1
  20. package/dist/actions/cash-payment/mock.d.ts +1 -1
  21. package/dist/actions/cash-payment/mock.js +10 -10
  22. package/dist/actions/cash-payment/types.d.ts +1 -1
  23. package/dist/actions/charge-moto/action.d.ts +6 -0
  24. package/dist/actions/charge-moto/action.js +8 -0
  25. package/dist/actions/charge-moto/mock.d.ts +2 -0
  26. package/dist/actions/charge-moto/mock.js +47 -0
  27. package/dist/actions/charge-moto/types.d.ts +53 -0
  28. package/dist/actions/charge-moto/types.js +1 -0
  29. package/dist/actions/create-payment-link/action.d.ts +6 -0
  30. package/dist/actions/create-payment-link/action.js +8 -0
  31. package/dist/actions/create-payment-link/mock.d.ts +2 -0
  32. package/dist/actions/create-payment-link/mock.js +35 -0
  33. package/dist/actions/create-payment-link/types.d.ts +27 -0
  34. package/dist/actions/create-payment-link/types.js +12 -0
  35. package/dist/actions/extension-payment/mock.d.ts +1 -1
  36. package/dist/actions/extension-payment/mock.js +3 -3
  37. package/dist/actions/extension-payment/types.d.ts +1 -1
  38. package/dist/actions/get-final-context/mock.d.ts +1 -1
  39. package/dist/actions/get-final-context/mock.js +2 -2
  40. package/dist/actions/get-products/mock.d.ts +1 -1
  41. package/dist/actions/get-products/mock.js +26 -9
  42. package/dist/actions/get-refunds/types.d.ts +1 -1
  43. package/dist/actions/get-remaining-refundable-quantities/action.d.ts +1 -1
  44. package/dist/actions/get-remaining-refundable-quantities/action.js +2 -2
  45. package/dist/actions/get-remaining-refundable-quantities/mock.d.ts +1 -1
  46. package/dist/actions/get-remaining-refundable-quantities/mock.js +2 -2
  47. package/dist/actions/get-time-clock-status/action.d.ts +6 -0
  48. package/dist/actions/get-time-clock-status/action.js +8 -0
  49. package/dist/actions/get-time-clock-status/mock.d.ts +2 -0
  50. package/dist/actions/get-time-clock-status/mock.js +17 -0
  51. package/dist/actions/get-time-clock-status/types.d.ts +18 -0
  52. package/dist/actions/get-time-clock-status/types.js +7 -0
  53. package/dist/actions/integration-payment/types.d.ts +1 -1
  54. package/dist/actions/park-order/types.d.ts +1 -1
  55. package/dist/actions/partial-payment/mock.d.ts +1 -1
  56. package/dist/actions/partial-payment/mock.js +8 -8
  57. package/dist/actions/partial-payment/types.d.ts +1 -1
  58. package/dist/actions/print/mock.d.ts +1 -1
  59. package/dist/actions/print/mock.js +9 -9
  60. package/dist/actions/print/types.d.ts +6 -6
  61. package/dist/actions/redeem-payment/types.d.ts +1 -1
  62. package/dist/actions/remove-cart-fee/mock.d.ts +1 -1
  63. package/dist/actions/remove-cart-fee/mock.js +7 -7
  64. package/dist/actions/remove-product-from-cart/mock.d.ts +1 -1
  65. package/dist/actions/remove-product-from-cart/mock.js +11 -8
  66. package/dist/actions/resume-parked-order/types.d.ts +1 -1
  67. package/dist/actions/select-all-refund-items/action.d.ts +1 -1
  68. package/dist/actions/select-all-refund-items/action.js +2 -2
  69. package/dist/actions/set-active-product/mock.d.ts +1 -1
  70. package/dist/actions/set-active-product/mock.js +19 -14
  71. package/dist/actions/set-active-refund/types.d.ts +1 -1
  72. package/dist/actions/tap-to-pay-payment/mock.d.ts +1 -1
  73. package/dist/actions/tap-to-pay-payment/mock.js +6 -6
  74. package/dist/actions/tap-to-pay-payment/types.d.ts +1 -1
  75. package/dist/actions/terminal-payment/mock.d.ts +1 -1
  76. package/dist/actions/terminal-payment/mock.js +6 -6
  77. package/dist/actions/terminal-payment/types.d.ts +2 -2
  78. package/dist/actions/update-cart-item-quantity/mock.d.ts +1 -1
  79. package/dist/actions/update-cart-item-quantity/mock.js +23 -15
  80. package/dist/actions/update-cart-item-quantity/types.d.ts +8 -1
  81. package/dist/actions/upsert-custom-table-data/mock.d.ts +1 -1
  82. package/dist/actions/upsert-custom-table-data/mock.js +3 -3
  83. package/dist/demo/database.js +30 -4
  84. package/dist/index.d.ts +6 -0
  85. package/dist/index.js +8 -0
  86. package/dist/projects/render/mocks.js +6 -0
  87. package/dist/projects/render/types.d.ts +4 -1
  88. package/package.json +2 -2
@@ -1,6 +1,6 @@
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";
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 = "empty" | "product" | "action" | "category" | "folder" | "back";
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 = "kaching" | "Manage";
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>, "settings"> | null;
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;
@@ -1,6 +1,6 @@
1
- export * from "./common-types";
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 "@final-commerce/common";
6
+ export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from '@final-commerce/common';
@@ -1,2 +1,2 @@
1
- import { AddCartDiscount } from "./types";
1
+ import { AddCartDiscount } from './types';
2
2
  export declare const mockAddCartDiscount: AddCartDiscount;
@@ -1,18 +1,18 @@
1
- import { MOCK_CART, mockPublishEvent } from "../../demo/database";
2
- import { percentToFraction, requireMinorUnitsInteger } from "../../demo/units";
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("[Mock] addCartDiscount called", params);
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, "Discount 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 "./types";
1
+ import { AddCartFee } from './types';
2
2
  export declare const mockAddCartFee: AddCartFee;
@@ -1,7 +1,7 @@
1
- import { MOCK_CART } from "../../demo/database";
2
- import { percentToFraction, requireMinorUnitsInteger } from "../../demo/units";
1
+ import { MOCK_CART } from '../../demo/database';
2
+ import { percentToFraction, requireMinorUnitsInteger } from '../../demo/units';
3
3
  export const mockAddCartFee = async (params) => {
4
- console.log("[Mock] addCartFee called", params);
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, "Fee amount");
13
+ : requireMinorUnitsInteger(params.amount, 'Fee amount');
14
14
  MOCK_CART.customFee.push({
15
- label: params.label || "Fee",
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 "./types";
1
+ import { AddProductToCart } from './types';
2
2
  export declare const mockAddProductToCart: AddProductToCart;
@@ -1,15 +1,19 @@
1
- import { MOCK_CART, MOCK_PRODUCTS, mockPublishEvent } from "../../demo/database";
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("[Mock] addProductToCart called", params);
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 + "_" + Date.now();
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(", ") : params.notes;
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
- const lineTotal = activeProduct.price * quantity;
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
  };
@@ -1,9 +1,21 @@
1
- import type { AddProductDiscountParams } from "../add-product-discount/types";
2
- import type { AddProductFeeParams } from "../add-product-fee/types";
1
+ import type { AddProductDiscountParams } from '../add-product-discount/types';
2
+ 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
- /** Defaults to 1. */
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 "./types";
1
+ import { AdjustInventory } from './types';
2
2
  export declare const mockAdjustInventory: AdjustInventory;
@@ -1,6 +1,6 @@
1
- import { MOCK_PRODUCTS } from "../../demo/database";
1
+ import { MOCK_PRODUCTS } from '../../demo/database';
2
2
  export const mockAdjustInventory = async (params) => {
3
- console.log("[Mock] adjustInventory called", params);
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 || "0",
36
- stockType: params?.stockType || "set",
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 "./types";
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 === "cancelled") {
7
+ if (targetFulfillmentState === 'cancelled') {
8
8
  return Promise.resolve({
9
9
  result: {
10
10
  allowed: false,
11
- blockedBy: "condition",
12
- guard: "no-cancel-open-order",
13
- reason: "Cannot cancel an order with open items"
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: "unpaid", fulfillment: "draft" },
20
- to: { payment: "unpaid", fulfillment: targetFulfillmentState },
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 "../../common-types/order-state";
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 "./types";
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("[Mock] authenticateUser called", params);
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("userId and pin must be provided together");
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 "./types";
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 "../../client";
5
+ import { commandFrameClient } from '../../client';
6
6
  export const calculateRefundTotal = async (params) => {
7
- return await commandFrameClient.call("calculateRefundTotal", params);
7
+ return await commandFrameClient.call('calculateRefundTotal', params);
8
8
  };
@@ -1,4 +1,4 @@
1
- import type { CFStatePair, CFTransitionResult } from "../../common-types/order-state";
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 "./types";
1
+ import { CashPayment } from './types';
2
2
  export declare const mockCashPayment: CashPayment;
@@ -1,6 +1,6 @@
1
- import { applyMockPayment, MOCK_CART } from "../../demo/database";
1
+ import { applyMockPayment, MOCK_CART } from '../../demo/database';
2
2
  export const mockCashPayment = async (params) => {
3
- console.log("[Mock] cashPayment called", params);
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: "cash",
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("amount is required (integer minor currency units)");
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("cancelled");
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("Could not open prompt/alert (possibly in non-interactive environment)", e);
47
+ console.warn('Could not open prompt/alert (possibly in non-interactive environment)', e);
48
48
  }
49
49
  }
50
- const order = applyMockPayment(params.amount, "cash", "cash");
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: "cash",
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,4 +1,4 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  export interface CashPaymentParams {
3
3
  /**
4
4
  * The amount to pay with this tender, in integer MINOR currency units
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Charge MOTO action
3
+ * Calls the chargeMoto action on the parent window
4
+ */
5
+ import type { ChargeMoto } from './types';
6
+ export declare const chargeMoto: ChargeMoto;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Charge MOTO action
3
+ * Calls the chargeMoto action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const chargeMoto = async (params) => {
7
+ return await commandFrameClient.call('chargeMoto', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import { ChargeMoto } from './types';
2
+ export declare const mockChargeMoto: ChargeMoto;
@@ -0,0 +1,47 @@
1
+ import { applyMockPayment, MOCK_CART } from '../../demo/database';
2
+ /** Mirrors kaching's `MOTO_MIN_AMOUNT_MINOR` — the processors' floor. */
3
+ const MOTO_MIN_AMOUNT_MINOR = 50;
4
+ /** The card fields that must be present and non-empty on every keyed charge. */
5
+ const REQUIRED_CARD_FIELDS = [
6
+ 'encryptedCardNumber',
7
+ 'encryptedExpiryMonth',
8
+ 'encryptedExpiryYear',
9
+ 'encryptedSecurityCode',
10
+ ];
11
+ export const mockChargeMoto = async (params) => {
12
+ console.log('[Mock] chargeMoto called', params);
13
+ if (!params)
14
+ throw new Error('Params required');
15
+ if (!Number.isInteger(params.amount)) {
16
+ throw new Error('amount must be an integer number of minor units');
17
+ }
18
+ if (params.amount < MOTO_MIN_AMOUNT_MINOR) {
19
+ throw new Error(`amount must be at least ${MOTO_MIN_AMOUNT_MINOR} minor units`);
20
+ }
21
+ for (const field of REQUIRED_CARD_FIELDS) {
22
+ const value = params.card?.[field];
23
+ if (!value || !value.trim()) {
24
+ throw new Error(`card.${field} is required`);
25
+ }
26
+ }
27
+ if (!params.idempotencyKey || !params.idempotencyKey.trim()) {
28
+ throw new Error('idempotencyKey is required so a retry replays instead of recharging');
29
+ }
30
+ const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
31
+ if (params.amount > balanceDue) {
32
+ throw new Error(`amount ${params.amount} exceeds balance due ${balanceDue}`);
33
+ }
34
+ // The mock always completes the sale in one leg — it does not model
35
+ // kaching's real partial-leg (`saleFinalized: false`) path.
36
+ const order = applyMockPayment(balanceDue, 'card', 'adyen');
37
+ if (!order) {
38
+ throw new Error('MOCK_CHARGE_MOTO_PARTIAL_UNSUPPORTED: the mock only supports charging the full balance due');
39
+ }
40
+ return {
41
+ success: true,
42
+ timestamp: new Date().toISOString(),
43
+ order,
44
+ saleFinalized: true,
45
+ remainingBalance: 0,
46
+ };
47
+ };
@@ -0,0 +1,53 @@
1
+ import { CFOrder } from '../../CommonTypes';
2
+ /**
3
+ * Provider-encrypted card fields, opaque to this library — mirrors kaching's
4
+ * `MotoCardFields` field for field. Never a raw PAN: these are the CSE blobs
5
+ * the provider's own client-side encrypter produces.
6
+ */
7
+ export interface ChargeMotoCardFields {
8
+ encryptedCardNumber: string;
9
+ encryptedExpiryMonth: string;
10
+ encryptedExpiryYear: string;
11
+ encryptedSecurityCode: string;
12
+ /** Optional AVS postal code the operator entered. */
13
+ postalCode?: string;
14
+ /** Provider-side `reference` for this payment. Defaults to the idempotency key server-side. */
15
+ reference?: string;
16
+ }
17
+ export interface ChargeMotoParams {
18
+ /**
19
+ * Total to charge, base + tip, in integer MINOR currency units. Minimum 50
20
+ * minor units (the processors' floor). This is the leg amount: a value
21
+ * below the cart's balance due records a partial payment.
22
+ */
23
+ amount: number;
24
+ /** Tip portion of `amount`, already collected by the caller's own UI. Defaults to 0. */
25
+ tipAmount?: number;
26
+ /**
27
+ * ISO 4217 code. Optional — the active company's currency is authoritative.
28
+ * When supplied it must match, or the charge is rejected before anything is sent.
29
+ */
30
+ currency?: string;
31
+ card: ChargeMotoCardFields;
32
+ /**
33
+ * Idempotency key for this charge, HELD BY THE CALLER across retries. A
34
+ * retried charge must carry the SAME key so the charge is replayed instead
35
+ * of doubled; use a NEW key after changing the amount.
36
+ */
37
+ idempotencyKey: string;
38
+ /** Optional tender label recorded on the payment method. */
39
+ paymentName?: string;
40
+ /** Fulfillment state to land on after full payment (default: auto-fulfill). */
41
+ targetFulfillmentState?: string;
42
+ }
43
+ export interface ChargeMotoResponse {
44
+ success: boolean;
45
+ timestamp: string;
46
+ /** The persisted order the charge landed on. */
47
+ order: CFOrder;
48
+ /** True only when this charge completed the sale (`paymentState === 'paid'`). */
49
+ saleFinalized: boolean;
50
+ /** Balance still due after this charge, in integer minor units. 0 when finalized. */
51
+ remainingBalance: number;
52
+ }
53
+ export type ChargeMoto = (params: ChargeMotoParams) => Promise<ChargeMotoResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Create payment link action
3
+ * Calls the createPaymentLink action on the parent window
4
+ */
5
+ import type { CreatePaymentLink } from './types';
6
+ export declare const createPaymentLink: CreatePaymentLink;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Create payment link action
3
+ * Calls the createPaymentLink action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const createPaymentLink = async (params) => {
7
+ return await commandFrameClient.call('createPaymentLink', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import { CreatePaymentLink } from './types';
2
+ export declare const mockCreatePaymentLink: CreatePaymentLink;