@final-commerce/command-frame 0.12.0-staging.1 → 0.12.0-staging.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 (80) hide show
  1. package/dist/CommonTypes.d.ts +4 -1
  2. package/dist/actions/assign-order-user/action.d.ts +6 -0
  3. package/dist/actions/assign-order-user/action.js +8 -0
  4. package/dist/actions/assign-order-user/mock.d.ts +2 -0
  5. package/dist/actions/assign-order-user/mock.js +30 -0
  6. package/dist/actions/assign-order-user/types.d.ts +15 -0
  7. package/dist/actions/assign-order-user/types.js +1 -0
  8. package/dist/actions/get-current-cart/mock.js +3 -0
  9. package/dist/actions/get-current-cart/types.d.ts +6 -0
  10. package/dist/actions/get-moto-config/action.d.ts +6 -0
  11. package/dist/actions/get-moto-config/action.js +8 -0
  12. package/dist/actions/get-moto-config/mock.d.ts +7 -0
  13. package/dist/actions/get-moto-config/mock.js +9 -0
  14. package/dist/actions/get-moto-config/types.d.ts +34 -0
  15. package/dist/actions/get-moto-config/types.js +5 -0
  16. package/dist/actions/get-order-statuses/action.d.ts +6 -0
  17. package/dist/actions/get-order-statuses/action.js +8 -0
  18. package/dist/actions/get-order-statuses/mock.d.ts +2 -0
  19. package/dist/actions/get-order-statuses/mock.js +5 -0
  20. package/dist/actions/get-order-statuses/types.d.ts +8 -0
  21. package/dist/actions/get-order-statuses/types.js +1 -0
  22. package/dist/actions/get-orders/action.d.ts +1 -1
  23. package/dist/actions/get-orders/action.js +2 -2
  24. package/dist/actions/get-orders/mock.d.ts +1 -1
  25. package/dist/actions/get-orders/mock.js +74 -19
  26. package/dist/actions/get-orders/types.d.ts +33 -2
  27. package/dist/actions/record-external-payment/action.d.ts +6 -0
  28. package/dist/actions/record-external-payment/action.js +8 -0
  29. package/dist/actions/record-external-payment/mock.d.ts +2 -0
  30. package/dist/actions/record-external-payment/mock.js +36 -0
  31. package/dist/actions/record-external-payment/types.d.ts +37 -0
  32. package/dist/actions/record-external-payment/types.js +1 -0
  33. package/dist/actions/release-from-cart/action.d.ts +6 -0
  34. package/dist/actions/release-from-cart/action.js +8 -0
  35. package/dist/actions/release-from-cart/mock.d.ts +2 -0
  36. package/dist/actions/release-from-cart/mock.js +26 -0
  37. package/dist/actions/release-from-cart/types.d.ts +8 -0
  38. package/dist/actions/release-from-cart/types.js +1 -0
  39. package/dist/actions/resume-order/action.d.ts +6 -0
  40. package/dist/actions/resume-order/action.js +8 -0
  41. package/dist/actions/resume-order/mock.d.ts +2 -0
  42. package/dist/actions/resume-order/mock.js +55 -0
  43. package/dist/actions/resume-order/types.d.ts +17 -0
  44. package/dist/actions/resume-order/types.js +1 -0
  45. package/dist/actions/resume-parked-order/mock.d.ts +5 -0
  46. package/dist/actions/resume-parked-order/mock.js +25 -24
  47. package/dist/actions/set-order-metadata/action.d.ts +6 -0
  48. package/dist/actions/set-order-metadata/action.js +8 -0
  49. package/dist/actions/set-order-metadata/mock.d.ts +5 -0
  50. package/dist/actions/set-order-metadata/mock.js +38 -0
  51. package/dist/actions/set-order-metadata/types.d.ts +20 -0
  52. package/dist/actions/set-order-metadata/types.js +1 -0
  53. package/dist/actions/set-order-status/action.d.ts +6 -0
  54. package/dist/actions/set-order-status/action.js +8 -0
  55. package/dist/actions/set-order-status/mock.d.ts +3 -0
  56. package/dist/actions/set-order-status/mock.js +44 -0
  57. package/dist/actions/set-order-status/types.d.ts +25 -0
  58. package/dist/actions/set-order-status/types.js +1 -0
  59. package/dist/actions/set-order-type/action.d.ts +6 -0
  60. package/dist/actions/set-order-type/action.js +8 -0
  61. package/dist/actions/set-order-type/mock.d.ts +3 -0
  62. package/dist/actions/set-order-type/mock.js +27 -0
  63. package/dist/actions/set-order-type/types.d.ts +17 -0
  64. package/dist/actions/set-order-type/types.js +1 -0
  65. package/dist/actions/set-scheduled-for/action.d.ts +6 -0
  66. package/dist/actions/set-scheduled-for/action.js +8 -0
  67. package/dist/actions/set-scheduled-for/mock.d.ts +4 -0
  68. package/dist/actions/set-scheduled-for/mock.js +45 -0
  69. package/dist/actions/set-scheduled-for/types.d.ts +22 -0
  70. package/dist/actions/set-scheduled-for/types.js +1 -0
  71. package/dist/actions/void-order/mock.js +17 -7
  72. package/dist/actions/void-order/types.d.ts +6 -2
  73. package/dist/common-types/order-state.d.ts +20 -1
  74. package/dist/demo/database.d.ts +4 -0
  75. package/dist/demo/database.js +29 -0
  76. package/dist/index.d.ts +20 -0
  77. package/dist/index.js +20 -0
  78. package/dist/projects/render/mocks.js +20 -0
  79. package/dist/projects/render/types.d.ts +11 -1
  80. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
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, ResolvedModifier, ResolvedModifierChoice, ModifierSelectionType, ModifierSelection, ModifierChoiceSelection, CartLineModifier, ProdModifierBreakdown, OrderLineItemModifier, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment, BookingAvailability, BookingSlot, BookingSlotResource, BookingResource, Booking, CartReservation, OrderReservation, Composite, CompositePart, CompositeItem, CompositeChoice, CompositeItemUnavailable, CompositePick, CartLineComponent, OrderLineItemComponent } from '@final-commerce/common/pos-types';
2
+ import type { Tax, Tip, Address, MetadataItem, OrderAssignedUser, OrderInCart, OrderCustomStatus, 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, ResolvedModifier, ResolvedModifierChoice, ModifierSelectionType, ModifierSelection, ModifierChoiceSelection, CartLineModifier, ProdModifierBreakdown, OrderLineItemModifier, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment, BookingAvailability, BookingSlot, BookingSlotResource, BookingResource, Booking, CartReservation, OrderReservation, Composite, CompositePart, CompositeItem, CompositeChoice, CompositeItemUnavailable, CompositePick, CartLineComponent, OrderLineItemComponent } from '@final-commerce/common/pos-types';
3
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>;
@@ -7,6 +7,9 @@ export type CFDiscount = Discount;
7
7
  export type CFCustomFee = CustomFee;
8
8
  export type CFAddress = Address;
9
9
  export type CFMetadataItem = MetadataItem;
10
+ export type CFOrderAssignedUser = OrderAssignedUser;
11
+ export type CFOrderInCart = OrderInCart;
12
+ export type CFOrderCustomStatus = OrderCustomStatus;
10
13
  export type CFTax = Tax;
11
14
  export type CFCartFeeTaxEntry = CartFeeTaxEntry;
12
15
  export type CFInventory = Inventory;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Assign order user action
3
+ * Calls the assignOrderUser action on the parent window
4
+ */
5
+ import type { AssignOrderUser } from './types';
6
+ export declare const assignOrderUser: AssignOrderUser;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Assign order user action
3
+ * Calls the assignOrderUser action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const assignOrderUser = async (params) => {
7
+ return await commandFrameClient.call('assignOrderUser', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { AssignOrderUser } from './types';
2
+ export declare const mockAssignOrderUser: AssignOrderUser;
@@ -0,0 +1,30 @@
1
+ import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, mockPublishEvent } from '../../demo/database';
2
+ export const mockAssignOrderUser = async (params) => {
3
+ console.log('[Mock] assignOrderUser called', params);
4
+ if (!params?.orderId) {
5
+ throw new Error('assignOrderUser: the demo has no live-cart order — pass an orderId');
6
+ }
7
+ if (params.userId !== null && typeof params.userId !== 'string') {
8
+ throw new Error('assignOrderUser: userId must be a user id or null');
9
+ }
10
+ const order = [...MOCK_ORDERS, ...MOCK_PARKED_ORDERS].find((o) => o._id === params.orderId);
11
+ if (!order) {
12
+ throw new Error(`Order with ID ${params.orderId} not found`);
13
+ }
14
+ if (params.userId === null) {
15
+ order.assignedUser = null;
16
+ }
17
+ else if (order.assignedUser?.userId !== params.userId) {
18
+ if (!MOCK_USERS.some((u) => u.id === params.userId)) {
19
+ throw new Error(`User with ID ${params.userId} not found`);
20
+ }
21
+ order.assignedUser = { userId: params.userId, assignedAt: new Date().toISOString() };
22
+ }
23
+ mockPublishEvent('orders', 'order-updated', { order });
24
+ return {
25
+ success: true,
26
+ orderId: order._id,
27
+ assignedUser: order.assignedUser ?? null,
28
+ timestamp: new Date().toISOString(),
29
+ };
30
+ };
@@ -0,0 +1,15 @@
1
+ import type { CFOrderAssignedUser } from '../../CommonTypes';
2
+ export interface AssignOrderUserParams {
3
+ /** Order to assign. Omit to target the live cart's order — it must already exist (parked, paid or transitioned). */
4
+ orderId?: string;
5
+ /** User to assign (e.g. the driver), or null to unassign. Replaces any current assignee. */
6
+ userId: string | null;
7
+ }
8
+ export interface AssignOrderUserResponse {
9
+ success: boolean;
10
+ orderId: string;
11
+ /** The order's assignee after the call; null when unassigned. */
12
+ assignedUser: CFOrderAssignedUser | null;
13
+ timestamp: string;
14
+ }
15
+ export type AssignOrderUser = (params: AssignOrderUserParams) => Promise<AssignOrderUserResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -13,6 +13,9 @@ export const mockGetCurrentCart = async () => {
13
13
  return {
14
14
  success: true,
15
15
  cart: safeSerialize(MOCK_CART),
16
+ // Every mock tender settles the whole sale and clears the cart, so the demo cart
17
+ // never holds an order with money on it — nothing to lock.
18
+ itemsLocked: false,
16
19
  lineTotals,
17
20
  timestamp: new Date().toISOString(),
18
21
  };
@@ -2,6 +2,12 @@ import { CFActiveCart } from '../../CommonTypes';
2
2
  export interface GetCurrentCartResponse {
3
3
  success: boolean;
4
4
  cart: CFActiveCart;
5
+ /**
6
+ * `true` while the order in this cart has any payment on it (a split leg, a part payment,
7
+ * or paid in full): its items, amounts and customer can no longer be changed — the
8
+ * value-changing cart commands and clearCart refuse. Absent on hosts that predate the lock.
9
+ */
10
+ itemsLocked?: boolean;
5
11
  /**
6
12
  * What each line adds to the cart, minor units, keyed by the line's `internalId` (products, bookings) or `id`
7
13
  * (custom sales): price × quantity − its own discounts + its own fees + its modifiers. Before the cart discount
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Get MOTO config action
3
+ * Calls the getMotoConfig action on the parent window
4
+ */
5
+ import type { GetMotoConfig } from './types';
6
+ export declare const getMotoConfig: GetMotoConfig;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get MOTO config action
3
+ * Calls the getMotoConfig action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const getMotoConfig = async () => {
7
+ return await commandFrameClient.call('getMotoConfig', undefined);
8
+ };
@@ -0,0 +1,7 @@
1
+ import { GetMotoConfig } from './types';
2
+ /**
3
+ * The mock has no Adyen account to mount card fields against, so it answers honestly: not
4
+ * available. A flow that hides its manual card tender on `available: false` behaves the same
5
+ * in a preview as on a host without a key.
6
+ */
7
+ export declare const mockGetMotoConfig: GetMotoConfig;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The mock has no Adyen account to mount card fields against, so it answers honestly: not
3
+ * available. A flow that hides its manual card tender on `available: false` behaves the same
4
+ * in a preview as on a host without a key.
5
+ */
6
+ export const mockGetMotoConfig = async () => {
7
+ console.log('[Mock] getMotoConfig called');
8
+ return { success: true, timestamp: new Date().toISOString(), available: false, reason: 'no-client-key' };
9
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Get MOTO config — everything a flow needs to take a keyed (card-not-present) payment itself:
3
+ * mount the processor's own card-entry fields, then send what they produce to `chargeMoto`.
4
+ */
5
+ /** Why manual card entry is not available here. */
6
+ export type MotoUnavailableReason =
7
+ /** The company does not take new sales on Adyen (keyed charges are Adyen-only today). */
8
+ 'provider-unsupported'
9
+ /** The host injected no Adyen client key (an older host, or an environment without one). */
10
+ | 'no-client-key'
11
+ /** The company's Adyen integration has no country yet. */
12
+ | 'no-country'
13
+ /** No active company. */
14
+ | 'no-company';
15
+ export type GetMotoConfigResponse = {
16
+ success: boolean;
17
+ timestamp: string;
18
+ } & ({
19
+ available: true;
20
+ provider: 'adyen';
21
+ /**
22
+ * Adyen's PUBLISHABLE client key for `@adyen/adyen-web`'s `AdyenCheckout({ clientKey })`.
23
+ * Injected by the host at runtime — never bake one into a flow build.
24
+ */
25
+ clientKey: string;
26
+ /** `AdyenCheckout({ environment })`. */
27
+ environment: 'test' | 'live';
28
+ /** The company's country, ISO 3166-1 alpha-2 — `AdyenCheckout({ countryCode })`. */
29
+ countryCode: string;
30
+ } | {
31
+ available: false;
32
+ reason: MotoUnavailableReason;
33
+ });
34
+ export type GetMotoConfig = () => Promise<GetMotoConfigResponse>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Get MOTO config — everything a flow needs to take a keyed (card-not-present) payment itself:
3
+ * mount the processor's own card-entry fields, then send what they produce to `chargeMoto`.
4
+ */
5
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Get order statuses action
3
+ * Calls the getOrderStatuses action on the parent window
4
+ */
5
+ import type { GetOrderStatuses } from './types';
6
+ export declare const getOrderStatuses: GetOrderStatuses;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Get order statuses action
3
+ * Calls the getOrderStatuses action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const getOrderStatuses = async () => {
7
+ return await commandFrameClient.call('getOrderStatuses', undefined);
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { GetOrderStatuses } from './types';
2
+ export declare const mockGetOrderStatuses: GetOrderStatuses;
@@ -0,0 +1,5 @@
1
+ import { MOCK_ORDER_STATUSES } from '../../demo/database';
2
+ export const mockGetOrderStatuses = async () => {
3
+ console.log('[Mock] getOrderStatuses called');
4
+ return { success: true, statuses: MOCK_ORDER_STATUSES.map((s) => ({ ...s })), timestamp: new Date().toISOString() };
5
+ };
@@ -0,0 +1,8 @@
1
+ import type { CFOrderStatusDefinition } from '../../common-types/order-state';
2
+ export interface GetOrderStatusesResponse {
3
+ success: boolean;
4
+ /** The running flow's order statuses, in the order they were defined. Empty when it defines none. */
5
+ statuses: CFOrderStatusDefinition[];
6
+ timestamp: string;
7
+ }
8
+ export type GetOrderStatuses = () => Promise<GetOrderStatusesResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,5 +2,5 @@
2
2
  * Get orders action
3
3
  * Calls the getOrders action on the parent window
4
4
  */
5
- import type { GetOrders } from "./types";
5
+ import type { GetOrders } from './types';
6
6
  export declare const getOrders: GetOrders;
@@ -2,7 +2,7 @@
2
2
  * Get orders action
3
3
  * Calls the getOrders action on the parent window
4
4
  */
5
- import { commandFrameClient } from "../../client";
5
+ import { commandFrameClient } from '../../client';
6
6
  export const getOrders = async (params) => {
7
- return await commandFrameClient.call("getOrders", params);
7
+ return await commandFrameClient.call('getOrders', params);
8
8
  };
@@ -1,2 +1,2 @@
1
- import { GetOrders } from "./types";
1
+ import { GetOrders } from './types';
2
2
  export declare const mockGetOrders: GetOrders;
@@ -1,26 +1,80 @@
1
- import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize } from "../../demo/database";
1
+ import { MOCK_ORDERS, MOCK_PARKED_ORDERS, MOCK_USERS, MOCK_STATIONS, MOCK_OUTLETS, safeSerialize, } from '../../demo/database';
2
2
  export const mockGetOrders = async (params) => {
3
- console.log("[Mock] getOrders called", params);
3
+ console.log('[Mock] getOrders called', params);
4
4
  // Start with a safe copy of mock orders, including parked (status: "parked").
5
5
  let orders = safeSerialize([...MOCK_ORDERS, ...MOCK_PARKED_ORDERS]);
6
6
  // Filter simulation
7
7
  if (params) {
8
- const { customerId, status, sessionId, searchValue, limit, offset, sortBy, sortDirection } = params;
8
+ const { customerId, status, sessionId, paymentState, fulfillmentState, outletId, assignedUserId, inCart, orderType, customStatusId, customStatusKey, scheduled, scheduledFrom, scheduledTo, searchValue, limit, offset, sortBy, sortDirection, } = params;
9
9
  // 1. Filtering
10
10
  if (customerId) {
11
- orders = orders.filter(o => o.customer &&
12
- '_id' in o.customer &&
13
- o.customer._id === customerId);
11
+ orders = orders.filter((o) => o.customer && '_id' in o.customer && o.customer._id === customerId);
14
12
  }
15
13
  if (status) {
16
- orders = orders.filter(o => o.status === status);
14
+ orders = orders.filter((o) => o.status === status);
17
15
  }
18
16
  if (sessionId) {
19
- orders = orders.filter(o => o.sessionId === sessionId);
17
+ orders = orders.filter((o) => o.sessionId === sessionId);
18
+ }
19
+ const anyOf = (criteria, value) => criteria === undefined ||
20
+ (Array.isArray(criteria) ? criteria.length === 0 || criteria.includes(value ?? '') : criteria === value);
21
+ if (paymentState !== undefined) {
22
+ orders = orders.filter((o) => anyOf(paymentState, o.paymentState));
23
+ }
24
+ if (fulfillmentState !== undefined) {
25
+ orders = orders.filter((o) => anyOf(fulfillmentState, o.fulfillmentState));
26
+ }
27
+ if (outletId) {
28
+ orders = orders.filter((o) => o.posData?.outlet === outletId);
29
+ }
30
+ if (assignedUserId) {
31
+ orders = orders.filter((o) => o.assignedUser?.userId === assignedUserId);
32
+ }
33
+ else if (assignedUserId === null) {
34
+ orders = orders.filter((o) => o.assignedUser == null);
35
+ }
36
+ if (orderType !== undefined) {
37
+ const types = Array.isArray(orderType) ? orderType : [orderType];
38
+ if (types.length)
39
+ orders = orders.filter((o) => types.includes(o.orderType ?? ''));
40
+ }
41
+ if (customStatusKey !== undefined) {
42
+ const keys = Array.isArray(customStatusKey) ? customStatusKey : [customStatusKey];
43
+ if (keys.length)
44
+ orders = orders.filter((o) => !!o.customStatus?.key && keys.includes(o.customStatus.key));
45
+ }
46
+ if (customStatusId !== undefined) {
47
+ const ids = Array.isArray(customStatusId) ? customStatusId : [customStatusId];
48
+ if (ids.length) {
49
+ orders = orders.filter((o) => !!o.customStatus &&
50
+ (ids.includes(o.customStatus.id) || (!!o.customStatus.key && ids.includes(o.customStatus.key))));
51
+ }
52
+ }
53
+ // Requested time (setScheduledFor). ISO strings in UTC compare correctly as strings.
54
+ const scheduledOf = (o) => o.scheduledFor ?? null;
55
+ if (typeof scheduled === 'boolean') {
56
+ orders = orders.filter((o) => (scheduledOf(o) !== null) === scheduled);
57
+ }
58
+ if (scheduledFrom) {
59
+ const from = new Date(scheduledFrom).toISOString();
60
+ orders = orders.filter((o) => (scheduledOf(o) ?? '') !== '' && scheduledOf(o) >= from);
61
+ }
62
+ if (scheduledTo) {
63
+ const to = new Date(scheduledTo).toISOString();
64
+ orders = orders.filter((o) => (scheduledOf(o) ?? '') !== '' && scheduledOf(o) <= to);
65
+ }
66
+ if (typeof inCart === 'boolean') {
67
+ // Mirrors common's isInCart: the flag when present, else the legacy reading.
68
+ const orderInCart = (o) => o.inCart != null
69
+ ? o.inCart.active
70
+ : o.fulfillmentState
71
+ ? o.fulfillmentState === 'draft'
72
+ : o.status === 'in-cart';
73
+ orders = orders.filter((o) => orderInCart(o) === inCart);
20
74
  }
21
75
  if (searchValue) {
22
76
  const searchLower = String(searchValue).toLowerCase();
23
- orders = orders.filter(o => {
77
+ orders = orders.filter((o) => {
24
78
  const receiptMatch = o.receiptId?.toLowerCase().includes(searchLower);
25
79
  const customerNameMatch = o.customer && 'firstName' in o.customer
26
80
  ? `${o.customer.firstName} ${o.customer.lastName}`.toLowerCase().includes(searchLower)
@@ -36,20 +90,21 @@ export const mockGetOrders = async (params) => {
36
90
  orders.sort((a, b) => {
37
91
  let valA = a[sortBy];
38
92
  let valB = b[sortBy];
93
+ // Like the host: a missing time sorts as '' (first when ascending).
94
+ if (sortBy === 'scheduledFor') {
95
+ valA = valA ?? '';
96
+ valB = valB ?? '';
97
+ }
39
98
  // Handle nested sort fields if necessary, basic support for now
40
99
  if (!valA && sortBy === 'createdAt')
41
100
  valA = a.createdAt || '';
42
101
  if (!valB && sortBy === 'createdAt')
43
102
  valB = b.createdAt || '';
44
103
  if (typeof valA === 'string' && typeof valB === 'string') {
45
- return sortDirection === 'descending'
46
- ? valB.localeCompare(valA)
47
- : valA.localeCompare(valB);
104
+ return sortDirection === 'descending' ? valB.localeCompare(valA) : valA.localeCompare(valB);
48
105
  }
49
106
  // Number comparison
50
- return sortDirection === 'descending'
51
- ? (valB || 0) - (valA || 0)
52
- : (valA || 0) - (valB || 0);
107
+ return sortDirection === 'descending' ? (valB || 0) - (valA || 0) : (valA || 0) - (valB || 0);
53
108
  });
54
109
  }
55
110
  else {
@@ -73,21 +128,21 @@ export const mockGetOrders = async (params) => {
73
128
  if (enrichedOrder.posData) {
74
129
  // Enrich Employee
75
130
  if (typeof enrichedOrder.posData.employee === 'string') {
76
- const employee = MOCK_USERS.find(u => u.id === enrichedOrder.posData.employee);
131
+ const employee = MOCK_USERS.find((u) => u.id === enrichedOrder.posData.employee);
77
132
  if (employee) {
78
133
  enrichedOrder.posData.employee = employee;
79
134
  }
80
135
  }
81
136
  // Enrich Station
82
137
  if (typeof enrichedOrder.posData.station === 'string') {
83
- const station = MOCK_STATIONS.find(s => s._id === enrichedOrder.posData.station);
138
+ const station = MOCK_STATIONS.find((s) => s._id === enrichedOrder.posData.station);
84
139
  if (station) {
85
140
  enrichedOrder.posData.station = station;
86
141
  }
87
142
  }
88
143
  // Enrich Outlet
89
144
  if (typeof enrichedOrder.posData.outlet === 'string') {
90
- const outlet = MOCK_OUTLETS.find(o => o.id === enrichedOrder.posData.outlet);
145
+ const outlet = MOCK_OUTLETS.find((o) => o.id === enrichedOrder.posData.outlet);
91
146
  if (outlet) {
92
147
  enrichedOrder.posData.outlet = outlet;
93
148
  }
@@ -99,6 +154,6 @@ export const mockGetOrders = async (params) => {
99
154
  success: true,
100
155
  orders: enrichedOrders,
101
156
  total: MOCK_ORDERS.length, // Total before pagination
102
- timestamp: new Date().toISOString()
157
+ timestamp: new Date().toISOString(),
103
158
  };
104
159
  };
@@ -1,15 +1,46 @@
1
- import { CFOrder } from "../../CommonTypes";
1
+ import { CFOrder } from '../../CommonTypes';
2
2
  export interface GetOrdersParams {
3
3
  /** e.g. 'completed', 'parked', 'refunded'. */
4
4
  status?: string;
5
5
  customerId?: string;
6
6
  sessionId?: string;
7
+ /** Payment state(s), e.g. 'paid' or ['unpaid', 'partially_paid']. A list matches any of them. */
8
+ paymentState?: string | string[];
9
+ /** Fulfillment state(s), e.g. 'in_progress' or ['pending', 'in_progress']. A list matches any of them. */
10
+ fulfillmentState?: string | string[];
11
+ /** Only orders placed at this outlet (`posData.outlet`). Without it, orders from every outlet in the company are returned. */
12
+ outletId?: string;
13
+ /**
14
+ * Only orders assigned to this user (`assignedUser.userId`), e.g. a driver's deliveries.
15
+ * `null`: only orders nobody is assigned to yet (e.g. deliveries awaiting a driver).
16
+ */
17
+ assignedUserId?: string | null;
18
+ /**
19
+ * true: only orders loaded in a cart; false: only orders that aren't. Reads `order.inCart` when the order
20
+ * carries it, otherwise the legacy reading (fulfillment 'draft' / status 'in-cart').
21
+ */
22
+ inCart?: boolean;
23
+ /** Order type label(s) set with setOrderType, e.g. 'delivery' or ['pickup', 'takeout']. Exact match; a list matches any. */
24
+ orderType?: string | string[];
25
+ /** Custom status key(s) set with setOrderStatus, e.g. 'in-kitchen'. A list matches any of them. */
26
+ customStatusKey?: string | string[];
27
+ /**
28
+ * Durable custom status id(s) (getOrderStatuses `id`). Also matches a status's key, for
29
+ * flows written before keys — prefer `customStatusKey`. A list matches any of them.
30
+ */
31
+ customStatusId?: string | string[];
32
+ /** true: only orders with a time (setScheduledFor); false: only "as soon as possible" orders (no time). */
33
+ scheduled?: boolean;
34
+ /** Only orders scheduled at or after this ISO 8601 date-time. Orders with no time never match. */
35
+ scheduledFrom?: string;
36
+ /** Only orders scheduled at or before this ISO 8601 date-time. Orders with no time never match. */
37
+ scheduledTo?: string;
7
38
  /** Default: 50. */
8
39
  limit?: number;
9
40
  /** Default: 0. */
10
41
  offset?: number;
11
42
  searchValue?: string;
12
- /** Default: 'createdAt'. */
43
+ /** Default: 'createdAt'. 'scheduledFor' sorts by the customer's requested time — orders with no time come first ascending. */
13
44
  sortBy?: string;
14
45
  /** Default: 'descending'. */
15
46
  sortDirection?: 'ascending' | 'descending';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Record external payment action
3
+ * Calls the recordExternalPayment action on the parent window
4
+ */
5
+ import type { RecordExternalPayment } from './types';
6
+ export declare const recordExternalPayment: RecordExternalPayment;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Record external payment action
3
+ * Calls the recordExternalPayment action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const recordExternalPayment = async (params) => {
7
+ return await commandFrameClient.call('recordExternalPayment', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { RecordExternalPayment } from './types';
2
+ export declare const mockRecordExternalPayment: RecordExternalPayment;
@@ -0,0 +1,36 @@
1
+ import { isFulfillmentState } from '@final-commerce/common';
2
+ import { applyMockPayment, MOCK_CART } from '../../demo/database';
3
+ export const mockRecordExternalPayment = async (params) => {
4
+ console.log('[Mock] recordExternalPayment called', params);
5
+ const label = typeof params?.label === 'string' ? params.label.trim() : '';
6
+ if (!label) {
7
+ throw new Error('recordExternalPayment: label is required');
8
+ }
9
+ const balanceDue = MOCK_CART.amountToBeCharged ?? MOCK_CART.total;
10
+ const amount = params.amount ?? balanceDue;
11
+ // Same rule as the host: positive, except on a zero-balance checkout.
12
+ if (!Number.isFinite(amount) || amount < 0 || (amount === 0 && balanceDue > 0)) {
13
+ throw new Error('recordExternalPayment: amount must be a positive integer (minor units)');
14
+ }
15
+ const target = params.checkoutFulfillmentTarget;
16
+ if (target !== undefined && !isFulfillmentState(target)) {
17
+ throw new Error(`recordExternalPayment: invalid checkoutFulfillmentTarget "${String(target)}"`);
18
+ }
19
+ if (amount > balanceDue) {
20
+ throw new Error(`recordExternalPayment: amount ${amount} exceeds the balance due ${balanceDue}`);
21
+ }
22
+ const order = applyMockPayment(amount, 'external', label);
23
+ const remainingBalance = MOCK_CART.remainingBalance ?? 0;
24
+ return {
25
+ success: true,
26
+ amount,
27
+ label,
28
+ paymentType: 'external',
29
+ change: 0,
30
+ cashRounding: 0,
31
+ order,
32
+ saleFinalized: !!order,
33
+ remainingBalance: order ? 0 : remainingBalance,
34
+ timestamp: new Date().toISOString(),
35
+ };
36
+ };
@@ -0,0 +1,37 @@
1
+ import { CFOrder } from '../../CommonTypes';
2
+ export interface RecordExternalPaymentParams {
3
+ /**
4
+ * What the payment was — shown on the order and in reports, e.g. 'Paid online',
5
+ * 'Uber Eats', 'Voucher'. Required; trimmed. Not checked against a list, so keep
6
+ * labels consistent across flows.
7
+ */
8
+ label: string;
9
+ /**
10
+ * Amount to record, in integer MINOR currency units. Omit to record the full balance
11
+ * due (completing the order). Below the balance due it records a partial payment —
12
+ * the rest can be taken with any other tender. Above the balance due is an error.
13
+ */
14
+ amount?: number;
15
+ /** Fulfillment state to land on after full payment, e.g. 'pending' to keep the order going to the kitchen. */
16
+ checkoutFulfillmentTarget?: string;
17
+ }
18
+ export interface RecordExternalPaymentResponse {
19
+ success: boolean;
20
+ /** The amount recorded, in integer MINOR currency units. */
21
+ amount: number;
22
+ /** The label, as recorded. */
23
+ label: string;
24
+ paymentType: 'external';
25
+ /** Always 0 — no money changes hands at the terminal. */
26
+ change: number;
27
+ /** Always 0 — cash rounding applies to cash only. */
28
+ cashRounding: number;
29
+ /** The order once the sale completes; null for a partial (split) leg. */
30
+ order: CFOrder | null;
31
+ /** True when this payment settled the remaining balance. */
32
+ saleFinalized: boolean;
33
+ /** Balance still due after this payment, in integer MINOR currency units. */
34
+ remainingBalance: number;
35
+ timestamp: string;
36
+ }
37
+ export type RecordExternalPayment = (params: RecordExternalPaymentParams) => Promise<RecordExternalPaymentResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Release from cart action
3
+ * Calls the releaseFromCart action on the parent window
4
+ */
5
+ import type { ReleaseFromCart } from './types';
6
+ export declare const releaseFromCart: ReleaseFromCart;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Release from cart action
3
+ * Calls the releaseFromCart action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const releaseFromCart = async () => {
7
+ return await commandFrameClient.call('releaseFromCart', undefined);
8
+ };
@@ -0,0 +1,2 @@
1
+ import type { ReleaseFromCart } from './types';
2
+ export declare const mockReleaseFromCart: ReleaseFromCart;
@@ -0,0 +1,26 @@
1
+ import { MOCK_CART, MOCK_ORDERS, resetMockCart, mockPublishEvent } from '../../demo/database';
2
+ export const mockReleaseFromCart = async () => {
3
+ console.log('[Mock] releaseFromCart called');
4
+ if (!MOCK_CART.products.length) {
5
+ throw new Error('releaseFromCart: the cart is empty');
6
+ }
7
+ const now = new Date().toISOString();
8
+ // Best-effort: the demo has no live-cart order, so the cart becomes a new unpaid draft.
9
+ const order = {
10
+ _id: `order_released_${Date.now()}`,
11
+ receiptId: `REL-${MOCK_ORDERS.length + 1}`,
12
+ status: 'in-cart',
13
+ paymentState: 'unpaid',
14
+ fulfillmentState: 'draft',
15
+ inCart: { active: false, stationId: null, since: now },
16
+ lineItems: [],
17
+ customSales: [],
18
+ paymentMethods: [],
19
+ summary: { total: MOCK_CART.total },
20
+ createdAt: now,
21
+ };
22
+ MOCK_ORDERS.push(order);
23
+ resetMockCart();
24
+ mockPublishEvent('orders', 'order-updated', { order });
25
+ return { success: true, order, timestamp: now };
26
+ };
@@ -0,0 +1,8 @@
1
+ import type { CFOrder } from '../../CommonTypes';
2
+ export interface ReleaseFromCartResponse {
3
+ success: boolean;
4
+ /** The order that left the cart, as saved — its state is unchanged and `inCart.active` is false. */
5
+ order: CFOrder;
6
+ timestamp: string;
7
+ }
8
+ export type ReleaseFromCart = () => Promise<ReleaseFromCartResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Resume order action
3
+ * Calls the resumeOrder action on the parent window
4
+ */
5
+ import type { ResumeOrder } from './types';
6
+ export declare const resumeOrder: ResumeOrder;