@final-commerce/command-frame 0.1.63 → 0.2.0-beta.6
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 +26 -28
- package/dist/CommonTypes.d.ts +118 -19
- package/dist/actions/add-customer-note/mock.js +27 -18
- package/dist/actions/add-customer-note/types.d.ts +3 -2
- package/dist/actions/add-product/mock.js +11 -5
- package/dist/actions/can-transition/action.d.ts +2 -0
- package/dist/actions/can-transition/action.js +4 -0
- package/dist/actions/can-transition/mock.d.ts +6 -0
- package/dist/actions/can-transition/mock.js +28 -0
- package/dist/actions/can-transition/types.d.ts +11 -0
- package/dist/actions/can-transition/types.js +1 -0
- package/dist/actions/cash-payment/types.d.ts +5 -0
- package/dist/actions/delete-parked-order/types.d.ts +3 -0
- package/dist/actions/edit-product/mock.js +4 -2
- package/dist/actions/extension-payment/types.d.ts +5 -0
- package/dist/actions/get-available-transitions/action.d.ts +2 -0
- package/dist/actions/get-available-transitions/action.js +4 -0
- package/dist/actions/get-available-transitions/mock.d.ts +6 -0
- package/dist/actions/get-available-transitions/mock.js +26 -0
- package/dist/actions/get-available-transitions/types.d.ts +9 -0
- package/dist/actions/get-available-transitions/types.js +1 -0
- package/dist/actions/get-context/mock.js +12 -6
- package/dist/actions/initiate-refund/types.d.ts +3 -0
- package/dist/actions/park-order/types.d.ts +3 -0
- package/dist/actions/partial-payment/types.d.ts +5 -0
- package/dist/actions/print/mock.js +3 -6
- package/dist/actions/print/types.d.ts +1 -7
- package/dist/actions/process-partial-refund/types.d.ts +3 -0
- package/dist/actions/remove-customer-note/mock.js +16 -7
- package/dist/actions/resume-parked-order/types.d.ts +3 -0
- package/dist/actions/tap-to-pay-payment/types.d.ts +5 -0
- package/dist/actions/terminal-payment/types.d.ts +5 -0
- package/dist/actions/vendara-payment/types.d.ts +5 -0
- package/dist/common-types/index.d.ts +1 -0
- package/dist/common-types/index.js +1 -0
- package/dist/common-types/order-state.d.ts +32 -0
- package/dist/common-types/order-state.js +6 -0
- package/dist/common-types/state-fragment.d.ts +77 -0
- package/dist/common-types/state-fragment.js +10 -0
- package/dist/demo/database.js +18 -24
- package/dist/fragments/index.d.ts +1 -0
- package/dist/fragments/index.js +1 -0
- package/dist/fragments/preorder-no-deposit.d.ts +26 -0
- package/dist/fragments/preorder-no-deposit.js +166 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +12 -0
- package/dist/projects/render/mocks.js +5 -1
- package/dist/projects/render/types.d.ts +3 -1
- package/dist/pubsub/topics/attributes/attribute-created/types.d.ts +6 -0
- package/dist/pubsub/topics/attributes/attribute-created/types.js +1 -0
- package/dist/pubsub/topics/attributes/attribute-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/attributes/attribute-updated/types.js +1 -0
- package/dist/pubsub/topics/attributes/index.d.ts +3 -0
- package/dist/pubsub/topics/attributes/index.js +18 -0
- package/dist/pubsub/topics/attributes/types.d.ts +6 -0
- package/dist/pubsub/topics/attributes/types.js +2 -0
- package/dist/pubsub/topics/categories/category-created/types.d.ts +6 -0
- package/dist/pubsub/topics/categories/category-created/types.js +1 -0
- package/dist/pubsub/topics/categories/category-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/categories/category-updated/types.js +1 -0
- package/dist/pubsub/topics/categories/index.d.ts +3 -0
- package/dist/pubsub/topics/categories/index.js +18 -0
- package/dist/pubsub/topics/categories/types.d.ts +6 -0
- package/dist/pubsub/topics/categories/types.js +2 -0
- package/dist/pubsub/topics/index.d.ts +4 -0
- package/dist/pubsub/topics/index.js +4 -0
- package/dist/pubsub/topics/orders/index.js +10 -0
- package/dist/pubsub/topics/orders/state-transition-blocked/types.d.ts +16 -0
- package/dist/pubsub/topics/orders/state-transition-blocked/types.js +1 -0
- package/dist/pubsub/topics/orders/state-transition-completed/types.d.ts +15 -0
- package/dist/pubsub/topics/orders/state-transition-completed/types.js +1 -0
- package/dist/pubsub/topics/orders/types.d.ts +6 -2
- package/dist/pubsub/topics/orders/types.js +2 -0
- package/dist/pubsub/topics/print/print-completed/types.d.ts +1 -1
- package/dist/pubsub/topics/print/print-error/types.d.ts +1 -1
- package/dist/pubsub/topics/print/print-started/types.d.ts +1 -1
- package/dist/pubsub/topics/transactions/index.d.ts +3 -0
- package/dist/pubsub/topics/transactions/index.js +18 -0
- package/dist/pubsub/topics/transactions/transaction-created/types.d.ts +6 -0
- package/dist/pubsub/topics/transactions/transaction-created/types.js +1 -0
- package/dist/pubsub/topics/transactions/transaction-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/transactions/transaction-updated/types.js +1 -0
- package/dist/pubsub/topics/transactions/types.d.ts +6 -0
- package/dist/pubsub/topics/transactions/types.js +2 -0
- package/dist/pubsub/topics/types.d.ts +8 -0
- package/dist/pubsub/topics/users/index.js +10 -0
- package/dist/pubsub/topics/users/types.d.ts +6 -2
- package/dist/pubsub/topics/users/types.js +2 -0
- package/dist/pubsub/topics/users/user-created/types.d.ts +6 -0
- package/dist/pubsub/topics/users/user-created/types.js +1 -0
- package/dist/pubsub/topics/users/user-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/users/user-updated/types.js +1 -0
- package/dist/pubsub/topics/variants/index.d.ts +3 -0
- package/dist/pubsub/topics/variants/index.js +18 -0
- package/dist/pubsub/topics/variants/types.d.ts +6 -0
- package/dist/pubsub/topics/variants/types.js +2 -0
- package/dist/pubsub/topics/variants/variant-created/types.d.ts +6 -0
- package/dist/pubsub/topics/variants/variant-created/types.js +1 -0
- package/dist/pubsub/topics/variants/variant-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/variants/variant-updated/types.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,11 +10,11 @@ Command Frame provides a structured way to build integrations that run inside Fi
|
|
|
10
10
|
|
|
11
11
|
The library provides three main capabilities:
|
|
12
12
|
|
|
13
|
-
| Capability
|
|
14
|
-
|
|
15
|
-
| **Commands**
|
|
16
|
-
| **Pub/Sub**
|
|
17
|
-
| **Hooks**
|
|
13
|
+
| Capability | Purpose | Scope |
|
|
14
|
+
| ------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------- |
|
|
15
|
+
| **Commands** | Call host functions from the iframe (e.g. get products, open cash drawer) | Request/response per call |
|
|
16
|
+
| **Pub/Sub** | Subscribe to real-time events from the host (e.g. cart changes, payments) | Page-scoped (while iframe is mounted) |
|
|
17
|
+
| **Hooks** | Register business-logic callbacks that persist across all pages | Session-scoped (survives page navigation) |
|
|
18
18
|
| **Host → iframe refunds** | Render asks the extension to reverse redeem / gift-card payments before completing a POS refund | Parent `postMessage` + `requestId` (see below) |
|
|
19
19
|
|
|
20
20
|
Domain models (orders, cart, customers, products, and related types) are documented in **[Types reference](./src/types/README.md)**.
|
|
@@ -54,7 +54,7 @@ For building applications that run inside the Render Point of Sale interface.
|
|
|
54
54
|
- **Features:** Order management, Product catalog, Customer management, Payments, Hardware integration (Cash drawer, Printer), Custom tables, Secrets storage.
|
|
55
55
|
|
|
56
56
|
```typescript
|
|
57
|
-
import { RenderClient } from
|
|
57
|
+
import { RenderClient } from "@final-commerce/command-frame";
|
|
58
58
|
|
|
59
59
|
const client = new RenderClient();
|
|
60
60
|
const products = await client.getProducts();
|
|
@@ -68,7 +68,7 @@ For building applications that run inside the Final Commerce Management Dashboar
|
|
|
68
68
|
- **Features:** Context, catalog, entities, custom tables, secrets, and optional host-specific commands (navigation, media, tax, branding, notifications) when the dashboard implements them.
|
|
69
69
|
|
|
70
70
|
```typescript
|
|
71
|
-
import { ManageClient } from
|
|
71
|
+
import { ManageClient } from "@final-commerce/command-frame";
|
|
72
72
|
|
|
73
73
|
const client = new ManageClient();
|
|
74
74
|
const context = await client.getContext();
|
|
@@ -82,14 +82,14 @@ The pub/sub system allows iframe extensions to subscribe to topics and receive r
|
|
|
82
82
|
- **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).
|
|
83
83
|
|
|
84
84
|
```typescript
|
|
85
|
-
import { topics } from
|
|
85
|
+
import { topics } from "@final-commerce/command-frame";
|
|
86
86
|
|
|
87
|
-
const subscriptionId = topics.subscribe(
|
|
88
|
-
console.log(
|
|
87
|
+
const subscriptionId = topics.subscribe("cart", event => {
|
|
88
|
+
console.log("Cart event:", event.type, event.data);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
91
|
// Unsubscribe when done
|
|
92
|
-
topics.unsubscribe(
|
|
92
|
+
topics.unsubscribe("cart", subscriptionId);
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
## Hooks
|
|
@@ -101,17 +101,21 @@ Hooks are **session-scoped** event callbacks that run in the host (Render) conte
|
|
|
101
101
|
- A stable `hookId` is required for deduplication (safe on iframe reload).
|
|
102
102
|
|
|
103
103
|
```typescript
|
|
104
|
-
import { hooks } from
|
|
105
|
-
|
|
106
|
-
hooks.register(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
import { hooks } from "@final-commerce/command-frame";
|
|
105
|
+
|
|
106
|
+
hooks.register(
|
|
107
|
+
"cart",
|
|
108
|
+
async (event, hostCommands) => {
|
|
109
|
+
await hostCommands.upsertCustomTableData({
|
|
110
|
+
tableName: "cart-events-log",
|
|
111
|
+
data: { eventType: event.type, payload: event.data, timestamp: event.timestamp }
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
{ hookId: "my-extension:cart-log" }
|
|
115
|
+
);
|
|
112
116
|
|
|
113
117
|
// Unregister when no longer needed
|
|
114
|
-
hooks.unregister(
|
|
118
|
+
hooks.unregister("my-extension:cart-log");
|
|
115
119
|
```
|
|
116
120
|
|
|
117
121
|
## Host-initiated extension refunds (redeem / gift card)
|
|
@@ -127,18 +131,12 @@ hooks.unregister('my-extension:cart-log');
|
|
|
127
131
|
Exported APIs: `installExtensionRefundListener`, `EXTENSION_REFUND_REQUEST_ACTION`, types **`ExtensionRefundParams`** / **`ExtensionRefundResponse`**.
|
|
128
132
|
|
|
129
133
|
```typescript
|
|
130
|
-
import {
|
|
131
|
-
installExtensionRefundListener,
|
|
132
|
-
type ExtensionRefundParams,
|
|
133
|
-
type ExtensionRefundResponse
|
|
134
|
-
} from '@final-commerce/command-frame';
|
|
134
|
+
import { installExtensionRefundListener, type ExtensionRefundParams, type ExtensionRefundResponse } from "@final-commerce/command-frame";
|
|
135
135
|
|
|
136
136
|
const unsubscribe = installExtensionRefundListener(async (params: ExtensionRefundParams): Promise<ExtensionRefundResponse> => {
|
|
137
137
|
// params.paymentType === "redeem", params.amount in major currency units, params.saleId, params.processor, etc.
|
|
138
138
|
const ok = await myGiftCardProvider.refund(params);
|
|
139
|
-
return ok
|
|
140
|
-
? { success: true, extensionTransactionId: ok.providerRefundId }
|
|
141
|
-
: { success: false, error: 'Refund declined' };
|
|
139
|
+
return ok ? { success: true, extensionTransactionId: ok.providerRefundId } : { success: false, error: "Refund declined" };
|
|
142
140
|
});
|
|
143
141
|
|
|
144
142
|
// on teardown (optional)
|
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -60,8 +60,7 @@ export declare enum CFUserTypes {
|
|
|
60
60
|
CASHIER = "cashier",
|
|
61
61
|
RESELLER = "reseller"
|
|
62
62
|
}
|
|
63
|
-
export
|
|
64
|
-
}
|
|
63
|
+
export type CFActiveEntity = Record<string, unknown>;
|
|
65
64
|
export interface CFDiscount {
|
|
66
65
|
value: number;
|
|
67
66
|
label?: string;
|
|
@@ -97,8 +96,26 @@ export interface CFTax {
|
|
|
97
96
|
amount: number;
|
|
98
97
|
taxTableName: string;
|
|
99
98
|
taxTableId: string;
|
|
99
|
+
/** Whether this tax compounds on top of others. */
|
|
100
|
+
compounding?: boolean;
|
|
101
|
+
/** Application order; lower numbers apply first. */
|
|
102
|
+
priority?: number;
|
|
103
|
+
}
|
|
104
|
+
/** Per-rate tax entry on a cart fee (gst, hst, etc.). Same shape as `CFTax`; declared
|
|
105
|
+
* separately to match the host's distinct `CartFeeTaxEntry` type. */
|
|
106
|
+
export interface CFCartFeeTaxEntry {
|
|
107
|
+
id: string;
|
|
108
|
+
name: string;
|
|
109
|
+
percentage: number;
|
|
110
|
+
amount: number;
|
|
111
|
+
taxTableId: string;
|
|
112
|
+
taxTableName: string;
|
|
113
|
+
compounding?: boolean;
|
|
114
|
+
priority?: number;
|
|
100
115
|
}
|
|
101
116
|
export interface CFInventory {
|
|
117
|
+
/** Warehouse identifier the stock is held at. */
|
|
118
|
+
warehouse: string;
|
|
102
119
|
outletId: string;
|
|
103
120
|
stock?: number | null;
|
|
104
121
|
_id?: string;
|
|
@@ -116,6 +133,29 @@ export interface CFOrderNote {
|
|
|
116
133
|
addedByUser?: string;
|
|
117
134
|
dateCreated?: string;
|
|
118
135
|
}
|
|
136
|
+
export interface CFAttributeOption {
|
|
137
|
+
name: string;
|
|
138
|
+
order?: number;
|
|
139
|
+
}
|
|
140
|
+
export interface CFAttribute {
|
|
141
|
+
_id: string;
|
|
142
|
+
companyId?: string;
|
|
143
|
+
optionName: string;
|
|
144
|
+
sortingOrder: number;
|
|
145
|
+
options: CFAttributeOption[];
|
|
146
|
+
}
|
|
147
|
+
export interface CFTransaction {
|
|
148
|
+
_id: string;
|
|
149
|
+
companyId?: string;
|
|
150
|
+
orderId?: string;
|
|
151
|
+
amount: number;
|
|
152
|
+
currency?: string;
|
|
153
|
+
status?: string;
|
|
154
|
+
paymentMethod?: string;
|
|
155
|
+
createdAt?: string;
|
|
156
|
+
updatedAt?: string;
|
|
157
|
+
[key: string]: unknown;
|
|
158
|
+
}
|
|
119
159
|
export interface CFCategory {
|
|
120
160
|
_id: string;
|
|
121
161
|
companyId: string;
|
|
@@ -132,7 +172,8 @@ export interface CFProductVariant {
|
|
|
132
172
|
barcode?: string;
|
|
133
173
|
costPrice?: number;
|
|
134
174
|
manageStock: boolean;
|
|
135
|
-
|
|
175
|
+
/** External variant identifier — required by host. */
|
|
176
|
+
externalId: string;
|
|
136
177
|
inventory?: CFInventory[];
|
|
137
178
|
allowBackorder?: boolean;
|
|
138
179
|
images?: string[];
|
|
@@ -145,11 +186,15 @@ export interface CFProductVariant {
|
|
|
145
186
|
value: string;
|
|
146
187
|
}[];
|
|
147
188
|
_id: string;
|
|
189
|
+
isDeleted?: boolean;
|
|
190
|
+
currency?: CurrencyCode;
|
|
191
|
+
minorUnits?: number;
|
|
148
192
|
}
|
|
149
193
|
export interface CFProduct {
|
|
150
194
|
_id: string;
|
|
151
195
|
companyId?: string;
|
|
152
|
-
|
|
196
|
+
/** External product identifier — required by host. */
|
|
197
|
+
externalId: string;
|
|
153
198
|
taxTable: string;
|
|
154
199
|
name: string;
|
|
155
200
|
description?: string;
|
|
@@ -169,8 +214,12 @@ export interface CFProduct {
|
|
|
169
214
|
minorUnits: number;
|
|
170
215
|
minPrice?: number;
|
|
171
216
|
maxPrice?: number;
|
|
217
|
+
/** Catalog-level price (rare; usually only on simple products). */
|
|
218
|
+
price?: number;
|
|
172
219
|
status?: string;
|
|
173
220
|
isDeleted?: boolean;
|
|
221
|
+
createdAt?: string;
|
|
222
|
+
updatedAt?: string;
|
|
174
223
|
}
|
|
175
224
|
export interface CFActiveProduct extends CFActiveEntity {
|
|
176
225
|
id: string;
|
|
@@ -196,10 +245,17 @@ export interface CFActiveProduct extends CFActiveEntity {
|
|
|
196
245
|
isUnlimited?: boolean;
|
|
197
246
|
attributes?: string;
|
|
198
247
|
localQuantity?: number;
|
|
248
|
+
/** Mongo-style id when the active product retains the catalog `_id`. */
|
|
249
|
+
_id?: string;
|
|
250
|
+
productType?: CFProductType;
|
|
251
|
+
/** Currency code for the line price. */
|
|
252
|
+
currency?: CurrencyCode;
|
|
253
|
+
/** Number of minor units (decimal places) for the line currency. */
|
|
254
|
+
minorUnits?: number;
|
|
199
255
|
}
|
|
200
256
|
export interface CFCustomer {
|
|
201
257
|
_id: string;
|
|
202
|
-
companyId:
|
|
258
|
+
companyId: string;
|
|
203
259
|
externalId?: string;
|
|
204
260
|
email: string;
|
|
205
261
|
firstName: string;
|
|
@@ -246,6 +302,8 @@ export interface CFCartFeeItem {
|
|
|
246
302
|
taxTableId?: string;
|
|
247
303
|
tax?: number;
|
|
248
304
|
taxName: string;
|
|
305
|
+
/** Per-rate breakdown so summary/refund views can show correct amounts per rate. */
|
|
306
|
+
taxes?: CFCartFeeTaxEntry[];
|
|
249
307
|
}
|
|
250
308
|
export interface CFTipPayment {
|
|
251
309
|
amount: number;
|
|
@@ -269,6 +327,8 @@ export interface CFPaymentMethod {
|
|
|
269
327
|
tip?: CFTipPayment | null;
|
|
270
328
|
cashRounding?: number;
|
|
271
329
|
emv?: string | null;
|
|
330
|
+
/** Processor fee charged on this payment. */
|
|
331
|
+
processorFee?: number | null;
|
|
272
332
|
}
|
|
273
333
|
export interface CFPosDataItem {
|
|
274
334
|
outlet: string;
|
|
@@ -358,8 +418,7 @@ export interface CFRefundedLineItem {
|
|
|
358
418
|
images?: string[];
|
|
359
419
|
fee: CFFeeLineItem;
|
|
360
420
|
}
|
|
361
|
-
export
|
|
362
|
-
}
|
|
421
|
+
export type CFRefundedCustomSale = CFCustomSale;
|
|
363
422
|
export interface CFRefundItem {
|
|
364
423
|
lineItems: CFRefundedLineItem[];
|
|
365
424
|
customSales: CFRefundedCustomSale[];
|
|
@@ -382,6 +441,12 @@ export interface CFOrder {
|
|
|
382
441
|
companyId: string;
|
|
383
442
|
externalId: string | null;
|
|
384
443
|
status: string;
|
|
444
|
+
/** Financial state (state machine). Undefined on legacy orders pre-backfill. */
|
|
445
|
+
paymentState?: string;
|
|
446
|
+
/** Operational state (state machine). Undefined on legacy orders pre-backfill. */
|
|
447
|
+
fulfillmentState?: string;
|
|
448
|
+
/** Computed display label from paymentState + fulfillmentState matrix. */
|
|
449
|
+
displayState?: string;
|
|
385
450
|
customer: Partial<CFActiveCustomer | null>;
|
|
386
451
|
customerNote?: string;
|
|
387
452
|
summary: CFSummary;
|
|
@@ -404,6 +469,10 @@ export interface CFOrder {
|
|
|
404
469
|
refund?: CFRefundItem[];
|
|
405
470
|
balance: number;
|
|
406
471
|
signature?: string | null;
|
|
472
|
+
/** ISO timestamp at which a parked order's stock reservation expires. */
|
|
473
|
+
parkExpiryDate?: string;
|
|
474
|
+
/** Park stock-reduction policy (host-defined string flag). */
|
|
475
|
+
parkReduceStock?: string;
|
|
407
476
|
}
|
|
408
477
|
export interface CFActiveUserRole {
|
|
409
478
|
id?: string;
|
|
@@ -435,7 +504,7 @@ export interface CFActiveUser extends CFActiveEntity {
|
|
|
435
504
|
_id: string;
|
|
436
505
|
}[];
|
|
437
506
|
type?: CFUserTypes;
|
|
438
|
-
companies?:
|
|
507
|
+
companies?: unknown;
|
|
439
508
|
}
|
|
440
509
|
export interface CFActiveOutlet extends CFActiveEntity {
|
|
441
510
|
address: string;
|
|
@@ -465,6 +534,12 @@ export interface CFActiveStation {
|
|
|
465
534
|
createdAt?: string;
|
|
466
535
|
updatedAt?: string;
|
|
467
536
|
stripeTerminalId?: string;
|
|
537
|
+
/** Stripe serial-reader identifier when paired. */
|
|
538
|
+
serialReaderId?: string;
|
|
539
|
+
/** User id of whoever enrolled the station. */
|
|
540
|
+
enrolledBy?: string;
|
|
541
|
+
/** Whether the station is virtual (no physical terminal). */
|
|
542
|
+
isVirtual?: boolean;
|
|
468
543
|
}
|
|
469
544
|
/** Cash register session (station session), aligned with Render `Session`. */
|
|
470
545
|
export interface CFSession {
|
|
@@ -515,8 +590,8 @@ export interface CFActiveCustomSales {
|
|
|
515
590
|
taxTableId?: string;
|
|
516
591
|
quantity: number;
|
|
517
592
|
price: number;
|
|
518
|
-
discount?:
|
|
519
|
-
fee?:
|
|
593
|
+
discount?: Record<string, unknown>;
|
|
594
|
+
fee?: Record<string, unknown>;
|
|
520
595
|
}
|
|
521
596
|
/** Non-revenue cart line (e.g. gift card load) — aligned with Render `NonRevenueItem.externalId` (order line id). */
|
|
522
597
|
export interface CFNonRevenueItem {
|
|
@@ -530,6 +605,8 @@ export interface CFNonRevenueItem {
|
|
|
530
605
|
}
|
|
531
606
|
export interface CFActiveCart extends CFActiveEntity {
|
|
532
607
|
tax?: number;
|
|
608
|
+
/** Per-rate tax breakdown for the cart. Same shape as line item taxes. */
|
|
609
|
+
taxes?: CFTax[];
|
|
533
610
|
total: number;
|
|
534
611
|
subtotal: number;
|
|
535
612
|
discount?: CFDiscount;
|
|
@@ -545,12 +622,28 @@ export interface CFActiveCart extends CFActiveEntity {
|
|
|
545
622
|
cartTotal?: number;
|
|
546
623
|
orderTotal?: number;
|
|
547
624
|
orderId?: string;
|
|
625
|
+
/** Currency code for amounts on this cart. */
|
|
626
|
+
currency?: CurrencyCode;
|
|
627
|
+
/** Number of minor units (decimal places) for the cart's currency. */
|
|
628
|
+
minorUnits?: number;
|
|
629
|
+
}
|
|
630
|
+
/** A parked order. Extends `CFActiveCart` with parking-specific fields. */
|
|
631
|
+
export interface CFActivePark extends CFActiveCart {
|
|
632
|
+
/** Required on parked orders (overrides the optional `orderId` on the parent). */
|
|
633
|
+
orderId: string;
|
|
634
|
+
receiptId: string;
|
|
635
|
+
servedBy: string | {
|
|
636
|
+
_id?: string;
|
|
637
|
+
firstName: string;
|
|
638
|
+
lastName: string;
|
|
639
|
+
} | undefined;
|
|
640
|
+
createdAt: string | number;
|
|
548
641
|
}
|
|
549
642
|
export interface CFActiveCompany extends CFActiveEntity {
|
|
550
643
|
id?: string;
|
|
551
644
|
name?: string;
|
|
552
645
|
logo?: string;
|
|
553
|
-
settings?:
|
|
646
|
+
settings?: Record<string, unknown>;
|
|
554
647
|
}
|
|
555
648
|
export type CFProjectName = "Render" | "Manage";
|
|
556
649
|
export interface CFContextRender {
|
|
@@ -568,10 +661,16 @@ export interface CFContextRender {
|
|
|
568
661
|
buildSourceId: string | null;
|
|
569
662
|
buildIsPremium: boolean;
|
|
570
663
|
isOffline: boolean;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
664
|
+
currency: string | null;
|
|
665
|
+
currencySymbol: string | null;
|
|
666
|
+
currencyPrefix: string | null;
|
|
667
|
+
currencySuffix: string | null;
|
|
668
|
+
thousandSeparator: string | null;
|
|
669
|
+
decimalSeparator: string | null;
|
|
670
|
+
user: Record<string, unknown> | null;
|
|
671
|
+
company: Omit<Record<string, unknown>, "settings"> | null;
|
|
672
|
+
station: Record<string, unknown> | null;
|
|
673
|
+
outlet: Record<string, unknown> | null;
|
|
575
674
|
timestamp: string;
|
|
576
675
|
}
|
|
577
676
|
export interface CFOutletInfo {
|
|
@@ -591,11 +690,11 @@ export interface CFOutletInfo {
|
|
|
591
690
|
country?: string;
|
|
592
691
|
}
|
|
593
692
|
export interface CFContextManage {
|
|
594
|
-
user:
|
|
595
|
-
company:
|
|
596
|
-
menuItem?:
|
|
693
|
+
user: unknown;
|
|
694
|
+
company: unknown;
|
|
695
|
+
menuItem?: unknown;
|
|
597
696
|
extensionId: string;
|
|
598
|
-
outlets?:
|
|
697
|
+
outlets?: unknown[];
|
|
599
698
|
timestamp: string;
|
|
600
699
|
}
|
|
601
700
|
export type CFContext = CFContextRender;
|
|
@@ -1,23 +1,32 @@
|
|
|
1
|
-
import { MOCK_CUSTOMERS } from "../../demo/database";
|
|
2
|
-
|
|
1
|
+
import { MOCK_CUSTOMERS, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
function generateNoteId() {
|
|
3
|
+
return `mock_note_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
|
|
4
|
+
}
|
|
5
|
+
export const mockAddCustomerNote = (params) => {
|
|
3
6
|
console.log("[Mock] addCustomerNote called", params);
|
|
4
|
-
if (params?.
|
|
5
|
-
|
|
6
|
-
if (customer) {
|
|
7
|
-
if (!customer.notes) {
|
|
8
|
-
customer.notes = [];
|
|
9
|
-
}
|
|
10
|
-
customer.notes.push({
|
|
11
|
-
_id: `mock_note_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`,
|
|
12
|
-
message: params.note,
|
|
13
|
-
createdAt: new Date().toISOString()
|
|
14
|
-
});
|
|
15
|
-
}
|
|
7
|
+
if (!params?.note) {
|
|
8
|
+
throw new Error("addCustomerNote: note is required");
|
|
16
9
|
}
|
|
17
|
-
|
|
10
|
+
const target = params.customerId ? MOCK_CUSTOMERS.find(c => c._id === params.customerId) : MOCK_CUSTOMERS[0];
|
|
11
|
+
if (!target) {
|
|
12
|
+
throw new Error("addCustomerNote: no target customer (provide customerId or seed at least one mock customer)");
|
|
13
|
+
}
|
|
14
|
+
const noteId = generateNoteId();
|
|
15
|
+
const note = {
|
|
16
|
+
_id: noteId,
|
|
17
|
+
message: params.note,
|
|
18
|
+
createdAt: new Date().toISOString()
|
|
19
|
+
};
|
|
20
|
+
target.notes = [...(target.notes || []), note];
|
|
21
|
+
mockPublishEvent("customers", "customer-note-added", {
|
|
22
|
+
customer: target,
|
|
23
|
+
note
|
|
24
|
+
});
|
|
25
|
+
return Promise.resolve({
|
|
18
26
|
success: true,
|
|
19
|
-
customerId:
|
|
20
|
-
|
|
27
|
+
customerId: target._id,
|
|
28
|
+
noteId,
|
|
29
|
+
note: params.note,
|
|
21
30
|
timestamp: new Date().toISOString()
|
|
22
|
-
};
|
|
31
|
+
});
|
|
23
32
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export interface AddCustomerNoteParams {
|
|
2
|
-
customerId: string;
|
|
3
2
|
note: string;
|
|
3
|
+
customerId?: string;
|
|
4
4
|
}
|
|
5
5
|
export interface AddCustomerNoteResponse {
|
|
6
6
|
success: boolean;
|
|
7
7
|
customerId: string;
|
|
8
|
+
noteId: string;
|
|
8
9
|
note: string;
|
|
9
10
|
timestamp: string;
|
|
10
11
|
}
|
|
11
|
-
export type AddCustomerNote = (params
|
|
12
|
+
export type AddCustomerNote = (params: AddCustomerNoteParams) => Promise<AddCustomerNoteResponse>;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { CFProductType, CurrencyCode } from "../../CommonTypes";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
2
3
|
export const mockAddProduct = async (params) => {
|
|
3
4
|
console.log("[Mock] addProduct called", params);
|
|
4
5
|
const hasVariants = params.variants && params.variants.length > 0;
|
|
6
|
+
const productId = "mock_product_" + Date.now();
|
|
5
7
|
return {
|
|
6
8
|
product: {
|
|
7
|
-
_id:
|
|
9
|
+
_id: productId,
|
|
10
|
+
externalId: `ext_${productId}`,
|
|
8
11
|
currency: CurrencyCode.USD,
|
|
9
12
|
minorUnits: 2,
|
|
10
13
|
name: params.name,
|
|
@@ -20,16 +23,19 @@ export const mockAddProduct = async (params) => {
|
|
|
20
23
|
maxPrice: params.price || 0,
|
|
21
24
|
variants: hasVariants
|
|
22
25
|
? params.variants.map((v, i) => ({ ...v, _id: `mock_variant_${Date.now()}_${i}` }))
|
|
23
|
-
: [
|
|
26
|
+
: [
|
|
27
|
+
{
|
|
24
28
|
_id: `mock_variant_${Date.now()}_0`,
|
|
29
|
+
externalId: `ext_variant_${Date.now()}_0`,
|
|
25
30
|
sku: params.sku || "",
|
|
26
31
|
price: params.price || 0,
|
|
27
32
|
salePrice: 0,
|
|
28
33
|
isOnSale: false,
|
|
29
34
|
manageStock: params.manageStock || false,
|
|
30
|
-
attributes: []
|
|
31
|
-
}
|
|
35
|
+
attributes: []
|
|
36
|
+
}
|
|
37
|
+
]
|
|
32
38
|
},
|
|
33
|
-
timestamp: new Date().toISOString()
|
|
39
|
+
timestamp: new Date().toISOString()
|
|
34
40
|
};
|
|
35
41
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CanTransitionParams, CanTransitionResponse } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementation: allows all transitions except a few known-invalid ones
|
|
4
|
+
* so the demo app can show both allowed and blocked responses.
|
|
5
|
+
*/
|
|
6
|
+
export declare const canTransitionMock: (params: CanTransitionParams) => Promise<CanTransitionResponse>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock implementation: allows all transitions except a few known-invalid ones
|
|
3
|
+
* so the demo app can show both allowed and blocked responses.
|
|
4
|
+
*/
|
|
5
|
+
export const canTransitionMock = async (params) => {
|
|
6
|
+
const to = params.to;
|
|
7
|
+
if (to.payment === "refunded" && to.fulfillment === "draft") {
|
|
8
|
+
return {
|
|
9
|
+
result: {
|
|
10
|
+
allowed: false,
|
|
11
|
+
blockedBy: "financial_invariant",
|
|
12
|
+
guard: "no-refund-in-draft",
|
|
13
|
+
reason: "Cannot refund an order that is still in draft",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (to.payment === "paid" && to.fulfillment === "cancelled") {
|
|
18
|
+
return {
|
|
19
|
+
result: {
|
|
20
|
+
allowed: false,
|
|
21
|
+
blockedBy: "cross_axis_rule",
|
|
22
|
+
guard: "no-pay-cancelled",
|
|
23
|
+
reason: "Cannot mark a cancelled order as paid",
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { result: { allowed: true } };
|
|
28
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CFStatePair, CFTransitionResult } from "../../common-types/order-state";
|
|
2
|
+
export interface CanTransitionParams {
|
|
3
|
+
/** Order to evaluate. If omitted, evaluates against a new order (from = null). */
|
|
4
|
+
orderId?: string;
|
|
5
|
+
/** Target state pair to transition to. */
|
|
6
|
+
to: CFStatePair;
|
|
7
|
+
}
|
|
8
|
+
export interface CanTransitionResponse {
|
|
9
|
+
result: CFTransitionResult;
|
|
10
|
+
}
|
|
11
|
+
export type CanTransition = (params: CanTransitionParams) => Promise<CanTransitionResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
export interface CashPaymentParams {
|
|
3
4
|
/** If not provided, uses the cart total. */
|
|
4
5
|
amount?: number;
|
|
5
6
|
/** Defaults to false. */
|
|
6
7
|
openChangeCalculator?: boolean;
|
|
8
|
+
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
9
|
+
checkoutFulfillmentTarget?: string;
|
|
7
10
|
}
|
|
8
11
|
export interface CashPaymentResponse {
|
|
9
12
|
success: boolean;
|
|
@@ -12,5 +15,7 @@ export interface CashPaymentResponse {
|
|
|
12
15
|
paymentType: string;
|
|
13
16
|
order: CFOrder | null;
|
|
14
17
|
timestamp: string;
|
|
18
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
19
|
+
transitionResult?: CFTransitionResult;
|
|
15
20
|
}
|
|
16
21
|
export type CashPayment = (params?: CashPaymentParams) => Promise<CashPaymentResponse>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
1
2
|
export interface DeleteParkedOrderParams {
|
|
2
3
|
orderId: string;
|
|
3
4
|
}
|
|
@@ -5,5 +6,7 @@ export interface DeleteParkedOrderResponse {
|
|
|
5
6
|
success: boolean;
|
|
6
7
|
orderId: string;
|
|
7
8
|
timestamp: string;
|
|
9
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
10
|
+
transitionResult?: CFTransitionResult;
|
|
8
11
|
}
|
|
9
12
|
export type DeleteParkedOrder = (params?: DeleteParkedOrderParams) => Promise<DeleteParkedOrderResponse>;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { CFProductType, CurrencyCode } from "../../CommonTypes";
|
|
2
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
2
3
|
export const mockEditProduct = async (params) => {
|
|
3
4
|
console.log("[Mock] editProduct called", params);
|
|
4
5
|
return {
|
|
5
6
|
product: {
|
|
6
7
|
_id: params.productId,
|
|
8
|
+
externalId: `ext_${params.productId}`,
|
|
7
9
|
currency: CurrencyCode.USD,
|
|
8
10
|
minorUnits: 2,
|
|
9
11
|
name: params.changes.name || "Updated Product",
|
|
@@ -14,8 +16,8 @@ export const mockEditProduct = async (params) => {
|
|
|
14
16
|
status: params.changes.status || "active",
|
|
15
17
|
productType: CFProductType.SIMPLE,
|
|
16
18
|
attributes: [],
|
|
17
|
-
variants: []
|
|
19
|
+
variants: []
|
|
18
20
|
},
|
|
19
|
-
timestamp: new Date().toISOString()
|
|
21
|
+
timestamp: new Date().toISOString()
|
|
20
22
|
};
|
|
21
23
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CFOrder } from "../../CommonTypes";
|
|
2
|
+
import type { CFTransitionResult } from "../../common-types/order-state";
|
|
2
3
|
/** Params for extension-initiated payments; host routes by `paymentType`. */
|
|
3
4
|
export interface ExtensionPaymentParams {
|
|
4
5
|
paymentType: string;
|
|
@@ -8,6 +9,8 @@ export interface ExtensionPaymentParams {
|
|
|
8
9
|
referenceId?: string;
|
|
9
10
|
extensionId?: string;
|
|
10
11
|
metadata?: Record<string, unknown>;
|
|
12
|
+
/** Override the fulfillment state after full payment. Render resolves the cascade. */
|
|
13
|
+
checkoutFulfillmentTarget?: string;
|
|
11
14
|
}
|
|
12
15
|
export interface ExtensionPaymentResponse {
|
|
13
16
|
success: boolean;
|
|
@@ -15,5 +18,7 @@ export interface ExtensionPaymentResponse {
|
|
|
15
18
|
paymentType: string;
|
|
16
19
|
order: CFOrder | null;
|
|
17
20
|
timestamp: string;
|
|
21
|
+
/** Present when the state machine blocked or forced the transition. */
|
|
22
|
+
transitionResult?: CFTransitionResult;
|
|
18
23
|
}
|
|
19
24
|
export type ExtensionPayment = (params?: ExtensionPaymentParams) => Promise<ExtensionPaymentResponse>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { GetAvailableTransitionsParams, GetAvailableTransitionsResponse } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Mock implementation: returns a fixed set of plausible transitions
|
|
4
|
+
* so the demo app has data to render.
|
|
5
|
+
*/
|
|
6
|
+
export declare const getAvailableTransitionsMock: (_params: GetAvailableTransitionsParams) => Promise<GetAvailableTransitionsResponse>;
|