@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
@@ -0,0 +1,35 @@
1
+ import { MOCK_CART, mockPublishEvent, resetMockCart } from '../../demo/database';
2
+ export const mockCreatePaymentLink = async (params) => {
3
+ console.log('[Mock] createPaymentLink called', params);
4
+ if (!params)
5
+ throw new Error('Params required');
6
+ const email = params.email?.trim() ? params.email : undefined;
7
+ const phone = params.phone?.trim() ? params.phone : undefined;
8
+ if (email && phone) {
9
+ throw new Error('exactly one of email or phone delivers a payment link, not both');
10
+ }
11
+ if (!email && !phone) {
12
+ throw new Error('exactly one of email or phone is required to deliver the payment link');
13
+ }
14
+ const hasCart = MOCK_CART.products.length > 0 ||
15
+ (MOCK_CART.customSales?.length ?? 0) > 0 ||
16
+ (MOCK_CART.nonRevenueItems?.length ?? 0) > 0;
17
+ if (!hasCart || MOCK_CART.total <= 0) {
18
+ throw new Error('ring the sale up before creating a payment link: the cart is empty');
19
+ }
20
+ const mockOrderId = 'order_' + Date.now();
21
+ const mockLinkId = 'link_' + Math.random().toString(36).substr(2, 9);
22
+ // Marks the cart consumed, same as a successful send in kaching — the order
23
+ // now owns the line.
24
+ resetMockCart();
25
+ mockPublishEvent('cart', 'cart-created', {});
26
+ return {
27
+ success: true,
28
+ timestamp: new Date().toISOString(),
29
+ orderId: mockOrderId,
30
+ url: `https://mock.finalpos.dev/pay/${mockLinkId}`,
31
+ id: mockLinkId,
32
+ expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
33
+ delivery: email ? { email: 'sent' } : { sms: 'sent' },
34
+ };
35
+ };
@@ -0,0 +1,27 @@
1
+ export interface CreatePaymentLinkParams {
2
+ /** Address to email the link to. Exactly one of `email`/`phone` is required. */
3
+ email?: string;
4
+ /** Phone number to text the link to, E.164 (e.g. "+15555550123"). Exactly one of `email`/`phone` is required. */
5
+ phone?: string;
6
+ }
7
+ export interface CreatePaymentLinkResponse {
8
+ success: boolean;
9
+ timestamp: string;
10
+ /** Client `_id` of the order the station created for this link (charges the CURRENT CART). */
11
+ orderId: string;
12
+ /** Hosted payment page to send the shopper. */
13
+ url: string;
14
+ /** The provider's payment-link id. */
15
+ id: string;
16
+ /** When the link stops accepting payment (ISO date string). */
17
+ expiresAt: string;
18
+ /**
19
+ * Per-channel delivery outcome. OPTIONAL: an older hub omits it entirely,
20
+ * which reads as "delivered" — treat absence as success, not as a failure.
21
+ */
22
+ delivery?: {
23
+ email?: 'sent' | 'failed';
24
+ sms?: 'sent' | 'failed';
25
+ };
26
+ }
27
+ export type CreatePaymentLink = (params: CreatePaymentLinkParams) => Promise<CreatePaymentLinkResponse>;
@@ -0,0 +1,12 @@
1
+ // Create Payment Link Types
2
+ //
3
+ // Creates a hosted payment link FOR THE CURRENT CART (station-v2 D-decisions,
4
+ // payment-link addendum). Mirrors kaching's `createPaymentLinkFromCart` input
5
+ // (`CreatePaymentLinkFromCartInput`) and result (`PaymentLinkFromCartResult`,
6
+ // which extends the provider's `PaymentLinkResponse` with the local `orderId`).
7
+ //
8
+ // The station creates the order (client `_id`, `unpaid × in_progress`) BEFORE
9
+ // the link is requested — only that id travels on the wire. On success the
10
+ // cart is cleared; on a failed send the order is voided and the cart is kept
11
+ // so the cashier can retry. Adyen-only today.
12
+ export {};
@@ -1,2 +1,2 @@
1
- import { ExtensionPayment } from "./types";
1
+ import { ExtensionPayment } from './types';
2
2
  export declare const mockExtensionPayment: ExtensionPayment;
@@ -1,6 +1,6 @@
1
- import { MOCK_ORDERS } from "../../demo/database";
1
+ import { MOCK_ORDERS } from '../../demo/database';
2
2
  export const mockExtensionPayment = async (params) => {
3
- const paymentType = params?.paymentType ?? "redeem";
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
  };
@@ -1,4 +1,4 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  /** Params for extension-initiated payments; host routes by `paymentType`. */
3
3
  export interface ExtensionPaymentParams {
4
4
  paymentType: string;
@@ -1,2 +1,2 @@
1
- import { GetFinalContext } from "./types";
1
+ import { GetFinalContext } from './types';
2
2
  export declare const mockGetFinalContext: GetFinalContext;
@@ -1,6 +1,6 @@
1
1
  export const mockGetFinalContext = async () => {
2
- console.log("[Mock] getFinalContext called");
2
+ console.log('[Mock] getFinalContext called');
3
3
  return {
4
- projectName: "kaching"
4
+ projectName: 'kaching',
5
5
  };
6
6
  };
@@ -1,2 +1,2 @@
1
- import { GetProducts } from "./types";
1
+ import { GetProducts } from './types';
2
2
  export declare const mockGetProducts: GetProducts;
@@ -1,36 +1,53 @@
1
- import { MOCK_PRODUCTS, safeSerialize } from "../../demo/database";
1
+ import { MOCK_PRODUCTS, safeSerialize } from '../../demo/database';
2
+ import { resolveUnit } from '@final-commerce/common';
2
3
  export const mockGetProducts = async (params) => {
3
- console.log("[Mock] getProducts called", params);
4
+ console.log('[Mock] getProducts called', params);
4
5
  // Simple filter simulation
5
6
  let products = MOCK_PRODUCTS;
6
7
  const query = params?.query || {};
7
8
  if (query.searchValue) {
8
9
  const search = String(query.searchValue).toLowerCase();
9
- products = products.filter(p => p.name.toLowerCase().includes(search) ||
10
- p.sku?.toLowerCase().includes(search));
10
+ products = products.filter((p) => p.name.toLowerCase().includes(search) || p.sku?.toLowerCase().includes(search));
11
11
  }
12
12
  if (query.categories) {
13
13
  // Handle categories filter: { $in: [...] } or direct string
14
14
  const catFilter = query.categories;
15
15
  if (typeof catFilter === 'string') {
16
- products = products.filter(p => (p.categories || []).some(c => c.name === catFilter));
16
+ products = products.filter((p) => (p.categories || []).some((c) => c.name === catFilter));
17
17
  }
18
18
  else if (typeof catFilter === 'object' && '$in' in catFilter) {
19
19
  const inList = catFilter.$in;
20
- products = products.filter(p => (p.categories || []).some(c => inList.includes(c.name)));
20
+ products = products.filter((p) => (p.categories || []).some((c) => inList.includes(c.name)));
21
21
  }
22
22
  else if (typeof catFilter === 'object' && '$contains' in catFilter) {
23
23
  const containsVal = catFilter.$contains;
24
- products = products.filter(p => (p.categories || []).some(c => c.name.includes(containsVal)));
24
+ products = products.filter((p) => (p.categories || []).some((c) => c.name.includes(containsVal)));
25
25
  }
26
26
  }
27
27
  const total = products.length;
28
28
  const offset = params?.offset ?? 0;
29
29
  const limit = params?.limit ?? 100;
30
30
  const paged = products.slice(offset, offset + limit);
31
+ // Mirror the real host's attachUnits: storage carries only `unitId`, the wire shape
32
+ // adds the RESOLVED unit (abbreviation, ratioToBase, precision) so a card can label
33
+ // stock and a quantity input can pick its step. Unresolvable ids pass through bare
34
+ // rather than killing the page — same stance as the host's per-variant catch.
35
+ const withUnits = safeSerialize(paged).map((product) => ({
36
+ ...product,
37
+ variants: (product.variants ?? []).map((variant) => {
38
+ if (!variant.unitId)
39
+ return variant;
40
+ try {
41
+ return { ...variant, unit: resolveUnit(variant.unitId) };
42
+ }
43
+ catch {
44
+ return variant;
45
+ }
46
+ }),
47
+ }));
31
48
  return {
32
- products: safeSerialize(paged),
49
+ products: withUnits,
33
50
  total,
34
- timestamp: new Date().toISOString()
51
+ timestamp: new Date().toISOString(),
35
52
  };
36
53
  };
@@ -1,4 +1,4 @@
1
- import { CFRefundItem } from "../../CommonTypes";
1
+ import { CFRefundItem } from '../../CommonTypes';
2
2
  export interface GetRefundsParams {
3
3
  orderId?: string;
4
4
  sessionId?: string;
@@ -2,5 +2,5 @@
2
2
  * Get remaining refundable quantities action
3
3
  * Calls the getRemainingRefundableQuantities action on the parent window
4
4
  */
5
- import type { GetRemainingRefundableQuantities } from "./types";
5
+ import type { GetRemainingRefundableQuantities } from './types';
6
6
  export declare const getRemainingRefundableQuantities: GetRemainingRefundableQuantities;
@@ -2,7 +2,7 @@
2
2
  * Get remaining refundable quantities action
3
3
  * Calls the getRemainingRefundableQuantities action on the parent window
4
4
  */
5
- import { commandFrameClient } from "../../client";
5
+ import { commandFrameClient } from '../../client';
6
6
  export const getRemainingRefundableQuantities = async (params) => {
7
- return await commandFrameClient.call("getRemainingRefundableQuantities", params);
7
+ return await commandFrameClient.call('getRemainingRefundableQuantities', params);
8
8
  };
@@ -1,2 +1,2 @@
1
- import { GetRemainingRefundableQuantities } from "./types";
1
+ import { GetRemainingRefundableQuantities } from './types';
2
2
  export declare const mockGetRemainingRefundableQuantities: GetRemainingRefundableQuantities;
@@ -1,11 +1,11 @@
1
1
  export const mockGetRemainingRefundableQuantities = async (_params) => {
2
- console.log("[Mock] getRemainingRefundableQuantities called", _params);
2
+ console.log('[Mock] getRemainingRefundableQuantities called', _params);
3
3
  return {
4
4
  success: true,
5
5
  lineItems: {},
6
6
  customSales: {},
7
7
  cartFees: {},
8
8
  tips: {},
9
- timestamp: new Date().toISOString()
9
+ timestamp: new Date().toISOString(),
10
10
  };
11
11
  };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Get time clock status action
3
+ * Calls the getTimeClockStatus action on the parent window
4
+ */
5
+ import type { GetTimeClockStatus } from './types';
6
+ export declare const getTimeClockStatus: GetTimeClockStatus;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get time clock status action
3
+ * Calls the getTimeClockStatus action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const getTimeClockStatus = async (params) => {
7
+ return await commandFrameClient.call('getTimeClockStatus', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import { GetTimeClockStatus } from './types';
2
+ export declare const mockGetTimeClockStatus: GetTimeClockStatus;
@@ -0,0 +1,17 @@
1
+ /** Fixed shift start used by the mock — a clocked-in snapshot with no break taken. */
2
+ const MOCK_CLOCK_IN_TIME = new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString();
3
+ export const mockGetTimeClockStatus = async (params) => {
4
+ console.log('[Mock] getTimeClockStatus called', params);
5
+ const workedMs = Date.now() - new Date(MOCK_CLOCK_IN_TIME).getTime();
6
+ return {
7
+ success: true,
8
+ timestamp: new Date().toISOString(),
9
+ status: 'clocked-in',
10
+ entry: {
11
+ clockInTime: MOCK_CLOCK_IN_TIME,
12
+ breakStartedAt: null,
13
+ totalBreakMinutes: 0,
14
+ workedMs,
15
+ },
16
+ };
17
+ };
@@ -0,0 +1,18 @@
1
+ export interface TimeClockEntry {
2
+ /** ISO date string of when the current shift started. */
3
+ clockInTime: string;
4
+ /** ISO date string of when the current break started, or `null` when not on break. */
5
+ breakStartedAt: string | null;
6
+ /** Total break time accumulated on this shift so far, in minutes. */
7
+ totalBreakMinutes: number;
8
+ /** Milliseconds worked so far on this shift, as of when this response was generated. */
9
+ workedMs: number;
10
+ }
11
+ export interface GetTimeClockStatusResponse {
12
+ success: boolean;
13
+ timestamp: string;
14
+ status: 'out' | 'clocked-in' | 'on-break';
15
+ /** `null` when `status` is `'out'`. */
16
+ entry: TimeClockEntry | null;
17
+ }
18
+ export type GetTimeClockStatus = (params?: Record<string, never>) => Promise<GetTimeClockStatusResponse>;
@@ -0,0 +1,7 @@
1
+ // Get Time Clock Status Types
2
+ //
3
+ // READ-ONLY query: is the active employee clocked out, clocked in, or on
4
+ // break, and since when? There are no clock-in/clock-out commands — this
5
+ // action only reports the current state; `workedMs` is a snapshot at call
6
+ // time and flows are expected to tick it client-side from `clockInTime`.
7
+ export {};
@@ -1,4 +1,4 @@
1
- import type { ExtensionPaymentResponse } from "../extension-payment/types";
1
+ import type { ExtensionPaymentResponse } from '../extension-payment/types';
2
2
  /**
3
3
  * Card display fields for an integration payment.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  export interface ParkOrderResponse {
3
3
  success: boolean;
4
4
  order: CFOrder;
@@ -1,2 +1,2 @@
1
- import { PartialPayment } from "./types";
1
+ import { PartialPayment } from './types';
2
2
  export declare const mockPartialPayment: PartialPayment;
@@ -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 mockPartialPayment = async (params) => {
4
- console.log("[Mock] partialPayment called", params);
4
+ console.log('[Mock] partialPayment called', params);
5
5
  const openUI = params?.openUI ?? true;
6
6
  if (openUI) {
7
7
  // Split-payment UI is host-owned; nothing to simulate here.
8
- window.alert("Demo: Split Payment UI would open here.");
8
+ window.alert('Demo: Split Payment UI would open here.');
9
9
  return {
10
10
  success: true,
11
11
  amount: params?.amount,
12
12
  isPercent: params?.isPercent || false,
13
13
  openUI,
14
14
  order: null,
15
- timestamp: new Date().toISOString()
15
+ timestamp: new Date().toISOString(),
16
16
  };
17
17
  }
18
18
  // Queue a partial amount as the next tender. The remaining balance is left
@@ -23,15 +23,15 @@ export const mockPartialPayment = async (params) => {
23
23
  // directly; a percent is raw 0-100 against the remaining total.
24
24
  const charge = params?.isPercent
25
25
  ? Math.round(remaining * percentToFraction(raw))
26
- : requireMinorUnitsInteger(raw, "Payment amount");
26
+ : requireMinorUnitsInteger(raw, 'Payment amount');
27
27
  MOCK_CART.amountToBeCharged = Math.min(Math.max(0, charge), remaining);
28
- mockPublishEvent("cart", "partial-payment-set", { amountToBeCharged: MOCK_CART.amountToBeCharged });
28
+ mockPublishEvent('cart', 'partial-payment-set', { amountToBeCharged: MOCK_CART.amountToBeCharged });
29
29
  return {
30
30
  success: true,
31
31
  amount: params?.amount,
32
32
  isPercent: params?.isPercent || false,
33
33
  openUI,
34
34
  order: null,
35
- timestamp: new Date().toISOString()
35
+ timestamp: new Date().toISOString(),
36
36
  };
37
37
  };
@@ -1,4 +1,4 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  export interface PartialPaymentParams {
3
3
  /** The payment amount in integer MINOR currency units (required if openUI is false). If isPercent is true, this is a percentage (0-100) instead. */
4
4
  amount?: number;
@@ -1,2 +1,2 @@
1
- import { Print } from "./types";
1
+ import { Print } from './types';
2
2
  export declare const mockPrint: Print;
@@ -1,25 +1,25 @@
1
1
  export const mockPrint = (params) => {
2
- console.log("[Mock] print called", params);
2
+ console.log('[Mock] print called', params);
3
3
  if (!params) {
4
- throw new Error("Print parameters are required");
4
+ throw new Error('Print parameters are required');
5
5
  }
6
6
  // Mock implementation - just log what would be printed
7
7
  switch (params.type) {
8
- case "image":
9
- console.log("[Mock] Would print image:", params.data.image?.substring(0, 50) + "...");
8
+ case 'image':
9
+ console.log('[Mock] Would print image:', params.data.image?.substring(0, 50) + '...');
10
10
  break;
11
- case "html":
11
+ case 'html':
12
12
  console.warn("[Mock] print type 'html' is DEPRECATED — rasterize and use type: 'image'.");
13
- console.log("[Mock] Would print HTML:", params.data.html?.substring(0, 100) + "...");
13
+ console.log('[Mock] Would print HTML:', params.data.html?.substring(0, 100) + '...');
14
14
  break;
15
- case "receipt":
15
+ case 'receipt':
16
16
  console.warn("[Mock] print type 'receipt' is DEPRECATED — rasterize and use type: 'image'.");
17
- console.log("[Mock] Would print receipt for order:", params.data.order);
17
+ console.log('[Mock] Would print receipt for order:', params.data.order);
18
18
  break;
19
19
  }
20
20
  return Promise.resolve({
21
21
  success: true,
22
22
  timestamp: new Date().toISOString(),
23
- type: params.type
23
+ type: params.type,
24
24
  });
25
25
  };
@@ -1,14 +1,14 @@
1
- import type { CFActiveOrder } from "../../CommonTypes";
2
- export type PrintType = "image" | "html" | "receipt";
1
+ import type { CFActiveOrder } from '../../CommonTypes';
2
+ export type PrintType = 'image' | 'html' | 'receipt';
3
3
  export type PrintParams = {
4
- type: "image";
4
+ type: 'image';
5
5
  data: {
6
6
  image: string;
7
7
  };
8
8
  options?: PrintOptions;
9
9
  } | {
10
10
  /** @deprecated Rasterize your HTML and use `type: "image"`. The native path posts raw HTML to the shell (no html2canvas/sanitization) and PrintOptions may be dropped. */
11
- type: "html";
11
+ type: 'html';
12
12
  data: {
13
13
  html: string;
14
14
  };
@@ -19,9 +19,9 @@ export type PrintParams = {
19
19
  * The station requires `order` (no active-order fallback), ignores
20
20
  * `globalBlockId`, and drops ALL PrintOptions (including tag routing).
21
21
  */
22
- type: "receipt";
22
+ type: 'receipt';
23
23
  data: {
24
- order?: Omit<CFActiveOrder, "_id">;
24
+ order?: Omit<CFActiveOrder, '_id'>;
25
25
  globalBlockId?: string;
26
26
  };
27
27
  options?: PrintOptions;
@@ -1,4 +1,4 @@
1
- import type { ExtensionPaymentResponse } from "../extension-payment/types";
1
+ import type { ExtensionPaymentResponse } from '../extension-payment/types';
2
2
  /**
3
3
  * Redeem (e.g. gift card) — always uses paymentType `"redeem"` on the wire.
4
4
  * `amount` is required so the persisted payment never silently falls back to the cart
@@ -1,2 +1,2 @@
1
- import type { RemoveCartFee } from "./types";
1
+ import type { RemoveCartFee } from './types';
2
2
  export declare const mockRemoveCartFee: RemoveCartFee;
@@ -1,4 +1,4 @@
1
- import { MOCK_CART, mockPublishEvent } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from '../../demo/database';
2
2
  function feeContributionToTotal(fee, subtotal) {
3
3
  // A percent fee is STORED as a fraction (10% -> 0.1), so it scales the
4
4
  // subtotal directly. Dividing by 100 again credited back a hundredth of the
@@ -9,14 +9,14 @@ function feeContributionToTotal(fee, subtotal) {
9
9
  return fee.amount;
10
10
  }
11
11
  export const mockRemoveCartFee = (params) => {
12
- console.log("[Mock] removeCartFee called", params);
12
+ console.log('[Mock] removeCartFee called', params);
13
13
  const { index } = params;
14
- if (typeof index !== "number" || !Number.isInteger(index) || index < 0) {
15
- throw new Error("removeCartFee requires a non-negative integer index");
14
+ if (typeof index !== 'number' || !Number.isInteger(index) || index < 0) {
15
+ throw new Error('removeCartFee requires a non-negative integer index');
16
16
  }
17
17
  const fees = MOCK_CART.customFee;
18
18
  if (!fees?.length) {
19
- throw new Error("Cart has no fees to remove");
19
+ throw new Error('Cart has no fees to remove');
20
20
  }
21
21
  if (index >= fees.length) {
22
22
  throw new Error(`Cart fee index ${index} is out of range (0–${fees.length - 1})`);
@@ -30,9 +30,9 @@ export const mockRemoveCartFee = (params) => {
30
30
  MOCK_CART.total -= delta;
31
31
  MOCK_CART.amountToBeCharged = MOCK_CART.total;
32
32
  MOCK_CART.remainingBalance = MOCK_CART.total;
33
- mockPublishEvent("cart", "cart-fee-removed", { feeIndex: index });
33
+ mockPublishEvent('cart', 'cart-fee-removed', { feeIndex: index });
34
34
  return Promise.resolve({
35
35
  success: true,
36
- timestamp: new Date().toISOString()
36
+ timestamp: new Date().toISOString(),
37
37
  });
38
38
  };
@@ -1,2 +1,2 @@
1
- import { RemoveProductFromCart } from "./types";
1
+ import { RemoveProductFromCart } from './types';
2
2
  export declare const mockRemoveProductFromCart: RemoveProductFromCart;
@@ -1,12 +1,13 @@
1
- import { MOCK_CART, mockPublishEvent } from "../../demo/database";
1
+ import { MOCK_CART, mockPublishEvent } from '../../demo/database';
2
+ import { extendPrice } from '@final-commerce/common';
2
3
  export const mockRemoveProductFromCart = (params) => {
3
- console.log("[Mock] removeProductFromCart called", params);
4
+ console.log('[Mock] removeProductFromCart called', params);
4
5
  if (!params?.internalId) {
5
- throw new Error("internalId is required");
6
+ throw new Error('internalId is required');
6
7
  }
7
8
  const { internalId } = params;
8
9
  // Find the product in the cart
9
- const productIndex = MOCK_CART.products.findIndex(p => p.internalId === internalId);
10
+ const productIndex = MOCK_CART.products.findIndex((p) => p.internalId === internalId);
10
11
  if (productIndex === -1) {
11
12
  throw new Error(`Cart item with internalId ${internalId} not found`);
12
13
  }
@@ -14,19 +15,21 @@ export const mockRemoveProductFromCart = (params) => {
14
15
  // Remove from cart
15
16
  MOCK_CART.products.splice(productIndex, 1);
16
17
  // Recalculate totals
17
- const lineTotal = product.price * product.quantity;
18
+ // The same rounded extension the add path put on: subtracting a raw multiply from a
19
+ // weighed line would leave the cent extendPrice rounded away stuck in the cart total.
20
+ const lineTotal = extendPrice(product.price, product.quantity);
18
21
  MOCK_CART.subtotal -= lineTotal;
19
22
  MOCK_CART.total -= lineTotal;
20
23
  MOCK_CART.amountToBeCharged = MOCK_CART.total;
21
24
  MOCK_CART.remainingBalance = MOCK_CART.total;
22
25
  // Publish product-deleted event
23
- mockPublishEvent("cart", "product-deleted", {
26
+ mockPublishEvent('cart', 'product-deleted', {
24
27
  product: product,
25
- internalId: internalId
28
+ internalId: internalId,
26
29
  });
27
30
  return Promise.resolve({
28
31
  success: true,
29
32
  internalId: internalId,
30
- timestamp: new Date().toISOString()
33
+ timestamp: new Date().toISOString(),
31
34
  });
32
35
  };
@@ -1,4 +1,4 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  export interface ResumeParkedOrderParams {
3
3
  orderId: string;
4
4
  }
@@ -2,5 +2,5 @@
2
2
  * Select all refund items action
3
3
  * Calls the selectAllRefundItems action on the parent window
4
4
  */
5
- import type { SelectAllRefundItems } from "./types";
5
+ import type { SelectAllRefundItems } from './types';
6
6
  export declare const selectAllRefundItems: SelectAllRefundItems;
@@ -2,7 +2,7 @@
2
2
  * Select all refund items action
3
3
  * Calls the selectAllRefundItems action on the parent window
4
4
  */
5
- import { commandFrameClient } from "../../client";
5
+ import { commandFrameClient } from '../../client';
6
6
  export const selectAllRefundItems = async (params) => {
7
- return await commandFrameClient.call("selectAllRefundItems", params);
7
+ return await commandFrameClient.call('selectAllRefundItems', params);
8
8
  };
@@ -1,2 +1,2 @@
1
- import type { SetActiveProduct } from "./types";
1
+ import type { SetActiveProduct } from './types';
2
2
  export declare const mockSetActiveProduct: SetActiveProduct;