@final-commerce/command-frame 0.3.1 → 0.3.2-preprod.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -96,7 +96,7 @@ const context = await client.getContext();
96
96
  The pub/sub system allows iframe extensions to subscribe to topics and receive real-time events published by the host (Render). Subscriptions are **page-scoped** -- they fire only while the iframe is mounted on the current page.
97
97
 
98
98
  - **[Pub/Sub Documentation](./src/pubsub/README.md)**
99
- - **Topics:** Cart (16), Customers (8), Orders (4), Payments (2), Products (4), Refunds (4), Print (3), Custom Tables (3), Outlet (2), Station (2), Session (2), Users (2).
99
+ - **Topics:** Cart (16), Customers (8), Orders (5), Payments (2), Products (4), Refunds (4), Print (3), Custom Tables (3), Outlet (2), Station (2), Session (2), Users (2).
100
100
 
101
101
  ```typescript
102
102
  import { topics } from "@final-commerce/command-frame";
@@ -29,6 +29,15 @@ export interface PrintOptions {
29
29
  };
30
30
  paperSize?: string;
31
31
  width?: string;
32
+ /**
33
+ * Routing tag for multi-printer stations (FI-7113): names the print CATEGORY
34
+ * (e.g. "receipt", "kitchen"), never a printer. The station maps tags to its
35
+ * connected printers; at print time the host resolves the tag and prints to
36
+ * every matched printer at that printer's own paper size/margins. Declare the
37
+ * flow's tag set in flow-settings (`print.tags`) so the station can offer them
38
+ * for mapping. Untagged prints keep the station's default behavior.
39
+ */
40
+ tag?: string;
32
41
  }
33
42
  export interface PrintResponse {
34
43
  success: boolean;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Void order action
3
+ * Calls the voidOrder action on the parent window
4
+ */
5
+ import type { VoidOrder } from './types';
6
+ export declare const voidOrder: VoidOrder;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Void order action
3
+ * Calls the voidOrder action on the parent window
4
+ */
5
+ import { commandFrameClient } from '../../client';
6
+ export const voidOrder = async (params) => {
7
+ return await commandFrameClient.call('voidOrder', params);
8
+ };
@@ -0,0 +1,2 @@
1
+ import { VoidOrder } from './types';
2
+ export declare const mockVoidOrder: VoidOrder;
@@ -0,0 +1,23 @@
1
+ import { MOCK_ORDERS, mockPublishEvent } from '../../demo/database';
2
+ // Payment states in which an order is still open — mirrors the runtime gate
3
+ // (kaching's OPEN_PAYMENT_STATES / handler.ts). Anything outside this set
4
+ // (paid, partially_refunded, refunded, voided, or unknown) is ORDER_NOT_VOIDABLE.
5
+ const OPEN_PAYMENT_STATES = ['unpaid', 'payment_pending', 'partially_paid'];
6
+ export const mockVoidOrder = async (params) => {
7
+ console.log('[Mock] voidOrder called', params);
8
+ const order = params?.orderId ? MOCK_ORDERS.find((o) => o._id === params.orderId) : MOCK_ORDERS[0];
9
+ if (!order) {
10
+ throw new Error(`Order with ID ${params?.orderId} not found`);
11
+ }
12
+ const orderId = order._id;
13
+ // Only OPEN orders are voidable — mirror the runtime gate.
14
+ if (!OPEN_PAYMENT_STATES.includes(order.paymentState)) {
15
+ throw new Error(`ORDER_NOT_VOIDABLE: order ${orderId} is '${order.paymentState}' — use the refund flow for completed orders`);
16
+ }
17
+ const hasCapturedLegs = (order.paymentMethods?.length ?? 0) > 0;
18
+ const outcome = hasCapturedLegs ? 'refunded' : 'voided';
19
+ order.paymentState = outcome;
20
+ order.fulfillmentState = 'cancelled';
21
+ mockPublishEvent('orders', 'order-voided', { orderId, outcome, reason: params?.reason });
22
+ return { success: true, orderId, outcome, timestamp: new Date().toISOString() };
23
+ };
@@ -0,0 +1,27 @@
1
+ import type { CFTransitionResult } from '../../common-types/order-state';
2
+ export type VoidOrderOutcome = 'voided' | 'refunded';
3
+ export interface VoidOrderParams {
4
+ /** Order to void; defaults to the active order. */
5
+ orderId?: string;
6
+ /**
7
+ * Optional cashier-facing reason. On a pure void, recorded on the void audit
8
+ * row and carried on the `order-voided` event. On the refund branch it rides
9
+ * the event only — the refund dispatcher does not consume it.
10
+ */
11
+ reason?: string;
12
+ }
13
+ export interface VoidOrderResponse {
14
+ success: boolean;
15
+ orderId: string;
16
+ /**
17
+ * `voided` — nothing was captured; pure state transition to voided × cancelled.
18
+ * `refunded` — captured split legs were refunded to their original tenders;
19
+ * order lands refunded × cancelled (financially equivalent to a
20
+ * void, but the capture + payout stay on the audit trail).
21
+ */
22
+ outcome: VoidOrderOutcome;
23
+ timestamp: string;
24
+ /** Present when the state machine blocked or forced the transition. */
25
+ transitionResult?: CFTransitionResult;
26
+ }
27
+ export type VoidOrder = (params?: VoidOrderParams) => Promise<VoidOrderResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -51,6 +51,7 @@ export declare const MOCK_PRODUCT_BLACK_GARLIC: import("@final-commerce/common/p
51
51
  export declare const MOCK_ORDER_1: CFActiveOrder;
52
52
  export declare const MOCK_ORDER_2: CFActiveOrder;
53
53
  export declare const MOCK_ORDER_3: CFActiveOrder;
54
+ export declare const MOCK_ORDER_4: CFActiveOrder;
54
55
  export declare const MOCK_PARKED_ORDER_1: CFActiveOrder;
55
56
  export declare const MOCK_PARKED_ORDER_2: CFActiveOrder;
56
57
  export declare const MOCK_USERS: import("@final-commerce/common/pos-types").ActiveUser[];
@@ -486,6 +486,59 @@ export const MOCK_ORDER_3 = {
486
486
  station: MOCK_STATION_1,
487
487
  createdAt: new Date(Date.now() - 7200000).toISOString()
488
488
  };
489
+ // Open order with one captured deposit leg — voidable via the refund branch
490
+ // (demoes voidOrder's `refunded` outcome). Copied from MOCK_ORDER_1, id/state/
491
+ // paymentMethods changed.
492
+ export const MOCK_ORDER_4 = {
493
+ _id: "order_1004",
494
+ currency: CurrencyCode.USD,
495
+ minorUnits: 2,
496
+ receiptId: "1001-0004",
497
+ companyId: MOCK_COMPANY.id,
498
+ externalId: null,
499
+ status: "in_progress",
500
+ paymentState: "partially_paid",
501
+ fulfillmentState: "pending",
502
+ displayState: "Partially Paid",
503
+ customer: MOCK_CUSTOMER_5,
504
+ summary: {
505
+ total: 2500,
506
+ subtotalAfterFees: 2500,
507
+ discountTotal: 0,
508
+ shippingTotal: 0,
509
+ totalTaxes: 0,
510
+ taxes: [],
511
+ isTaxInclusive: false
512
+ },
513
+ cartDiscount: null,
514
+ cartFees: [],
515
+ paymentMethods: [
516
+ {
517
+ transactionId: "trans_cash_2",
518
+ paymentType: "cash",
519
+ amount: 1000,
520
+ timestamp: new Date(Date.now() - 600000).toISOString(),
521
+ processor: "cash"
522
+ }
523
+ ],
524
+ source: "pos",
525
+ posData: {
526
+ outlet: MOCK_OUTLET_MAIN.id,
527
+ station: MOCK_STATION_2._id,
528
+ employee: MOCK_USER_MARIO.id
529
+ },
530
+ sessionId: "sess_4",
531
+ metadata: [],
532
+ billing: null,
533
+ shipping: null,
534
+ lineItems: [createLineItem(MOCK_PRODUCT_RED_PEPPER, 0, 1)],
535
+ customSales: [],
536
+ balance: 1500,
537
+ user: MOCK_USER_MARIO,
538
+ outlet: MOCK_OUTLET_MAIN,
539
+ station: MOCK_STATION_2,
540
+ createdAt: new Date(Date.now() - 600000).toISOString()
541
+ };
489
542
  export const MOCK_PARKED_ORDER_1 = {
490
543
  _id: "parked_2001",
491
544
  currency: CurrencyCode.USD,
@@ -592,7 +645,7 @@ export const MOCK_PRODUCTS = [
592
645
  MOCK_PRODUCT_HABANERO,
593
646
  MOCK_PRODUCT_BLACK_GARLIC
594
647
  ];
595
- export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2, MOCK_ORDER_3];
648
+ export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2, MOCK_ORDER_3, MOCK_ORDER_4];
596
649
  export const MOCK_PARKED_ORDERS = [MOCK_PARKED_ORDER_1, MOCK_PARKED_ORDER_2];
597
650
  // Compatibility Exports (reassigned by setMockDatabase)
598
651
  export let MOCK_USER = MOCK_USERS[0];
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ export declare const command: {
33
33
  readonly parkOrder: import(".").ParkOrder;
34
34
  readonly resumeParkedOrder: import(".").ResumeParkedOrder;
35
35
  readonly deleteParkedOrder: import(".").DeleteParkedOrder;
36
+ readonly voidOrder: import(".").VoidOrder;
36
37
  readonly cashPayment: import(".").CashPayment;
37
38
  readonly getCashRoundingAmount: import(".").GetCashRoundingAmount;
38
39
  readonly tapToPayPayment: import(".").TapToPayPayment;
@@ -161,6 +162,7 @@ export type { ClearCart, ClearCartResponse } from './actions/clear-cart/types';
161
162
  export type { ParkOrder, ParkOrderResponse } from './actions/park-order/types';
162
163
  export type { ResumeParkedOrder, ResumeParkedOrderParams, ResumeParkedOrderResponse, } from './actions/resume-parked-order/types';
163
164
  export type { DeleteParkedOrder, DeleteParkedOrderParams, DeleteParkedOrderResponse, } from './actions/delete-parked-order/types';
165
+ export type { VoidOrder, VoidOrderParams, VoidOrderResponse, VoidOrderOutcome } from './actions/void-order/types';
164
166
  export type { CashPayment, CashPaymentParams, CashPaymentResponse } from './actions/cash-payment/types';
165
167
  export type { GetCashRoundingAmount, GetCashRoundingAmountParams, GetCashRoundingAmountResponse, } from './actions/get-cash-rounding-amount/types';
166
168
  export type { TapToPayPayment, TapToPayPaymentParams, TapToPayPaymentResponse, } from './actions/tap-to-pay-payment/types';
@@ -240,7 +242,7 @@ export { transactionsTopic } from './pubsub/topics/transactions';
240
242
  export { categoriesTopic } from './pubsub/topics/categories';
241
243
  export { attributesTopic } from './pubsub/topics/attributes';
242
244
  export type { CustomerCreatedPayload, CustomerUpdatedPayload, CustomerNoteAddedPayload, CustomerNoteDeletedPayload, CustomerAssignedPayload, CustomerUnassignedPayload, CustomerActiveSetPayload, CustomerActiveGetPayload, CustomerCreatedEvent, CustomerUpdatedEvent, CustomerNoteAddedEvent, CustomerNoteDeletedEvent, CustomerAssignedEvent, CustomerUnassignedEvent, CustomerActiveSetEvent, CustomerActiveGetEvent, CustomersEventType, CustomersEventPayload, } from './pubsub/topics/customers/types';
243
- export type { OrderCreatedPayload, OrderUpdatedPayload, OrderActiveSetPayload, OrderActiveGetPayload, OrderCreatedEvent, OrderUpdatedEvent, OrderActiveSetEvent, OrderActiveGetEvent, OrderStateTransitionCompletedPayload, OrderStateTransitionBlockedPayload, OrderStateTransitionCompletedEvent, OrderStateTransitionBlockedEvent, OrdersEventType, OrdersEventPayload, } from './pubsub/topics/orders/types';
245
+ export type { OrderCreatedPayload, OrderUpdatedPayload, OrderVoidedPayload, OrderActiveSetPayload, OrderActiveGetPayload, OrderCreatedEvent, OrderUpdatedEvent, OrderVoidedEvent, OrderActiveSetEvent, OrderActiveGetEvent, OrderStateTransitionCompletedPayload, OrderStateTransitionBlockedPayload, OrderStateTransitionCompletedEvent, OrderStateTransitionBlockedEvent, OrdersEventType, OrdersEventPayload, } from './pubsub/topics/orders/types';
244
246
  export type { RefundCreatedPayload, RefundUpdatedPayload, RefundActiveSetPayload, RefundActiveGetPayload, RefundCreatedEvent, RefundUpdatedEvent, RefundActiveSetEvent, RefundActiveGetEvent, RefundsEventType, RefundsEventPayload, } from './pubsub/topics/refunds/types';
245
247
  export type { ProductCreatedPayload, ProductUpdatedPayload, ProductSetActivePayload, ProductGetActivePayload, ProductCreatedEvent, ProductUpdatedEvent, ProductSetActiveEvent, ProductGetActiveEvent, ProductsEventType, ProductsEventPayload, } from './pubsub/topics/products/types';
246
248
  export type { OutletActiveSetPayload, OutletActiveGetPayload, OutletActiveSetEvent, OutletActiveGetEvent, OutletEventType, OutletEventPayload, } from './pubsub/topics/outlet/types';
package/dist/index.js CHANGED
@@ -33,6 +33,7 @@ import { clearCart } from './actions/clear-cart/action';
33
33
  import { parkOrder } from './actions/park-order/action';
34
34
  import { resumeParkedOrder } from './actions/resume-parked-order/action';
35
35
  import { deleteParkedOrder } from './actions/delete-parked-order/action';
36
+ import { voidOrder } from './actions/void-order/action';
36
37
  import { cashPayment } from './actions/cash-payment/action';
37
38
  import { getCashRoundingAmount } from './actions/get-cash-rounding-amount/action';
38
39
  import { tapToPayPayment } from './actions/tap-to-pay-payment/action';
@@ -163,6 +164,7 @@ export const command = {
163
164
  parkOrder,
164
165
  resumeParkedOrder,
165
166
  deleteParkedOrder,
167
+ voidOrder,
166
168
  cashPayment,
167
169
  getCashRoundingAmount,
168
170
  tapToPayPayment,
@@ -31,6 +31,7 @@ import { mockCashPayment } from '../../actions/cash-payment/mock';
31
31
  import { mockGetCashRoundingAmount } from '../../actions/get-cash-rounding-amount/mock';
32
32
  import { mockClearCart } from '../../actions/clear-cart/mock';
33
33
  import { mockDeleteParkedOrder } from '../../actions/delete-parked-order/mock';
34
+ import { mockVoidOrder } from '../../actions/void-order/mock';
34
35
  import { mockExampleFunction } from '../../actions/example-function/mock';
35
36
  import { mockGetCategories } from '../../actions/get-categories/mock';
36
37
  import { mockGetContext } from '../../actions/get-context/mock';
@@ -123,6 +124,7 @@ export const RENDER_MOCKS = {
123
124
  getCashRoundingAmount: mockGetCashRoundingAmount,
124
125
  clearCart: mockClearCart,
125
126
  deleteParkedOrder: mockDeleteParkedOrder,
127
+ voidOrder: mockVoidOrder,
126
128
  exampleFunction: mockExampleFunction,
127
129
  getCategories: mockGetCategories,
128
130
  getContext: mockGetContext,
@@ -1,4 +1,4 @@
1
- import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, VendaraPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms } from '../../index';
1
+ import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, VoidOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, VendaraPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms } from '../../index';
2
2
  import type { OpenExtensionOverlay } from '../../actions/open-extension-overlay/types';
3
3
  import type { ResolveExtensionOverlay } from '../../actions/resolve-extension-overlay/types';
4
4
  export interface RenderProviderActions {
@@ -34,6 +34,7 @@ export interface RenderProviderActions {
34
34
  parkOrder: ParkOrder;
35
35
  resumeParkedOrder: ResumeParkedOrder;
36
36
  deleteParkedOrder: DeleteParkedOrder;
37
+ voidOrder: VoidOrder;
37
38
  initiateRefund: InitiateRefund;
38
39
  openExtensionOverlay: OpenExtensionOverlay;
39
40
  resolveExtensionOverlay: ResolveExtensionOverlay;
@@ -36,6 +36,11 @@ export const ordersTopic = {
36
36
  id: "state-transition-blocked",
37
37
  name: "State Transition Blocked",
38
38
  description: "Published when an order state transition is blocked by the state machine"
39
+ },
40
+ {
41
+ id: "order-voided",
42
+ name: "Order Voided",
43
+ description: "Published when an open order is voided (pure void, or captured legs refunded)"
39
44
  }
40
45
  ]
41
46
  };
@@ -0,0 +1,14 @@
1
+ import type { TopicEvent } from '../../../types';
2
+ /**
3
+ * Order Voided Event Types
4
+ */
5
+ export interface OrderVoidedPayload {
6
+ orderId: string;
7
+ /** 'voided' = nothing captured; 'refunded' = captured legs were refunded. */
8
+ outcome: 'voided' | 'refunded';
9
+ reason?: string;
10
+ }
11
+ /**
12
+ * Typed event for order-voided
13
+ */
14
+ export type OrderVoidedEvent = TopicEvent<OrderVoidedPayload>;
@@ -0,0 +1 @@
1
+ export {};
@@ -4,15 +4,17 @@
4
4
  */
5
5
  export * from "./order-created/types";
6
6
  export * from "./order-updated/types";
7
+ export * from "./order-voided/types";
7
8
  export * from "./set-active-order/types";
8
9
  export * from "./get-active-order/types";
9
10
  export * from "./state-transition-completed/types";
10
11
  export * from "./state-transition-blocked/types";
11
12
  import type { OrderCreatedPayload } from "./order-created/types";
12
13
  import type { OrderUpdatedPayload } from "./order-updated/types";
14
+ import type { OrderVoidedPayload } from "./order-voided/types";
13
15
  import type { OrderActiveSetPayload } from "./set-active-order/types";
14
16
  import type { OrderActiveGetPayload } from "./get-active-order/types";
15
17
  import type { OrderStateTransitionCompletedPayload } from "./state-transition-completed/types";
16
18
  import type { OrderStateTransitionBlockedPayload } from "./state-transition-blocked/types";
17
- export type OrdersEventPayload = OrderCreatedPayload | OrderUpdatedPayload | OrderActiveSetPayload | OrderActiveGetPayload | OrderStateTransitionCompletedPayload | OrderStateTransitionBlockedPayload;
18
- export type OrdersEventType = "order-created" | "order-updated" | "set-active-order" | "get-active-order" | "state-transition-completed" | "state-transition-blocked";
19
+ export type OrdersEventPayload = OrderCreatedPayload | OrderUpdatedPayload | OrderVoidedPayload | OrderActiveSetPayload | OrderActiveGetPayload | OrderStateTransitionCompletedPayload | OrderStateTransitionBlockedPayload;
20
+ export type OrdersEventType = "order-created" | "order-updated" | "order-voided" | "set-active-order" | "get-active-order" | "state-transition-completed" | "state-transition-blocked";
@@ -5,6 +5,7 @@
5
5
  // Re-export all event types
6
6
  export * from "./order-created/types";
7
7
  export * from "./order-updated/types";
8
+ export * from "./order-voided/types";
8
9
  export * from "./set-active-order/types";
9
10
  export * from "./get-active-order/types";
10
11
  export * from "./state-transition-completed/types";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@final-commerce/command-frame",
3
- "version": "0.3.1",
3
+ "version": "0.3.2-preprod.1",
4
4
  "description": "Commands Frame library",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",