@final-commerce/command-frame 0.1.63 → 0.1.72
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/dist/CommonTypes.d.ts +128 -12
- 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/edit-product/mock.js +4 -2
- package/dist/actions/extension-payment/types.d.ts +4 -0
- package/dist/actions/get-context/mock.js +12 -6
- package/dist/actions/get-products/mock.js +6 -1
- package/dist/actions/get-products/types.d.ts +2 -0
- package/dist/actions/integration-payment/action.d.ts +5 -0
- package/dist/actions/integration-payment/action.js +7 -0
- package/dist/actions/integration-payment/mock.d.ts +2 -0
- package/dist/actions/integration-payment/mock.js +4 -0
- package/dist/actions/integration-payment/types.d.ts +56 -0
- package/dist/actions/integration-payment/types.js +1 -0
- package/dist/actions/print/mock.js +3 -6
- package/dist/actions/print/types.d.ts +1 -7
- package/dist/actions/redeem-payment/types.d.ts +9 -5
- package/dist/actions/remove-customer-note/mock.js +16 -7
- package/dist/demo/database.js +9 -24
- package/dist/index.d.ts +13 -1
- package/dist/index.js +8 -1
- package/dist/projects/render/mocks.js +2 -0
- package/dist/projects/render/types.d.ts +2 -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/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/split-payments/index.d.ts +12 -0
- package/dist/pubsub/topics/split-payments/index.js +22 -0
- package/dist/pubsub/topics/split-payments/split-payment-updated/types.d.ts +16 -0
- package/dist/pubsub/topics/split-payments/split-payment-updated/types.js +1 -0
- package/dist/pubsub/topics/split-payments/types.d.ts +10 -0
- package/dist/pubsub/topics/split-payments/types.js +5 -0
- 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 +10 -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 +4 -4
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,6 +245,13 @@ 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;
|
|
@@ -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,30 @@ 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;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Status of an in-progress payment / split-payment session. Mirrors render's
|
|
335
|
+
* `PaymentStatus` enum (`failed | success | canceled | inProgress`).
|
|
336
|
+
*/
|
|
337
|
+
export type CFPaymentStatus = "failed" | "success" | "canceled" | "inProgress";
|
|
338
|
+
/**
|
|
339
|
+
* In-progress split-payment session state. Mirrors render's `ActiveSplitPayment`.
|
|
340
|
+
* Published over the `split-payments` topic whenever the slice mutates so that
|
|
341
|
+
* builder consumers can render partial-payment progress (e.g. a cart-payments
|
|
342
|
+
* repeater) without owning the underlying Redux state.
|
|
343
|
+
*/
|
|
344
|
+
export interface CFSplitPayment {
|
|
345
|
+
amountRemaining?: number | null;
|
|
346
|
+
amountToBeCharged?: number | null;
|
|
347
|
+
splitNumber?: null | number;
|
|
348
|
+
currentSplit?: number;
|
|
349
|
+
status?: CFPaymentStatus;
|
|
350
|
+
isFixed?: boolean;
|
|
351
|
+
payments?: null | CFPaymentMethod[];
|
|
352
|
+
paidAmount?: number;
|
|
353
|
+
tip?: number | null;
|
|
272
354
|
}
|
|
273
355
|
export interface CFPosDataItem {
|
|
274
356
|
outlet: string;
|
|
@@ -404,6 +486,10 @@ export interface CFOrder {
|
|
|
404
486
|
refund?: CFRefundItem[];
|
|
405
487
|
balance: number;
|
|
406
488
|
signature?: string | null;
|
|
489
|
+
/** ISO timestamp at which a parked order's stock reservation expires. */
|
|
490
|
+
parkExpiryDate?: string;
|
|
491
|
+
/** Park stock-reduction policy (host-defined string flag). */
|
|
492
|
+
parkReduceStock?: string;
|
|
407
493
|
}
|
|
408
494
|
export interface CFActiveUserRole {
|
|
409
495
|
id?: string;
|
|
@@ -465,6 +551,12 @@ export interface CFActiveStation {
|
|
|
465
551
|
createdAt?: string;
|
|
466
552
|
updatedAt?: string;
|
|
467
553
|
stripeTerminalId?: string;
|
|
554
|
+
/** Stripe serial-reader identifier when paired. */
|
|
555
|
+
serialReaderId?: string;
|
|
556
|
+
/** User id of whoever enrolled the station. */
|
|
557
|
+
enrolledBy?: string;
|
|
558
|
+
/** Whether the station is virtual (no physical terminal). */
|
|
559
|
+
isVirtual?: boolean;
|
|
468
560
|
}
|
|
469
561
|
/** Cash register session (station session), aligned with Render `Session`. */
|
|
470
562
|
export interface CFSession {
|
|
@@ -530,6 +622,8 @@ export interface CFNonRevenueItem {
|
|
|
530
622
|
}
|
|
531
623
|
export interface CFActiveCart extends CFActiveEntity {
|
|
532
624
|
tax?: number;
|
|
625
|
+
/** Per-rate tax breakdown for the cart. Same shape as line item taxes. */
|
|
626
|
+
taxes?: CFTax[];
|
|
533
627
|
total: number;
|
|
534
628
|
subtotal: number;
|
|
535
629
|
discount?: CFDiscount;
|
|
@@ -545,6 +639,22 @@ export interface CFActiveCart extends CFActiveEntity {
|
|
|
545
639
|
cartTotal?: number;
|
|
546
640
|
orderTotal?: number;
|
|
547
641
|
orderId?: string;
|
|
642
|
+
/** Currency code for amounts on this cart. */
|
|
643
|
+
currency?: CurrencyCode;
|
|
644
|
+
/** Number of minor units (decimal places) for the cart's currency. */
|
|
645
|
+
minorUnits?: number;
|
|
646
|
+
}
|
|
647
|
+
/** A parked order. Extends `CFActiveCart` with parking-specific fields. */
|
|
648
|
+
export interface CFActivePark extends CFActiveCart {
|
|
649
|
+
/** Required on parked orders (overrides the optional `orderId` on the parent). */
|
|
650
|
+
orderId: string;
|
|
651
|
+
receiptId: string;
|
|
652
|
+
servedBy: string | {
|
|
653
|
+
_id?: string;
|
|
654
|
+
firstName: string;
|
|
655
|
+
lastName: string;
|
|
656
|
+
} | undefined;
|
|
657
|
+
createdAt: string | number;
|
|
548
658
|
}
|
|
549
659
|
export interface CFActiveCompany extends CFActiveEntity {
|
|
550
660
|
id?: string;
|
|
@@ -568,10 +678,16 @@ export interface CFContextRender {
|
|
|
568
678
|
buildSourceId: string | null;
|
|
569
679
|
buildIsPremium: boolean;
|
|
570
680
|
isOffline: boolean;
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
681
|
+
currency: string | null;
|
|
682
|
+
currencySymbol: string | null;
|
|
683
|
+
currencyPrefix: string | null;
|
|
684
|
+
currencySuffix: string | null;
|
|
685
|
+
thousandSeparator: string | null;
|
|
686
|
+
decimalSeparator: string | null;
|
|
687
|
+
user: Record<string, unknown> | null;
|
|
688
|
+
company: Omit<Record<string, unknown>, "settings"> | null;
|
|
689
|
+
station: Record<string, unknown> | null;
|
|
690
|
+
outlet: Record<string, unknown> | null;
|
|
575
691
|
timestamp: string;
|
|
576
692
|
}
|
|
577
693
|
export interface CFOutletInfo {
|
|
@@ -591,11 +707,11 @@ export interface CFOutletInfo {
|
|
|
591
707
|
country?: string;
|
|
592
708
|
}
|
|
593
709
|
export interface CFContextManage {
|
|
594
|
-
user:
|
|
595
|
-
company:
|
|
596
|
-
menuItem?:
|
|
710
|
+
user: unknown;
|
|
711
|
+
company: unknown;
|
|
712
|
+
menuItem?: unknown;
|
|
597
713
|
extensionId: string;
|
|
598
|
-
outlets?:
|
|
714
|
+
outlets?: unknown[];
|
|
599
715
|
timestamp: string;
|
|
600
716
|
}
|
|
601
717
|
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
|
};
|
|
@@ -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
|
};
|
|
@@ -8,6 +8,10 @@ export interface ExtensionPaymentParams {
|
|
|
8
8
|
referenceId?: string;
|
|
9
9
|
extensionId?: string;
|
|
10
10
|
metadata?: Record<string, unknown>;
|
|
11
|
+
/** EMV data when the underlying payment carries one (typed as `IntegrationEmvData` by the integration wrapper). */
|
|
12
|
+
emvData?: unknown;
|
|
13
|
+
/** Processor fee in minor units; recorded on the order's paymentMethod.processorFee. */
|
|
14
|
+
processorFee?: number;
|
|
11
15
|
}
|
|
12
16
|
export interface ExtensionPaymentResponse {
|
|
13
17
|
success: boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MOCK_COMPANY, MOCK_OUTLET, MOCK_STATION, MOCK_USER } from "../../demo/database";
|
|
2
2
|
// Mock for Render context (POS terminal)
|
|
3
|
-
export const mockGetContext =
|
|
3
|
+
export const mockGetContext = () => {
|
|
4
4
|
console.log("[Mock] getContext called (Render)");
|
|
5
|
-
return {
|
|
5
|
+
return Promise.resolve({
|
|
6
6
|
userId: MOCK_USER.id || null,
|
|
7
7
|
companyId: MOCK_COMPANY.id || null,
|
|
8
8
|
companyName: MOCK_COMPANY.name || null,
|
|
@@ -17,17 +17,23 @@ export const mockGetContext = async () => {
|
|
|
17
17
|
buildSourceId: "mock_source_id",
|
|
18
18
|
buildIsPremium: true,
|
|
19
19
|
isOffline: false,
|
|
20
|
+
currency: "USD",
|
|
21
|
+
currencySymbol: "$",
|
|
22
|
+
currencyPrefix: "$",
|
|
23
|
+
currencySuffix: "",
|
|
24
|
+
thousandSeparator: ",",
|
|
25
|
+
decimalSeparator: ".",
|
|
20
26
|
user: null,
|
|
21
27
|
company: null,
|
|
22
28
|
station: null,
|
|
23
29
|
outlet: null,
|
|
24
30
|
timestamp: new Date().toISOString()
|
|
25
|
-
};
|
|
31
|
+
});
|
|
26
32
|
};
|
|
27
33
|
// Mock for Manage context (Hub/BuilderHub)
|
|
28
|
-
export const mockGetContextManage =
|
|
34
|
+
export const mockGetContextManage = () => {
|
|
29
35
|
console.log("[Mock] getContext called (Manage)");
|
|
30
|
-
return {
|
|
36
|
+
return Promise.resolve({
|
|
31
37
|
user: {
|
|
32
38
|
_id: MOCK_USER.id,
|
|
33
39
|
id: MOCK_USER.id,
|
|
@@ -47,5 +53,5 @@ export const mockGetContextManage = async () => {
|
|
|
47
53
|
extensionId: "mock_extension_id",
|
|
48
54
|
outlets: [MOCK_OUTLET],
|
|
49
55
|
timestamp: new Date().toISOString()
|
|
50
|
-
};
|
|
56
|
+
});
|
|
51
57
|
};
|
|
@@ -24,8 +24,13 @@ export const mockGetProducts = async (params) => {
|
|
|
24
24
|
products = products.filter(p => (p.categories || []).includes(containsVal));
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
const total = products.length;
|
|
28
|
+
const offset = params?.offset ?? 0;
|
|
29
|
+
const limit = params?.limit ?? 100;
|
|
30
|
+
const paged = products.slice(offset, offset + limit);
|
|
27
31
|
return {
|
|
28
|
-
products: safeSerialize(
|
|
32
|
+
products: safeSerialize(paged),
|
|
33
|
+
total,
|
|
29
34
|
timestamp: new Date().toISOString()
|
|
30
35
|
};
|
|
31
36
|
};
|
|
@@ -29,6 +29,8 @@ export interface GetProductsParams {
|
|
|
29
29
|
}
|
|
30
30
|
export interface GetProductsResponse {
|
|
31
31
|
products: CFProduct[];
|
|
32
|
+
/** Total number of products matching the query, ignoring offset/limit. Optional — hosts that cannot cheaply compute the total may omit it. */
|
|
33
|
+
total?: number;
|
|
32
34
|
timestamp: string;
|
|
33
35
|
}
|
|
34
36
|
export type GetProducts = (params?: GetProductsParams) => Promise<GetProductsResponse>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration payment — thin wrapper over {@link extensionPayment} with `paymentType: "integration"`.
|
|
3
|
+
*/
|
|
4
|
+
import { extensionPayment } from "../extension-payment/action";
|
|
5
|
+
export const integrationPayment = async (params) => {
|
|
6
|
+
return extensionPayment({ ...params, paymentType: "integration" });
|
|
7
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ExtensionPaymentResponse } from "../extension-payment/types";
|
|
2
|
+
/**
|
|
3
|
+
* Card display fields for an integration payment.
|
|
4
|
+
*
|
|
5
|
+
* Render JSON-serializes this object onto the order's `paymentMethod.emv` field;
|
|
6
|
+
* the transactions list, split-payment refund modal, and receipt mapper parse it
|
|
7
|
+
* back. Field names are translated to the platform's canonical EMV keys ("Brand",
|
|
8
|
+
* "Cardholder Name", "Card Number", etc.) on the host before serialization — your
|
|
9
|
+
* extension passes camelCase, the order's persisted shape is unchanged from the
|
|
10
|
+
* native card flow.
|
|
11
|
+
*
|
|
12
|
+
* All fields are optional; the more you supply, the richer the receipt and the
|
|
13
|
+
* transactions row will be. At minimum, supplying `brand` and `cardNumberLast4`
|
|
14
|
+
* produces the typical "Visa **** **** **** 4242" row.
|
|
15
|
+
*/
|
|
16
|
+
export interface IntegrationEmvData {
|
|
17
|
+
/** Card brand, e.g. "Visa", "MasterCard". → "Brand" */
|
|
18
|
+
brand?: string;
|
|
19
|
+
/** Cardholder name as printed on the card. → "Cardholder Name" */
|
|
20
|
+
cardholderName?: string;
|
|
21
|
+
/** Issuing country (ISO 3166-1 alpha-2), e.g. "US". → "Country" */
|
|
22
|
+
country?: string;
|
|
23
|
+
/** Display expiry, e.g. "12/26". → "Expiry date" */
|
|
24
|
+
expiryDate?: string;
|
|
25
|
+
/** Issuer / bank name. → "Issuer" */
|
|
26
|
+
issuer?: string;
|
|
27
|
+
/** Last 4 digits of the card. Render masks to "**** **** **** XXXX" before display. → "Card Number" */
|
|
28
|
+
cardNumberLast4?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Integration payment (e.g. Stripe-like) — always uses paymentType `"integration"` on the wire.
|
|
32
|
+
* The extension processes the payment with its own provider, then reports the result here so
|
|
33
|
+
* Render can record the transaction + order.
|
|
34
|
+
*
|
|
35
|
+
* Required fields (compile-time enforced by TS, runtime-enforced by the host handler):
|
|
36
|
+
* - `amount` — minor units of the captured amount
|
|
37
|
+
* - `emvData` — typed card display fields; the host maps + JSON-serializes to `paymentMethod.emv`
|
|
38
|
+
* (same persisted shape as the native card flow). Required: if the integration
|
|
39
|
+
* doesn't produce card data, use redeemPayment instead.
|
|
40
|
+
*/
|
|
41
|
+
export interface IntegrationPaymentParams {
|
|
42
|
+
amount: number;
|
|
43
|
+
emvData: IntegrationEmvData;
|
|
44
|
+
/** Human-readable label (e.g. "Visa ****4242"); shown in the transaction list. */
|
|
45
|
+
label?: string;
|
|
46
|
+
/** Identifier of the extension making the call; audit/debug link. */
|
|
47
|
+
extensionId?: string;
|
|
48
|
+
/** Label/name of the integration (e.g. "Stripe", "AMP"). Stored on the order's paymentMethod.processor. */
|
|
49
|
+
processor?: string;
|
|
50
|
+
referenceId?: string;
|
|
51
|
+
metadata?: Record<string, unknown>;
|
|
52
|
+
/** Provider fee in minor units — stored on paymentMethod.processorFee. */
|
|
53
|
+
processorFee?: number;
|
|
54
|
+
}
|
|
55
|
+
export type IntegrationPaymentResponse = ExtensionPaymentResponse;
|
|
56
|
+
export type IntegrationPayment = (params: IntegrationPaymentParams) => Promise<IntegrationPaymentResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const mockPrint =
|
|
1
|
+
export const mockPrint = (params) => {
|
|
2
2
|
console.log("[Mock] print called", params);
|
|
3
3
|
if (!params) {
|
|
4
4
|
throw new Error("Print parameters are required");
|
|
@@ -11,16 +11,13 @@ export const mockPrint = async (params) => {
|
|
|
11
11
|
case "html":
|
|
12
12
|
console.log("[Mock] Would print HTML:", params.data.html?.substring(0, 100) + "...");
|
|
13
13
|
break;
|
|
14
|
-
case "selector":
|
|
15
|
-
console.log("[Mock] Would print element with selector:", params.data.selector);
|
|
16
|
-
break;
|
|
17
14
|
case "receipt":
|
|
18
15
|
console.log("[Mock] Would print receipt for order:", params.data.order);
|
|
19
16
|
break;
|
|
20
17
|
}
|
|
21
|
-
return {
|
|
18
|
+
return Promise.resolve({
|
|
22
19
|
success: true,
|
|
23
20
|
timestamp: new Date().toISOString(),
|
|
24
21
|
type: params.type
|
|
25
|
-
};
|
|
22
|
+
});
|
|
26
23
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CFActiveOrder } from "../../CommonTypes";
|
|
2
|
-
export type PrintType = "image" | "html" | "
|
|
2
|
+
export type PrintType = "image" | "html" | "receipt";
|
|
3
3
|
export type PrintParams = {
|
|
4
4
|
type: "image";
|
|
5
5
|
data: {
|
|
@@ -12,12 +12,6 @@ export type PrintParams = {
|
|
|
12
12
|
html: string;
|
|
13
13
|
};
|
|
14
14
|
options?: PrintOptions;
|
|
15
|
-
} | {
|
|
16
|
-
type: "selector";
|
|
17
|
-
data: {
|
|
18
|
-
selector: string;
|
|
19
|
-
};
|
|
20
|
-
options?: PrintOptions;
|
|
21
15
|
} | {
|
|
22
16
|
type: "receipt";
|
|
23
17
|
data: {
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { ExtensionPaymentResponse } from "../extension-payment/types";
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Redeem (e.g. gift card) — always uses paymentType `"redeem"` on the wire.
|
|
4
|
+
* `amount` is required so the persisted payment never silently falls back to the cart
|
|
5
|
+
* total. The host handler also re-validates this at runtime to catch raw-postMessage callers.
|
|
6
|
+
*/
|
|
3
7
|
export interface RedeemPaymentParams {
|
|
4
|
-
amount
|
|
5
|
-
processor?: string;
|
|
8
|
+
amount: number;
|
|
6
9
|
label?: string;
|
|
7
|
-
referenceId?: string;
|
|
8
10
|
extensionId?: string;
|
|
11
|
+
processor?: string;
|
|
12
|
+
referenceId?: string;
|
|
9
13
|
metadata?: Record<string, unknown>;
|
|
10
14
|
}
|
|
11
15
|
export type RedeemPaymentResponse = ExtensionPaymentResponse;
|
|
12
|
-
export type RedeemPayment = (params
|
|
16
|
+
export type RedeemPayment = (params: RedeemPaymentParams) => Promise<RedeemPaymentResponse>;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
import { MOCK_CUSTOMERS, mockPublishEvent } from "../../demo/database";
|
|
2
|
+
export const mockRemoveCustomerNote = (params) => {
|
|
2
3
|
console.log("[Mock] removeCustomerNote called", params);
|
|
3
4
|
const noteId = params?.noteId ?? "";
|
|
4
5
|
const timestamp = new Date().toISOString();
|
|
5
6
|
if (!noteId) {
|
|
6
|
-
return { success: false, noteId, timestamp };
|
|
7
|
+
return Promise.resolve({ success: false, noteId, timestamp });
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
noteId
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
for (const customer of MOCK_CUSTOMERS) {
|
|
10
|
+
const before = customer.notes?.length ?? 0;
|
|
11
|
+
const removed = (customer.notes || []).find(n => n._id === noteId);
|
|
12
|
+
customer.notes = (customer.notes || []).filter(n => n._id !== noteId);
|
|
13
|
+
if ((customer.notes?.length ?? 0) !== before) {
|
|
14
|
+
mockPublishEvent("customers", "customer-note-deleted", {
|
|
15
|
+
customer,
|
|
16
|
+
note: removed
|
|
17
|
+
});
|
|
18
|
+
return Promise.resolve({ success: true, noteId, timestamp });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return Promise.resolve({ success: false, noteId, timestamp });
|
|
13
22
|
};
|