@final-commerce/command-frame 0.3.0-beta.3 → 0.3.0-beta.5

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 (123) hide show
  1. package/README.md +50 -28
  2. package/dist/CommonTypes.d.ts +2 -1
  3. package/dist/actions/add-cart-discount/mock.js +6 -3
  4. package/dist/actions/add-cart-fee/mock.js +6 -6
  5. package/dist/actions/add-custom-sale/mock.js +7 -2
  6. package/dist/actions/add-order-note/mock.js +3 -1
  7. package/dist/actions/apply-transition/action.d.ts +2 -0
  8. package/dist/actions/apply-transition/action.js +4 -0
  9. package/dist/actions/apply-transition/mock.d.ts +6 -0
  10. package/dist/actions/apply-transition/mock.js +33 -0
  11. package/dist/actions/apply-transition/types.d.ts +17 -0
  12. package/dist/actions/can-transition/action.d.ts +2 -0
  13. package/dist/actions/can-transition/action.js +4 -0
  14. package/dist/actions/can-transition/mock.d.ts +6 -0
  15. package/dist/actions/can-transition/mock.js +28 -0
  16. package/dist/actions/can-transition/types.d.ts +11 -0
  17. package/dist/actions/cash-payment/mock.js +12 -18
  18. package/dist/actions/cash-payment/types.d.ts +5 -0
  19. package/dist/actions/delete-parked-order/mock.js +3 -1
  20. package/dist/actions/delete-parked-order/types.d.ts +3 -0
  21. package/dist/actions/extension-payment/types.d.ts +8 -3
  22. package/dist/actions/get-available-transitions/action.d.ts +2 -0
  23. package/dist/actions/get-available-transitions/action.js +4 -0
  24. package/dist/actions/get-available-transitions/mock.d.ts +6 -0
  25. package/dist/actions/get-available-transitions/mock.js +26 -0
  26. package/dist/actions/get-available-transitions/types.d.ts +9 -0
  27. package/dist/actions/get-context/mock.js +1 -1
  28. package/dist/actions/get-orders/mock.js +3 -3
  29. package/dist/actions/get-products/mock.js +6 -1
  30. package/dist/actions/get-products/types.d.ts +2 -0
  31. package/dist/actions/get-smart-grid-layout/mock.d.ts +1 -1
  32. package/dist/actions/get-smart-grid-layout/mock.js +3 -1
  33. package/dist/actions/get-smart-grid-layout/types.d.ts +1 -3
  34. package/dist/actions/initiate-refund/types.d.ts +3 -0
  35. package/dist/actions/integration-payment/types.d.ts +48 -8
  36. package/dist/actions/open-extension-overlay/mock.js +1 -1
  37. package/dist/actions/open-extension-overlay/types.d.ts +1 -1
  38. package/dist/actions/park-order/mock.js +4 -1
  39. package/dist/actions/park-order/types.d.ts +3 -0
  40. package/dist/actions/partial-payment/mock.js +21 -3
  41. package/dist/actions/partial-payment/types.d.ts +5 -0
  42. package/dist/actions/process-partial-refund/types.d.ts +3 -0
  43. package/dist/actions/redeem-payment/types.d.ts +9 -5
  44. package/dist/actions/remove-custom-sale/mock.d.ts +2 -0
  45. package/dist/actions/remove-custom-sale/mock.js +29 -0
  46. package/dist/actions/remove-customer-from-cart/mock.js +3 -1
  47. package/dist/actions/remove-order-note/mock.d.ts +2 -0
  48. package/dist/actions/remove-order-note/mock.js +12 -0
  49. package/dist/actions/remove-product-discount/mock.d.ts +2 -0
  50. package/dist/actions/remove-product-discount/mock.js +17 -0
  51. package/dist/actions/remove-product-fee/mock.d.ts +2 -0
  52. package/dist/actions/remove-product-fee/mock.js +17 -0
  53. package/dist/actions/remove-product-from-cart/mock.js +5 -5
  54. package/dist/actions/resolve-extension-overlay/mock.js +1 -1
  55. package/dist/actions/resume-parked-order/mock.js +4 -1
  56. package/dist/actions/resume-parked-order/types.d.ts +3 -0
  57. package/dist/actions/save-smart-grid-layout/mock.d.ts +1 -1
  58. package/dist/actions/save-smart-grid-layout/mock.js +3 -0
  59. package/dist/actions/save-smart-grid-layout/types.d.ts +1 -3
  60. package/dist/actions/tap-to-pay-payment/mock.js +5 -3
  61. package/dist/actions/tap-to-pay-payment/types.d.ts +5 -0
  62. package/dist/actions/terminal-payment/mock.js +4 -5
  63. package/dist/actions/terminal-payment/types.d.ts +5 -0
  64. package/dist/actions/update-cart-item-quantity/mock.js +9 -9
  65. package/dist/actions/vendara-payment/types.d.ts +5 -0
  66. package/dist/common-types/index.d.ts +1 -0
  67. package/dist/common-types/index.js +1 -0
  68. package/dist/common-types/order-state.d.ts +32 -0
  69. package/dist/common-types/order-state.js +6 -0
  70. package/dist/common-types/state-fragment.d.ts +77 -0
  71. package/dist/common-types/state-fragment.js +10 -0
  72. package/dist/demo/database.d.ts +12 -1
  73. package/dist/demo/database.js +173 -3
  74. package/dist/fragments/index.d.ts +1 -0
  75. package/dist/fragments/index.js +1 -0
  76. package/dist/fragments/preorder-no-deposit.d.ts +26 -0
  77. package/dist/fragments/preorder-no-deposit.js +166 -0
  78. package/dist/index.d.ts +21 -20
  79. package/dist/index.js +23 -21
  80. package/dist/interceptors/index.d.ts +21 -0
  81. package/dist/interceptors/index.js +53 -0
  82. package/dist/interceptors/types.d.ts +8 -16
  83. package/dist/projects/render/mocks.js +19 -17
  84. package/dist/projects/render/types.d.ts +7 -6
  85. package/dist/pubsub/topics/orders/index.js +10 -0
  86. package/dist/pubsub/topics/orders/state-transition-blocked/types.d.ts +16 -0
  87. package/dist/pubsub/topics/orders/state-transition-blocked/types.js +1 -0
  88. package/dist/pubsub/topics/orders/state-transition-completed/types.d.ts +15 -0
  89. package/dist/pubsub/topics/orders/state-transition-completed/types.js +1 -0
  90. package/dist/pubsub/topics/orders/types.d.ts +6 -2
  91. package/dist/pubsub/topics/orders/types.js +2 -0
  92. package/dist/pubsub/topics/split-payments/index.d.ts +12 -0
  93. package/dist/pubsub/topics/split-payments/index.js +22 -0
  94. package/dist/pubsub/topics/split-payments/split-payment-updated/types.d.ts +16 -0
  95. package/dist/pubsub/topics/split-payments/split-payment-updated/types.js +1 -0
  96. package/dist/pubsub/topics/split-payments/types.d.ts +10 -0
  97. package/dist/pubsub/topics/split-payments/types.js +5 -0
  98. package/dist/pubsub/topics/types.d.ts +2 -0
  99. package/package.json +3 -3
  100. package/dist/actions/extension-refund/constants.d.ts +0 -2
  101. package/dist/actions/extension-refund/constants.js +0 -2
  102. package/dist/actions/extension-refund/extension-refund-listener.d.ts +0 -11
  103. package/dist/actions/extension-refund/extension-refund-listener.js +0 -60
  104. package/dist/actions/extension-refund/types.d.ts +0 -32
  105. package/dist/actions/extension-refund/types.js +0 -5
  106. package/dist/actions/set-active-outlet/action.d.ts +0 -2
  107. package/dist/actions/set-active-outlet/action.js +0 -4
  108. package/dist/actions/set-active-outlet/mock.d.ts +0 -2
  109. package/dist/actions/set-active-outlet/mock.js +0 -16
  110. package/dist/actions/set-active-outlet/types.d.ts +0 -10
  111. package/dist/actions/set-active-session/action.d.ts +0 -2
  112. package/dist/actions/set-active-session/action.js +0 -4
  113. package/dist/actions/set-active-session/mock.d.ts +0 -2
  114. package/dist/actions/set-active-session/mock.js +0 -15
  115. package/dist/actions/set-active-session/types.d.ts +0 -10
  116. package/dist/actions/set-active-station/action.d.ts +0 -2
  117. package/dist/actions/set-active-station/action.js +0 -4
  118. package/dist/actions/set-active-station/mock.d.ts +0 -2
  119. package/dist/actions/set-active-station/mock.js +0 -16
  120. package/dist/actions/set-active-station/types.d.ts +0 -10
  121. /package/dist/actions/{set-active-outlet → apply-transition}/types.js +0 -0
  122. /package/dist/actions/{set-active-session → can-transition}/types.js +0 -0
  123. /package/dist/actions/{set-active-station → get-available-transitions}/types.js +0 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * State machine protocol types for the command-frame boundary.
3
+ * These mirror @final-commerce/common shapes but carry no logic.
4
+ * command-frame must NOT depend on common.
5
+ */
6
+ export {};
@@ -0,0 +1,77 @@
1
+ /**
2
+ * State config fragment types for the command-frame boundary.
3
+ * These mirror @final-commerce/common's StateConfigFragment shapes but carry no logic.
4
+ * command-frame must NOT depend on common.
5
+ *
6
+ * Extensions pass a CFStateConfigFragment to Render, which merges it into the
7
+ * running StoredStateConfig via mergeFragment(). All contributed entries are tagged
8
+ * with the extension's id (_sourceExtensionId) so they can be cleaned up on unregister.
9
+ */
10
+ import type { CFStatePair } from "./order-state";
11
+ export type CFConditionOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "notIn" | "isEmpty" | "isNotEmpty";
12
+ export interface CFCondition {
13
+ /** Dot-path into the OrderContext, e.g. "order.balance" or "computed.totalPaid". */
14
+ field: string;
15
+ operator: CFConditionOperator;
16
+ value: unknown;
17
+ }
18
+ /** All conditions in a group are AND'd together. */
19
+ export interface CFConditionGroup {
20
+ conditions: CFCondition[];
21
+ }
22
+ /** Groups are OR'd — the first passing group satisfies the set. */
23
+ export interface CFTransitionConditionSet {
24
+ id: string;
25
+ label: string;
26
+ groups: CFConditionGroup[];
27
+ }
28
+ export interface CFPaymentTransitionPath {
29
+ from: string;
30
+ to: string;
31
+ /** References a CFTransitionConditionSet.id in the same fragment. */
32
+ conditionSetId?: string;
33
+ }
34
+ export interface CFFulfillmentTransitionPath {
35
+ from: string;
36
+ to: string;
37
+ conditionSetId?: string;
38
+ }
39
+ export interface CFCrossAxisRule {
40
+ id: string;
41
+ label: string;
42
+ description?: string;
43
+ enabled: boolean;
44
+ /** Which axis + target state(s) activate this rule. */
45
+ trigger: {
46
+ axis: "payment" | "fulfillment";
47
+ to: string[];
48
+ };
49
+ /** Which axis + states must be present when the trigger fires. */
50
+ requires: {
51
+ axis: "payment" | "fulfillment";
52
+ states: string[];
53
+ };
54
+ }
55
+ export interface CFDisplayStateRule {
56
+ paymentState?: string[];
57
+ fulfillmentState?: string[];
58
+ label: string;
59
+ color?: string;
60
+ icon?: string;
61
+ }
62
+ /**
63
+ * Partial config contributed by an extension. Render merges this into the
64
+ * running StoredStateConfig. All arrays are appended; display rules replace
65
+ * on key collision.
66
+ *
67
+ * IDs (crossAxisRules, transitionConditions) must be unique across the merged
68
+ * config — prefix them with your extension id to avoid collisions.
69
+ */
70
+ export interface CFStateConfigFragment {
71
+ paymentPaths?: CFPaymentTransitionPath[];
72
+ fulfillmentPaths?: CFFulfillmentTransitionPath[];
73
+ crossAxisRules?: CFCrossAxisRule[];
74
+ transitionConditions?: CFTransitionConditionSet[];
75
+ validInitialStates?: CFStatePair[];
76
+ displayStateMap?: CFDisplayStateRule[];
77
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * State config fragment types for the command-frame boundary.
3
+ * These mirror @final-commerce/common's StateConfigFragment shapes but carry no logic.
4
+ * command-frame must NOT depend on common.
5
+ *
6
+ * Extensions pass a CFStateConfigFragment to Render, which merges it into the
7
+ * running StoredStateConfig via mergeFragment(). All contributed entries are tagged
8
+ * with the extension's id (_sourceExtensionId) so they can be cleaned up on unregister.
9
+ */
10
+ export {};
@@ -2,7 +2,7 @@
2
2
  * Mock Database for Standalone/Demo Mode
3
3
  * Stores mock data that mimics the Render environment
4
4
  */
5
- import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails } from "../CommonTypes";
5
+ import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails, CFSmartGridLayout } from "../CommonTypes";
6
6
  export * from "./mocks";
7
7
  /** Replace mock catalog / context data in place (same array references mock handlers use). */
8
8
  export interface MockDatabaseConfig {
@@ -50,6 +50,9 @@ export declare const MOCK_PRODUCT_HABANERO: import("@final-commerce/common/pos-t
50
50
  export declare const MOCK_PRODUCT_BLACK_GARLIC: import("@final-commerce/common/pos-types").FullProduct;
51
51
  export declare const MOCK_ORDER_1: CFActiveOrder;
52
52
  export declare const MOCK_ORDER_2: CFActiveOrder;
53
+ export declare const MOCK_ORDER_3: CFActiveOrder;
54
+ export declare const MOCK_PARKED_ORDER_1: CFActiveOrder;
55
+ export declare const MOCK_PARKED_ORDER_2: CFActiveOrder;
53
56
  export declare const MOCK_USERS: import("@final-commerce/common/pos-types").ActiveUser[];
54
57
  export declare const MOCK_STATIONS: import("@final-commerce/common/pos-types").ActiveStation[];
55
58
  export declare const MOCK_OUTLETS: import("@final-commerce/common/pos-types").ActiveOutlet[];
@@ -64,6 +67,7 @@ export declare let MOCK_OUTLET: CFActiveOutlet;
64
67
  export declare let MOCK_CART: CFActiveCart;
65
68
  export declare let MOCK_ACTIVE_PRODUCT: CFActiveProduct;
66
69
  export declare const setMockActiveProduct: (activeProduct: CFActiveProduct) => void;
70
+ export declare const MOCK_SMART_GRID_LAYOUTS: Record<string, CFSmartGridLayout>;
67
71
  export declare const resetMockCart: () => void;
68
72
  /**
69
73
  * Replace in-memory mock data used by default mock handlers. Arrays are mutated in place
@@ -75,3 +79,10 @@ type MockEventCallback = (event: any) => void;
75
79
  export declare const mockPublishEvent: (topic: string, eventType: string, data: any) => void;
76
80
  export declare const mockSubscribeToTopic: (topic: string, callback: MockEventCallback) => void;
77
81
  export declare const createOrderFromCart: (paymentType: string, amount: number, processor?: string) => CFActiveOrder;
82
+ /**
83
+ * Apply a (possibly partial) payment of `amount` minor units to the active cart.
84
+ * Decrements the remaining balance; when it reaches zero the sale completes
85
+ * (creates the order, resets the cart, returns it). Otherwise the cart stays
86
+ * open with `amountToBeCharged` reset to what's left, and returns null.
87
+ */
88
+ export declare const applyMockPayment: (amount: number, paymentType: string, processor?: string) => CFActiveOrder | null;
@@ -6,7 +6,7 @@ import { CFProductType, CFUserTypes, CurrencyCode } from "../CommonTypes";
6
6
  export * from "./mocks";
7
7
  // Asset Imports - Using Remote URLs to avoid build complexity with asset copying
8
8
  const ASSETS_BASE_URL = "https://raw.githubusercontent.com/Final-Commerce/command-frame/refs/heads/main/src/demo/assets";
9
- const logo = `${ASSETS_BASE_URL}/logo.png`;
9
+ const logo = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA5OCAxMDQiIGZpbGw9Im5vbmUiPjxwYXRoIGQ9Ik01NS4yOTk4IDUwLjE2NjJMMzcuNzQyMiA0MC4wMjkzTDMxLjcyNzQgNTAuNDQ3MkwzOC45MjQyIDU0LjYwMjJMNTUuMjk5OCA1MC4xNjYyWiIgZmlsbD0iI0E1NjhCQyIvPjxwYXRoIGQ9Ik0zMS45OTYzIDcwLjQ1MDZMNDkuNTU2OCA4MC41ODkxTDU1LjU3MTUgNzAuMTcxM0w0OC4zNzE4IDY2LjAxNDVMMzEuOTk2MyA3MC40NTA2WiIgZmlsbD0iI0E1NjhCQyIvPjxwYXRoIGQ9Ik0zNi4zNTQyIDM0LjI1NzJDMzYuMzU0MiAzNC4yNTcyIDM2LjM1ODMgMzQuMjYzNSAzNi4zNTY3IDM0LjI2NjRDMzcuMTg2OSAzNC4wNjk3IDM4LjA5MTkgMzQuMTU5NiAzOC44ODUxIDM0LjYxNzVMNjIuNjQ4NiA0OC4zMzc0TDU0LjE3MjkgMjkuOTA0OUwzNi4zNDk2IDM0LjI1ODRMMzYuMzU0MiAzNC4yNTcyWiIgZmlsbD0iI0ZDODc1MyIvPjxwYXRoIGQ9Ik0zMy4wOTg4IDE4Ljk1MDdMMzYuMzc3MiAzNC4yNDczTDE4Ljc1MjUgMzkuMzM3M0wyOC45MzcxIDIxLjY5N0MyOS44NDUzIDIwLjEyMzkgMzEuNDE1MiAxOS4xNzYxIDMzLjA5ODggMTguOTUwN1oiIGZpbGw9IiM0MkQzQTkiLz48cGF0aCBkPSJNMTguNzUzMiAzOS4zNDA2TDIwLjY4MjQgNTkuNTE3MUw0LjU3NjA3IDYzLjg5NjJMMTguNzUzMiAzOS4zNDA2WiIgZmlsbD0iIzI3OTdFOCIvPjxwYXRoIGQ9Ik0zNi4zNzc5IDM0LjI0MDNDMzYuMzc3OSAzNC4yNDAzIDM2LjM3NzQgMzQuMjQ3OCAzNi4zODAzIDM0LjI0OTVDMzUuNTYyNCAzNC40OTE5IDM0LjgyMzkgMzUuMDE5NiAzNC4zNjczIDM1LjgxMDVMMjAuNjg2OSA1OS41MDU2TDE4Ljc1NzcgMzkuMzI5MUwzNi4zODI0IDM0LjIzOTFMMzYuMzc3OSAzNC4yNDAzWiIgZmlsbD0iIzFEQkFDQiIvPjxwYXRoIGQ9Ik01NS45MzUyIDEwMS41NDNMNTEuMDgxOSA4Ni42NjU5TDMzLjI1ODcgOTEuMDE5NEw1MC45NDk5IDEwMS4yMzNDNTIuNTI3NiAxMDIuMTQ0IDU0LjM2MzggMTAyLjE4NSA1NS45MzUyIDEwMS41NDNaIiBmaWxsPSIjRkQ1MjYzIi8+PHBhdGggZD0iTTMzLjI1NDkgOTEuMDE0TDI0Ljc4MjEgNzIuNTgzMkw4LjYzMTM1IDc2Ljc5NzVMMzMuMjU0OSA5MS4wMTRaIiBmaWxsPSIjRkZDRjIzIi8+PHBhdGggZD0iTTUxLjA3OSA4Ni42NjM5QzUxLjA3OSA4Ni42NjM5IDUxLjA3NDkgODYuNjU3NiA1MS4wNzY2IDg2LjY1NDdDNTAuMjQ2NCA4Ni44NTE0IDQ5LjM0MTQgODYuNzYxNSA0OC41NDgyIDg2LjMwMzZMMjQuNzg0NiA3Mi41ODM3TDMzLjI2MDQgOTEuMDE2MUw1MS4wODM2IDg2LjY2MjdMNTEuMDc5IDg2LjY2MzlaIiBmaWxsPSIjRkM4NzUzIi8+PHBhdGggZD0iTTU0LjMzNDIgMTAxLjk2OUw1MS4wNTU4IDg2LjY3MjRMNjguNjgwNSA4MS41ODI0TDU4LjQ5NTkgOTkuMjIyN0M1Ny41ODc3IDEwMC43OTYgNTYuMDE3OCAxMDEuNzQ0IDU0LjMzNDIgMTAxLjk2OVoiIGZpbGw9IiM0MkQzQTkiLz48cGF0aCBkPSJNNjguNjgwMSA4MS41ODk5TDY2Ljc0OTMgNjEuNDE2Mkw4Mi44NTU2IDU3LjAzNzJMNjguNjgwMSA4MS41ODk5WiIgZmlsbD0iIzI3OTdFOCIvPjxwYXRoIGQ9Ik01MS4wNTU3IDg2LjY3ODZDNTEuMDU1NyA4Ni42Nzg2IDUxLjA1NjIgODYuNjcxMSA1MS4wNTMyIDg2LjY2OTVDNTEuODcxMSA4Ni40MjcxIDUyLjYwOTcgODUuODk5NCA1My4wNjYzIDg1LjEwODVMNjYuNzQ2NyA2MS40MTMzTDY4LjY3NTkgODEuNTg5OEw1MS4wNTExIDg2LjY3OThMNTEuMDU1NyA4Ni42Nzg2WiIgZmlsbD0iIzFEQkFDQiIvPjxwYXRoIGQ9Ik00Ny44OTQ5IDI2LjI3NjhDNDcuODc4IDI2LjM1OTcgNDcuODUyIDI2LjQ0NTEgNDcuODA2OCAyNi41MjM0TDQ3LjYyNzggMjYuODMzM0M0Ni43ODY1IDI4LjI5MDYgNDQuOTIzMiAyOC43ODY5IDQzLjQ2MTggMjcuOTQzMkM0Mi4wMDA0IDI3LjA5OTQgNDEuNDk4NiAyNS4yMzc2IDQyLjMzOTkgMjMuNzgwNEw0Mi41MTg5IDIzLjQ3MDRDNDIuNTY0MSAyMy4zOTIyIDQyLjYyNSAyMy4zMjY5IDQyLjY4ODQgMjMuMjcwOEwzNi40ODUzIDE5LjY4OTRDMzQuOTA3NiAxOC43Nzg2IDMzLjA3MTQgMTguNzM4MiAzMS41IDE5LjM3OTlMMzYuMzUzMyAzNC4yNTY5TDU0LjE3NjUgMjkuOTAzNUw0Ny44OTQ5IDI2LjI3NjhaIiBmaWxsPSIjRkQ1MjYzIi8+PHBhdGggZD0iTTc1LjYzODYgNDIuMzAyN0M3NS42MjE3IDQyLjM4NTcgNzUuNTk1NiA0Mi40NzExIDc1LjU1MDUgNDIuNTQ5M0w3NS4zNzE1IDQyLjg1OTNDNzQuNTMwMiA0NC4zMTY1IDcyLjY2NjkgNDQuODEyOSA3MS4yMDU0IDQzLjk2OTFDNjkuNzQ0IDQzLjEyNTQgNjkuMjQyMyA0MS4yNjM2IDcwLjA4MzYgMzkuODA2M0w3MC4yNjI2IDM5LjQ5NjNDNzAuMzA3NyAzOS40MTgxIDcwLjM2ODYgMzkuMzUyOSA3MC40MzIgMzkuMjk2N0w1NC4xNzYxIDI5LjkxMTRMNjIuNjUxOSA0OC4zNDM5TDc4LjgwMjYgNDQuMTI5NUw3NS42NDE1IDQyLjMwNDRMNzUuNjM4NiA0Mi4zMDI3WiIgZmlsbD0iI0ZGQ0YyMyIvPjxwYXRoIGQ9Ik03NS42MDU4IDQwLjgyMTlMNzUuNjQ0MiA0MC43NTUyQzc4LjE0ODEgMzYuNDE4MyA3OC42NDY1IDMxLjQ0ODggNzcuNDMwOSAyNi45MzgzQzc2LjIxNTMgMjIuNDI3OCA3My4yODQ3IDE4LjM3MTggNjguOTM1MiAxNS44NjA3QzY0LjU4NTggMTMuMzQ5NSA1OS42MDc5IDEyLjgzOTUgNTUuMDkzOSAxNC4wNDJDNTAuNTc5OSAxNS4yNDQ2IDQ2LjUyNTMgMTguMTYwOSA0NC4wMjE0IDIyLjQ5NzhMNDIuOTkxMSAyNC4yODI0QzQyLjM3MzkgMjUuMzUxNCA0Mi43NDQyIDI2LjcxNjMgNDMuODEzNCAyNy4zMzM2QzQ0Ljg4MjYgMjcuOTUwOSA0Ni4yNTE0IDI3LjU4NjIgNDYuODY2OSAyNi41MjAxTDQ3Ljg5NzMgMjQuNzM1NUM0OS43ODU3IDIxLjQ2NDcgNTIuODQ0MSAxOS4yNjczIDU2LjI1NDggMTguMzU4N0M1OS42NjU0IDE3LjQ1MDEgNjMuNDE5MSAxNy44MzI3IDY2LjY5OTQgMTkuNzI2NkM2OS45Nzk2IDIxLjYyMDQgNzIuMTg3OSAyNC42Nzk5IDczLjEwNjMgMjguMDg3OUM3NC4wMjQ4IDMxLjQ5NiA3My42NTEgMzUuMjQzNCA3MS43NjI2IDM4LjUxNDFMNzEuNzI0MSAzOC41ODA4TDcwLjczMzkgNDAuMjk1OEM3MC4xMTY3IDQxLjM2NDkgNzAuNDg3IDQyLjcyOTcgNzEuNTU2MiA0My4zNDdDNzIuNjI1NCA0My45NjQ0IDczLjk5NDIgNDMuNTk5NyA3NC42MDk4IDQyLjUzMzZMNzUuNTk5OSA0MC44MTg1TDc1LjYwNTggNDAuODIxOVoiIGZpbGw9IiMzRDRDNjYiLz48L3N2Zz4="; // crisp vector mark (was logo.png — pixelated when scaled)
10
10
  const basilAlmondImg = `${ASSETS_BASE_URL}/basil-almond-paste.png`;
11
11
  const beerImg = `${ASSETS_BASE_URL}/beer-paste.png`;
12
12
  const beetImg = `${ASSETS_BASE_URL}/beet-paste.png`;
@@ -343,6 +343,9 @@ export const MOCK_ORDER_1 = {
343
343
  companyId: MOCK_COMPANY.id,
344
344
  externalId: null,
345
345
  status: "completed",
346
+ paymentState: "paid",
347
+ fulfillmentState: "fulfilled",
348
+ displayState: "Completed",
346
349
  customer: MOCK_CUSTOMER_1,
347
350
  summary: {
348
351
  total: 2100,
@@ -390,6 +393,9 @@ export const MOCK_ORDER_2 = {
390
393
  companyId: MOCK_COMPANY.id,
391
394
  externalId: null,
392
395
  status: "completed",
396
+ paymentState: "paid",
397
+ fulfillmentState: "fulfilled",
398
+ displayState: "Completed",
393
399
  customer: MOCK_CUSTOMER_2,
394
400
  summary: {
395
401
  total: 3000,
@@ -429,6 +435,140 @@ export const MOCK_ORDER_2 = {
429
435
  station: MOCK_STATION_2,
430
436
  createdAt: new Date(Date.now() - 3600000).toISOString()
431
437
  };
438
+ export const MOCK_ORDER_3 = {
439
+ _id: "order_1003",
440
+ currency: CurrencyCode.USD,
441
+ minorUnits: 2,
442
+ receiptId: "1001-0003",
443
+ companyId: MOCK_COMPANY.id,
444
+ externalId: null,
445
+ status: "refunded",
446
+ paymentState: "refunded",
447
+ fulfillmentState: "fulfilled",
448
+ displayState: "Refunded",
449
+ customer: MOCK_CUSTOMER_3,
450
+ summary: {
451
+ total: 1500,
452
+ subtotalAfterFees: 1500,
453
+ discountTotal: 0,
454
+ shippingTotal: 0,
455
+ totalTaxes: 0,
456
+ taxes: [],
457
+ isTaxInclusive: false
458
+ },
459
+ cartDiscount: null,
460
+ cartFees: [],
461
+ paymentMethods: [
462
+ {
463
+ transactionId: "trans_card_2",
464
+ paymentType: "credit_card",
465
+ amount: 1500,
466
+ timestamp: new Date(Date.now() - 7200000).toISOString(),
467
+ processor: "stripe"
468
+ }
469
+ ],
470
+ source: "pos",
471
+ posData: {
472
+ outlet: MOCK_OUTLET_MAIN.id,
473
+ station: MOCK_STATION_1._id,
474
+ employee: MOCK_USER_MARIO.id
475
+ },
476
+ sessionId: "sess_3",
477
+ metadata: [],
478
+ billing: null,
479
+ shipping: null,
480
+ lineItems: [createLineItem(MOCK_PRODUCT_BEET, 0, 1)],
481
+ customSales: [],
482
+ balance: 0,
483
+ user: MOCK_USER_MARIO,
484
+ outlet: MOCK_OUTLET_MAIN,
485
+ station: MOCK_STATION_1,
486
+ createdAt: new Date(Date.now() - 7200000).toISOString()
487
+ };
488
+ export const MOCK_PARKED_ORDER_1 = {
489
+ _id: "parked_2001",
490
+ currency: CurrencyCode.USD,
491
+ minorUnits: 2,
492
+ receiptId: "PARK-0001",
493
+ companyId: MOCK_COMPANY.id,
494
+ externalId: null,
495
+ status: "parked",
496
+ paymentState: "unpaid",
497
+ fulfillmentState: "pending",
498
+ displayState: "Parked",
499
+ customer: MOCK_CUSTOMER_4,
500
+ summary: {
501
+ total: 2100,
502
+ subtotalAfterFees: 2100,
503
+ discountTotal: 0,
504
+ shippingTotal: 0,
505
+ totalTaxes: 0,
506
+ taxes: [],
507
+ isTaxInclusive: false
508
+ },
509
+ cartDiscount: null,
510
+ cartFees: [],
511
+ paymentMethods: [],
512
+ source: "pos",
513
+ posData: {
514
+ outlet: MOCK_OUTLET_MAIN.id,
515
+ station: MOCK_STATION_1._id,
516
+ employee: MOCK_USER_LUIGI.id
517
+ },
518
+ sessionId: "sess_park_1",
519
+ metadata: [],
520
+ billing: null,
521
+ shipping: null,
522
+ lineItems: [createLineItem(MOCK_PRODUCT_LEMON, 0, 2)],
523
+ customSales: [],
524
+ balance: 2100,
525
+ user: MOCK_USER_LUIGI,
526
+ outlet: MOCK_OUTLET_MAIN,
527
+ station: MOCK_STATION_1,
528
+ createdAt: new Date(Date.now() - 1800000).toISOString()
529
+ };
530
+ export const MOCK_PARKED_ORDER_2 = {
531
+ _id: "parked_2002",
532
+ currency: CurrencyCode.USD,
533
+ minorUnits: 2,
534
+ receiptId: "PARK-0002",
535
+ companyId: MOCK_COMPANY.id,
536
+ externalId: null,
537
+ status: "parked",
538
+ paymentState: "unpaid",
539
+ fulfillmentState: "pending",
540
+ displayState: "Parked",
541
+ customer: null,
542
+ summary: {
543
+ total: 2500,
544
+ subtotalAfterFees: 2500,
545
+ discountTotal: 0,
546
+ shippingTotal: 0,
547
+ totalTaxes: 0,
548
+ taxes: [],
549
+ isTaxInclusive: false
550
+ },
551
+ cartDiscount: null,
552
+ cartFees: [],
553
+ paymentMethods: [],
554
+ source: "pos",
555
+ posData: {
556
+ outlet: MOCK_OUTLET_MAIN.id,
557
+ station: MOCK_STATION_2._id,
558
+ employee: MOCK_USER_MARIO.id
559
+ },
560
+ sessionId: "sess_park_2",
561
+ metadata: [],
562
+ billing: null,
563
+ shipping: null,
564
+ lineItems: [createLineItem(MOCK_PRODUCT_CARAMELIZED, 0, 1), createLineItem(MOCK_PRODUCT_GINGER_LIME, 0, 1)],
565
+ customSales: [],
566
+ balance: 2500,
567
+ user: MOCK_USER_MARIO,
568
+ outlet: MOCK_OUTLET_MAIN,
569
+ station: MOCK_STATION_2,
570
+ createdAt: new Date(Date.now() - 900000).toISOString()
571
+ };
432
572
  // --- EXPORT COLLECTIONS ---
433
573
  export const MOCK_USERS = [MOCK_USER_MARIO, MOCK_USER_LUIGI];
434
574
  export const MOCK_STATIONS = [MOCK_STATION_1, MOCK_STATION_2];
@@ -451,8 +591,8 @@ export const MOCK_PRODUCTS = [
451
591
  MOCK_PRODUCT_HABANERO,
452
592
  MOCK_PRODUCT_BLACK_GARLIC
453
593
  ];
454
- export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2];
455
- export const MOCK_PARKED_ORDERS = [];
594
+ export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2, MOCK_ORDER_3];
595
+ export const MOCK_PARKED_ORDERS = [MOCK_PARKED_ORDER_1, MOCK_PARKED_ORDER_2];
456
596
  // Compatibility Exports (reassigned by setMockDatabase)
457
597
  export let MOCK_USER = MOCK_USERS[0];
458
598
  export let MOCK_STATION = MOCK_STATIONS[0];
@@ -471,6 +611,10 @@ export let MOCK_ACTIVE_PRODUCT;
471
611
  export const setMockActiveProduct = (activeProduct) => {
472
612
  MOCK_ACTIVE_PRODUCT = activeProduct;
473
613
  };
614
+ // In-memory smart-grid layouts keyed by gridId. Used by mockGetSmartGridLayout /
615
+ // mockSaveSmartGridLayout so the standalone builder (no command-frame host) can
616
+ // round-trip layouts within a session.
617
+ export const MOCK_SMART_GRID_LAYOUTS = {};
474
618
  // Helper to reset cart
475
619
  export const resetMockCart = () => {
476
620
  MOCK_CART = {
@@ -612,6 +756,9 @@ export const createOrderFromCart = (paymentType, amount, processor = "cash") =>
612
756
  companyId: MOCK_COMPANY.id,
613
757
  externalId: null,
614
758
  status: "completed",
759
+ paymentState: "paid",
760
+ fulfillmentState: "fulfilled",
761
+ displayState: "Completed",
615
762
  customer: MOCK_CART.customer ? MOCK_CART.customer : null,
616
763
  summary: {
617
764
  total: totalNum,
@@ -657,3 +804,26 @@ export const createOrderFromCart = (paymentType, amount, processor = "cash") =>
657
804
  mockPublishEvent("cart", "cart-created", {});
658
805
  return newOrder;
659
806
  };
807
+ /**
808
+ * Apply a (possibly partial) payment of `amount` minor units to the active cart.
809
+ * Decrements the remaining balance; when it reaches zero the sale completes
810
+ * (creates the order, resets the cart, returns it). Otherwise the cart stays
811
+ * open with `amountToBeCharged` reset to what's left, and returns null.
812
+ */
813
+ export const applyMockPayment = (amount, paymentType, processor = "cash") => {
814
+ const remainingBefore = MOCK_CART.remainingBalance ?? MOCK_CART.total;
815
+ const charge = Math.min(Math.max(0, amount || remainingBefore), remainingBefore);
816
+ const remainingAfter = Math.max(0, remainingBefore - charge);
817
+ if (remainingAfter > 0) {
818
+ // Partial payment — keep the cart open, queue the rest for the next tender.
819
+ MOCK_CART.remainingBalance = remainingAfter;
820
+ MOCK_CART.amountToBeCharged = remainingAfter;
821
+ mockPublishEvent("cart", "partial-payment-applied", { charged: charge, remaining: remainingAfter });
822
+ return null;
823
+ }
824
+ // Fully paid — create the completed order (this also resets the cart).
825
+ const orderTotal = MOCK_CART.total;
826
+ const order = createOrderFromCart(paymentType, orderTotal, processor);
827
+ mockPublishEvent("payments", "payment-done", { order });
828
+ return order;
829
+ };
@@ -0,0 +1 @@
1
+ export { preorderNoDepositFragment } from "./preorder-no-deposit";
@@ -0,0 +1 @@
1
+ export { preorderNoDepositFragment } from "./preorder-no-deposit";
@@ -0,0 +1,26 @@
1
+ import type { CFStateConfigFragment } from "../common-types/state-fragment";
2
+ /**
3
+ * Pre-order fragment — no deposit required.
4
+ *
5
+ * Mirrors preorder-with-deposit but removes the cross-axis rule that gates
6
+ * `on_hold` on payment state. An order can be placed on hold while still
7
+ * `unpaid` — payment is collected later (pay-at-pickup, BOPIS, COD, etc.).
8
+ *
9
+ * State flow:
10
+ *
11
+ * unpaid|on_hold → (cashier collects payment) → paid|on_hold
12
+ * ↓
13
+ * (progress fulfillment)
14
+ * ↓
15
+ * paid|in_progress
16
+ *
17
+ * Key difference from preorder-with-deposit:
18
+ * - No cross-axis rule blocking `on_hold` when unpaid. The cashier can
19
+ * confirm the pre-order without collecting a deposit first.
20
+ * - `unpaid|on_hold` is whitelisted as a valid first-save state pair.
21
+ * - `in_progress` still requires at least a partial payment (you must pay
22
+ * before the merchant starts fulfilling).
23
+ *
24
+ * Prefix all IDs with your extension id before merging to avoid collisions.
25
+ */
26
+ export declare const preorderNoDepositFragment: CFStateConfigFragment;
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Pre-order fragment — no deposit required.
3
+ *
4
+ * Mirrors preorder-with-deposit but removes the cross-axis rule that gates
5
+ * `on_hold` on payment state. An order can be placed on hold while still
6
+ * `unpaid` — payment is collected later (pay-at-pickup, BOPIS, COD, etc.).
7
+ *
8
+ * State flow:
9
+ *
10
+ * unpaid|on_hold → (cashier collects payment) → paid|on_hold
11
+ * ↓
12
+ * (progress fulfillment)
13
+ * ↓
14
+ * paid|in_progress
15
+ *
16
+ * Key difference from preorder-with-deposit:
17
+ * - No cross-axis rule blocking `on_hold` when unpaid. The cashier can
18
+ * confirm the pre-order without collecting a deposit first.
19
+ * - `unpaid|on_hold` is whitelisted as a valid first-save state pair.
20
+ * - `in_progress` still requires at least a partial payment (you must pay
21
+ * before the merchant starts fulfilling).
22
+ *
23
+ * Prefix all IDs with your extension id before merging to avoid collisions.
24
+ */
25
+ export const preorderNoDepositFragment = {
26
+ paymentPaths: [
27
+ {
28
+ from: "unpaid",
29
+ to: "partially_paid",
30
+ conditionSetId: "require-payment-recorded"
31
+ },
32
+ {
33
+ from: "unpaid",
34
+ to: "paid",
35
+ conditionSetId: "require-full-payment"
36
+ },
37
+ {
38
+ from: "partially_paid",
39
+ to: "paid",
40
+ conditionSetId: "require-full-payment"
41
+ }
42
+ ],
43
+ fulfillmentPaths: [
44
+ {
45
+ from: "draft",
46
+ to: "on_hold",
47
+ conditionSetId: "preorder-no-deposit-require-items"
48
+ },
49
+ {
50
+ from: "on_hold",
51
+ to: "cancelled",
52
+ conditionSetId: "preorder-no-deposit-cancel-before-progress"
53
+ }
54
+ ],
55
+ transitionConditions: [
56
+ {
57
+ id: "preorder-no-deposit-require-items",
58
+ label: "Require at least one item to place pre-order",
59
+ groups: [
60
+ {
61
+ conditions: [
62
+ {
63
+ field: "computed.itemCount",
64
+ operator: "gte",
65
+ value: 1
66
+ }
67
+ ]
68
+ }
69
+ ]
70
+ },
71
+ {
72
+ id: "preorder-no-deposit-cancel-before-progress",
73
+ label: "Can only cancel pre-order before fulfillment begins",
74
+ groups: [
75
+ {
76
+ conditions: [
77
+ {
78
+ field: "computed.fulfilledItemCount",
79
+ operator: "eq",
80
+ value: 0
81
+ }
82
+ ]
83
+ }
84
+ ]
85
+ },
86
+ {
87
+ id: "require-payment-recorded",
88
+ label: "Require at least one payment before marking partially paid",
89
+ groups: [
90
+ {
91
+ conditions: [
92
+ {
93
+ field: "computed.totalPaid",
94
+ operator: "gt",
95
+ value: 0
96
+ }
97
+ ]
98
+ }
99
+ ]
100
+ },
101
+ {
102
+ id: "require-full-payment",
103
+ label: "Require full payment before marking as paid",
104
+ groups: [
105
+ {
106
+ conditions: [
107
+ {
108
+ field: "computed.totalPaid",
109
+ operator: "gte",
110
+ value: 1
111
+ },
112
+ {
113
+ field: "computed.balance",
114
+ operator: "lte",
115
+ value: 0
116
+ }
117
+ ]
118
+ }
119
+ ]
120
+ }
121
+ ],
122
+ crossAxisRules: [
123
+ {
124
+ id: "preorder-no-deposit-require-payment-before-confirm",
125
+ label: "Require payment before starting fulfillment",
126
+ description: "Fulfillment cannot move to in_progress unless at least a partial payment has been made",
127
+ enabled: true,
128
+ trigger: {
129
+ axis: "fulfillment",
130
+ to: ["in_progress"]
131
+ },
132
+ requires: {
133
+ axis: "payment",
134
+ states: ["partially_paid", "paid"]
135
+ }
136
+ }
137
+ ],
138
+ validInitialStates: [
139
+ { payment: "unpaid", fulfillment: "on_hold" },
140
+ { payment: "partially_paid", fulfillment: "on_hold" },
141
+ { payment: "paid", fulfillment: "on_hold" }
142
+ ],
143
+ displayStateMap: [
144
+ {
145
+ paymentState: ["unpaid"],
146
+ fulfillmentState: ["on_hold"],
147
+ label: "Pre-Order",
148
+ color: "#6366f1",
149
+ icon: "clock"
150
+ },
151
+ {
152
+ paymentState: ["partially_paid"],
153
+ fulfillmentState: ["on_hold"],
154
+ label: "Pre-Order (Deposit Received)",
155
+ color: "#f59e0b",
156
+ icon: "clock"
157
+ },
158
+ {
159
+ paymentState: ["paid"],
160
+ fulfillmentState: ["on_hold"],
161
+ label: "Pre-Order (Fully Paid)",
162
+ color: "#22c55e",
163
+ icon: "check-circle"
164
+ }
165
+ ]
166
+ };