@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.
Files changed (76) hide show
  1. package/dist/CommonTypes.d.ts +128 -12
  2. package/dist/actions/add-customer-note/mock.js +27 -18
  3. package/dist/actions/add-customer-note/types.d.ts +3 -2
  4. package/dist/actions/add-product/mock.js +11 -5
  5. package/dist/actions/edit-product/mock.js +4 -2
  6. package/dist/actions/extension-payment/types.d.ts +4 -0
  7. package/dist/actions/get-context/mock.js +12 -6
  8. package/dist/actions/get-products/mock.js +6 -1
  9. package/dist/actions/get-products/types.d.ts +2 -0
  10. package/dist/actions/integration-payment/action.d.ts +5 -0
  11. package/dist/actions/integration-payment/action.js +7 -0
  12. package/dist/actions/integration-payment/mock.d.ts +2 -0
  13. package/dist/actions/integration-payment/mock.js +4 -0
  14. package/dist/actions/integration-payment/types.d.ts +56 -0
  15. package/dist/actions/integration-payment/types.js +1 -0
  16. package/dist/actions/print/mock.js +3 -6
  17. package/dist/actions/print/types.d.ts +1 -7
  18. package/dist/actions/redeem-payment/types.d.ts +9 -5
  19. package/dist/actions/remove-customer-note/mock.js +16 -7
  20. package/dist/demo/database.js +9 -24
  21. package/dist/index.d.ts +13 -1
  22. package/dist/index.js +8 -1
  23. package/dist/projects/render/mocks.js +2 -0
  24. package/dist/projects/render/types.d.ts +2 -1
  25. package/dist/pubsub/topics/attributes/attribute-created/types.d.ts +6 -0
  26. package/dist/pubsub/topics/attributes/attribute-created/types.js +1 -0
  27. package/dist/pubsub/topics/attributes/attribute-updated/types.d.ts +6 -0
  28. package/dist/pubsub/topics/attributes/attribute-updated/types.js +1 -0
  29. package/dist/pubsub/topics/attributes/index.d.ts +3 -0
  30. package/dist/pubsub/topics/attributes/index.js +18 -0
  31. package/dist/pubsub/topics/attributes/types.d.ts +6 -0
  32. package/dist/pubsub/topics/attributes/types.js +2 -0
  33. package/dist/pubsub/topics/categories/category-created/types.d.ts +6 -0
  34. package/dist/pubsub/topics/categories/category-created/types.js +1 -0
  35. package/dist/pubsub/topics/categories/category-updated/types.d.ts +6 -0
  36. package/dist/pubsub/topics/categories/category-updated/types.js +1 -0
  37. package/dist/pubsub/topics/categories/index.d.ts +3 -0
  38. package/dist/pubsub/topics/categories/index.js +18 -0
  39. package/dist/pubsub/topics/categories/types.d.ts +6 -0
  40. package/dist/pubsub/topics/categories/types.js +2 -0
  41. package/dist/pubsub/topics/index.d.ts +4 -0
  42. package/dist/pubsub/topics/index.js +4 -0
  43. package/dist/pubsub/topics/print/print-completed/types.d.ts +1 -1
  44. package/dist/pubsub/topics/print/print-error/types.d.ts +1 -1
  45. package/dist/pubsub/topics/print/print-started/types.d.ts +1 -1
  46. package/dist/pubsub/topics/split-payments/index.d.ts +12 -0
  47. package/dist/pubsub/topics/split-payments/index.js +22 -0
  48. package/dist/pubsub/topics/split-payments/split-payment-updated/types.d.ts +16 -0
  49. package/dist/pubsub/topics/split-payments/split-payment-updated/types.js +1 -0
  50. package/dist/pubsub/topics/split-payments/types.d.ts +10 -0
  51. package/dist/pubsub/topics/split-payments/types.js +5 -0
  52. package/dist/pubsub/topics/transactions/index.d.ts +3 -0
  53. package/dist/pubsub/topics/transactions/index.js +18 -0
  54. package/dist/pubsub/topics/transactions/transaction-created/types.d.ts +6 -0
  55. package/dist/pubsub/topics/transactions/transaction-created/types.js +1 -0
  56. package/dist/pubsub/topics/transactions/transaction-updated/types.d.ts +6 -0
  57. package/dist/pubsub/topics/transactions/transaction-updated/types.js +1 -0
  58. package/dist/pubsub/topics/transactions/types.d.ts +6 -0
  59. package/dist/pubsub/topics/transactions/types.js +2 -0
  60. package/dist/pubsub/topics/types.d.ts +10 -0
  61. package/dist/pubsub/topics/users/index.js +10 -0
  62. package/dist/pubsub/topics/users/types.d.ts +6 -2
  63. package/dist/pubsub/topics/users/types.js +2 -0
  64. package/dist/pubsub/topics/users/user-created/types.d.ts +6 -0
  65. package/dist/pubsub/topics/users/user-created/types.js +1 -0
  66. package/dist/pubsub/topics/users/user-updated/types.d.ts +6 -0
  67. package/dist/pubsub/topics/users/user-updated/types.js +1 -0
  68. package/dist/pubsub/topics/variants/index.d.ts +3 -0
  69. package/dist/pubsub/topics/variants/index.js +18 -0
  70. package/dist/pubsub/topics/variants/types.d.ts +6 -0
  71. package/dist/pubsub/topics/variants/types.js +2 -0
  72. package/dist/pubsub/topics/variants/variant-created/types.d.ts +6 -0
  73. package/dist/pubsub/topics/variants/variant-created/types.js +1 -0
  74. package/dist/pubsub/topics/variants/variant-updated/types.d.ts +6 -0
  75. package/dist/pubsub/topics/variants/variant-updated/types.js +1 -0
  76. package/package.json +4 -4
@@ -60,8 +60,7 @@ export declare enum CFUserTypes {
60
60
  CASHIER = "cashier",
61
61
  RESELLER = "reseller"
62
62
  }
63
- export interface CFActiveEntity {
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
- externalId?: string;
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
- externalId?: string;
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
- user: Record<string, any> | null;
572
- company: Omit<Record<string, any>, 'settings'> | null;
573
- station: Record<string, any> | null;
574
- outlet: Record<string, any> | null;
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: any;
595
- company: any;
596
- menuItem?: any;
710
+ user: unknown;
711
+ company: unknown;
712
+ menuItem?: unknown;
597
713
  extensionId: string;
598
- outlets?: any[];
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
- export const mockAddCustomerNote = async (params) => {
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?.customerId && params.note) {
5
- const customer = MOCK_CUSTOMERS.find(c => c._id === params.customerId);
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
- return {
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: params?.customerId || "",
20
- note: params?.note || "",
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?: AddCustomerNoteParams) => Promise<AddCustomerNoteResponse>;
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: "mock_product_" + Date.now(),
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 = async () => {
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 = async () => {
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(products),
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,5 @@
1
+ /**
2
+ * Integration payment — thin wrapper over {@link extensionPayment} with `paymentType: "integration"`.
3
+ */
4
+ import type { IntegrationPayment } from "./types";
5
+ export declare const integrationPayment: IntegrationPayment;
@@ -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,2 @@
1
+ import type { IntegrationPayment } from "./types";
2
+ export declare const mockIntegrationPayment: IntegrationPayment;
@@ -0,0 +1,4 @@
1
+ import { mockExtensionPayment } from "../extension-payment/mock";
2
+ export const mockIntegrationPayment = async (params) => {
3
+ return mockExtensionPayment({ ...params, paymentType: "integration" });
4
+ };
@@ -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 = async (params) => {
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" | "selector" | "receipt";
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
- /** Redeem (e.g. gift card) — always uses paymentType `"redeem"` on the wire. */
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?: number;
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?: RedeemPaymentParams) => Promise<RedeemPaymentResponse>;
16
+ export type RedeemPayment = (params: RedeemPaymentParams) => Promise<RedeemPaymentResponse>;
@@ -1,13 +1,22 @@
1
- export const mockRemoveCustomerNote = async (params) => {
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
- return {
9
- success: true,
10
- noteId,
11
- timestamp
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
  };