@final-commerce/command-frame 0.8.0-staging.2 → 0.9.0-staging.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/CommonTypes.d.ts +25 -1
- package/dist/actions/add-product-fee/mock.d.ts +1 -1
- package/dist/actions/add-product-fee/mock.js +15 -9
- package/dist/actions/add-product-to-cart/mock.d.ts +23 -0
- package/dist/actions/add-product-to-cart/mock.js +300 -1
- package/dist/actions/add-product-to-cart/types.d.ts +27 -1
- package/dist/actions/get-composite-availability/action.d.ts +6 -0
- package/dist/actions/get-composite-availability/action.js +8 -0
- package/dist/actions/get-composite-availability/mock.d.ts +2 -0
- package/dist/actions/get-composite-availability/mock.js +45 -0
- package/dist/actions/get-composite-availability/types.d.ts +29 -0
- package/dist/actions/get-composite-availability/types.js +1 -0
- package/dist/actions/get-composite-price/action.d.ts +6 -0
- package/dist/actions/get-composite-price/action.js +8 -0
- package/dist/actions/get-composite-price/mock.d.ts +2 -0
- package/dist/actions/get-composite-price/mock.js +37 -0
- package/dist/actions/get-composite-price/types.d.ts +31 -0
- package/dist/actions/get-composite-price/types.js +1 -0
- package/dist/actions/get-current-cart/mock.d.ts +1 -1
- package/dist/actions/get-current-cart/mock.js +13 -3
- package/dist/actions/get-current-cart/types.d.ts +7 -1
- package/dist/actions/get-product-modifier-selections/mock.js +12 -0
- package/dist/actions/get-products/mock.js +7 -3
- package/dist/actions/get-products/types.d.ts +1 -1
- package/dist/actions/set-product-modifier-selections/mock.js +12 -0
- package/dist/demo/database.d.ts +39 -1
- package/dist/demo/database.js +218 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/projects/render/mocks.js +4 -0
- package/dist/projects/render/types.d.ts +3 -1
- package/dist/pubsub/topics/products/catalog-visibility-changed/types.d.ts +17 -0
- package/dist/pubsub/topics/products/catalog-visibility-changed/types.js +1 -0
- package/dist/pubsub/topics/products/composite-changed/types.d.ts +17 -0
- package/dist/pubsub/topics/products/composite-changed/types.js +1 -0
- package/dist/pubsub/topics/products/index.d.ts +2 -2
- package/dist/pubsub/topics/products/index.js +33 -18
- package/dist/pubsub/topics/products/inventory-changed/types.d.ts +18 -0
- package/dist/pubsub/topics/products/inventory-changed/types.js +1 -0
- package/dist/pubsub/topics/products/types.d.ts +16 -10
- package/dist/pubsub/topics/products/types.js +7 -4
- package/package.json +2 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CFCompositePick } from '../../CommonTypes';
|
|
2
|
+
export interface GetCompositePriceParams {
|
|
3
|
+
/** The composite's variant — the one `addProductToCart` takes. */
|
|
4
|
+
variantId: string;
|
|
5
|
+
/** The picks so far, exactly as `addProductToCart({ composite })` would send them. */
|
|
6
|
+
composite: CFCompositePick[];
|
|
7
|
+
/** B41: the date and time a bookable pick is for, as `addProductToCart` takes it; without one a bookable pick is refused. */
|
|
8
|
+
compositeSlot?: {
|
|
9
|
+
startAt: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface GetCompositePriceResponse {
|
|
13
|
+
success: boolean;
|
|
14
|
+
/** Why these picks are refused — the same refusal and text `addProductToCart` would give. */
|
|
15
|
+
reason?: string;
|
|
16
|
+
/**
|
|
17
|
+
* What ONE composite with these picks adds to the cart, minor units: the line price the host would build plus the
|
|
18
|
+
* picked items' modifiers. Before discounts, fees and tax. Show it; do not recompute it. Absent when refused.
|
|
19
|
+
*/
|
|
20
|
+
total?: number;
|
|
21
|
+
/**
|
|
22
|
+
* The parts that still need picks before the composite can be added, and how many ("Pick 2 more"); empty when every
|
|
23
|
+
* required part is filled. Decided by the host — keep Add to cart disabled while this is not empty.
|
|
24
|
+
*/
|
|
25
|
+
missing: {
|
|
26
|
+
partId: string;
|
|
27
|
+
needed: number;
|
|
28
|
+
}[];
|
|
29
|
+
timestamp: string;
|
|
30
|
+
}
|
|
31
|
+
export type GetCompositePrice = (params: GetCompositePriceParams) => Promise<GetCompositePriceResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GetCurrentCart } from
|
|
1
|
+
import { GetCurrentCart } from './types';
|
|
2
2
|
export declare const mockGetCurrentCart: GetCurrentCart;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import { MOCK_CART, safeSerialize } from
|
|
1
|
+
import { MOCK_CART, buildModifierRows, safeSerialize } from '../../demo/database';
|
|
2
|
+
import { extendPrice } from '@final-commerce/common';
|
|
2
3
|
export const mockGetCurrentCart = async () => {
|
|
3
|
-
console.log(
|
|
4
|
+
console.log('[Mock] getCurrentCart called');
|
|
5
|
+
// The mock keeps no discounts or fees per line: a line is its price × quantity plus its modifier rows.
|
|
6
|
+
const lineTotals = Object.fromEntries([
|
|
7
|
+
...MOCK_CART.products.map((line) => [
|
|
8
|
+
line.internalId ?? line.id,
|
|
9
|
+
extendPrice(line.price, line.quantity) + buildModifierRows(line.modifiers, line.quantity).modifiersTotal,
|
|
10
|
+
]),
|
|
11
|
+
...(MOCK_CART.customSales ?? []).map((sale) => [sale.id, extendPrice(sale.price, sale.quantity)]),
|
|
12
|
+
]);
|
|
4
13
|
return {
|
|
5
14
|
success: true,
|
|
6
15
|
cart: safeSerialize(MOCK_CART),
|
|
7
|
-
|
|
16
|
+
lineTotals,
|
|
17
|
+
timestamp: new Date().toISOString(),
|
|
8
18
|
};
|
|
9
19
|
};
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import { CFActiveCart } from
|
|
1
|
+
import { CFActiveCart } from '../../CommonTypes';
|
|
2
2
|
export interface GetCurrentCartResponse {
|
|
3
3
|
success: boolean;
|
|
4
4
|
cart: CFActiveCart;
|
|
5
|
+
/**
|
|
6
|
+
* What each line adds to the cart, minor units, keyed by the line's `internalId` (products, bookings) or `id`
|
|
7
|
+
* (custom sales): price × quantity − its own discounts + its own fees + its modifiers. Before the cart discount
|
|
8
|
+
* and tax; Σ = the cart's subtotal before non-revenue items. Show it; do not recompute it.
|
|
9
|
+
*/
|
|
10
|
+
lineTotals?: Record<string, number>;
|
|
5
11
|
timestamp: string;
|
|
6
12
|
}
|
|
7
13
|
export type GetCurrentCart = () => Promise<GetCurrentCartResponse>;
|
|
@@ -16,6 +16,18 @@ export const mockGetProductModifierSelections = async (params) => {
|
|
|
16
16
|
timestamp: new Date().toISOString(),
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
// Like the host (FT-83): a composite line's modifiers belong to its components.
|
|
20
|
+
if (line.components?.length) {
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
reason: 'The modifiers of a composite line cannot be edited yet: remove the line and add it again with its picks',
|
|
24
|
+
internalId: line.internalId,
|
|
25
|
+
selections: [],
|
|
26
|
+
rows: [],
|
|
27
|
+
modifiersTotal: 0,
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
19
31
|
// The priced rows already sit on the line; extending them by the line quantity is
|
|
20
32
|
// the host's job, not the flow's.
|
|
21
33
|
const { rows, modifiersTotal } = buildModifierRows(line.modifiers, line.quantity);
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { MOCK_PRODUCTS, safeSerialize } from '../../demo/database';
|
|
1
|
+
import { MOCK_PRODUCTS, mockCompositeAtOutlet, mockHiddenProductIds, safeSerialize } from '../../demo/database';
|
|
2
2
|
import { resolveUnit } from '@final-commerce/common';
|
|
3
3
|
export const mockGetProducts = async (params) => {
|
|
4
4
|
console.log('[Mock] getProducts called', params);
|
|
5
|
-
// Simple filter simulation
|
|
6
|
-
|
|
5
|
+
// Simple filter simulation. Like the host: a product hidden at this outlet is left out, and a composite offers only
|
|
6
|
+
// what is sold here.
|
|
7
|
+
const hidden = mockHiddenProductIds();
|
|
8
|
+
let products = MOCK_PRODUCTS.filter((p) => !hidden.has(p._id)).map((p) =>
|
|
9
|
+
// B43: the host never hands a composite modifiers of its own.
|
|
10
|
+
p.composite ? { ...p, modifiers: [], composite: mockCompositeAtOutlet(p.composite, hidden) } : p);
|
|
7
11
|
const query = params?.query || {};
|
|
8
12
|
// Same rule as the real host: a bookable service is not catalogue stock and is left out unless
|
|
9
13
|
// the query names `productType`. Mirrored here on purpose — a mock that hands back services the
|
|
@@ -27,7 +27,7 @@ export interface GetProductsParams {
|
|
|
27
27
|
};
|
|
28
28
|
status?: string;
|
|
29
29
|
/**
|
|
30
|
-
* `simple` | `variable` | `booking`. Naming it at all switches OFF the default exclusion
|
|
30
|
+
* `simple` | `variable` | `booking` | `composite`. Naming it at all switches OFF the default exclusion
|
|
31
31
|
* of bookable services — including `{ $ne: 'booking' }`, which then means what it says.
|
|
32
32
|
*/
|
|
33
33
|
productType?: string | {
|
|
@@ -30,6 +30,18 @@ export const mockSetProductModifierSelections = async (params) => {
|
|
|
30
30
|
timestamp: new Date().toISOString(),
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
// Like the host (FT-83): a composite line's modifiers belong to its components.
|
|
34
|
+
if (line.components?.length) {
|
|
35
|
+
return {
|
|
36
|
+
success: false,
|
|
37
|
+
reason: 'The modifiers of a composite line cannot be edited yet: remove the line and add it again with its picks',
|
|
38
|
+
internalId: line.internalId,
|
|
39
|
+
selections: [],
|
|
40
|
+
rows: [],
|
|
41
|
+
modifiersTotal: 0,
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
33
45
|
// Full replacement — passing [] clears the rows. The line drops the product's resolved
|
|
34
46
|
// stack when it is built, so the menu is re-read from the catalogue to price against.
|
|
35
47
|
// Cart totals are not touched, for the same reason addProductToCart does not move them
|
package/dist/demo/database.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Mock Database for Standalone/Demo Mode
|
|
3
3
|
* Stores mock data that mimics the Render environment
|
|
4
4
|
*/
|
|
5
|
-
import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails, CFSmartGridLayout, CFBooking, CFBookingAvailability, CFBookingResource, CFCartLineModifier, CFProdModifierBreakdown, CFModifierSelection, CFResolvedModifier } from '../CommonTypes';
|
|
5
|
+
import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFComposite, CFCartLineComponent, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails, CFSmartGridLayout, CFBooking, CFBookingAvailability, CFBookingResource, CFBookingSlot, CFCartLineModifier, CFProdModifierBreakdown, CFModifierSelection, CFResolvedModifier } from '../CommonTypes';
|
|
6
6
|
export * from './mocks';
|
|
7
7
|
/** Replace mock catalog / context data in place (same array references mock handlers use). */
|
|
8
8
|
export interface MockDatabaseConfig {
|
|
@@ -19,6 +19,12 @@ export interface MockDatabaseConfig {
|
|
|
19
19
|
bookingResources?: CFBookingResource[];
|
|
20
20
|
/** Windows already taken when the dataset loads, so a calendar does not open empty. */
|
|
21
21
|
bookings?: CFBooking[];
|
|
22
|
+
/** Products hidden at an outlet (the host's `catalog-visibility`, product-level rows). Empty = sold everywhere. */
|
|
23
|
+
catalogVisibility?: MockCatalogVisibility[];
|
|
24
|
+
}
|
|
25
|
+
export interface MockCatalogVisibility {
|
|
26
|
+
productId: string;
|
|
27
|
+
outletId: string;
|
|
22
28
|
}
|
|
23
29
|
export declare const MOCK_COMPANY: CFActiveCompany;
|
|
24
30
|
export declare const MOCK_OUTLET_MAIN: CFActiveOutlet;
|
|
@@ -64,8 +70,40 @@ export declare const MOCK_OUTLETS: import("@final-commerce/common/pos-types").Ac
|
|
|
64
70
|
export declare const MOCK_CUSTOMERS: import("@final-commerce/common/pos-types").ActiveCustomer[];
|
|
65
71
|
export declare const MOCK_CATEGORIES: import("@final-commerce/common/pos-types").Category[];
|
|
66
72
|
export declare const MOCK_PRODUCT_HAIRCUT: CFProduct;
|
|
73
|
+
export declare const MOCK_PRODUCT_PASTE_TRIO: CFProduct;
|
|
67
74
|
export declare const MOCK_PRODUCTS: import("@final-commerce/common/pos-types").FullProduct[];
|
|
68
75
|
export declare const MOCK_ORDERS: import("@final-commerce/common/pos-types").ActiveOrder[];
|
|
76
|
+
/** Nothing hidden by default; `setMockDatabase({ catalogVisibility })` hides products at an outlet. */
|
|
77
|
+
export declare const MOCK_CATALOG_VISIBILITY: MockCatalogVisibility[];
|
|
78
|
+
/**
|
|
79
|
+
* The host's cart stock check for composites (kaching `compositeStockRefusal`), over the demo shelves — a copy: what the
|
|
80
|
+
* cart takes of each component's variant (plain lines and components × their line quantity) against its shelf here.
|
|
81
|
+
* The demo has no pools or units, so it counts per variant; untracked and backordered variants are never short.
|
|
82
|
+
*/
|
|
83
|
+
export declare function mockCompositeStockRefusal(products: {
|
|
84
|
+
variantId: string;
|
|
85
|
+
quantity: number;
|
|
86
|
+
components?: CFCartLineComponent[];
|
|
87
|
+
}[]): string | null;
|
|
88
|
+
/** Product ids hidden at the demo's active outlet. */
|
|
89
|
+
export declare const mockHiddenProductIds: () => Set<string>;
|
|
90
|
+
/**
|
|
91
|
+
* The host's outlet rules for a composite (kaching `resolveComposite`), over the demo's static view — a copy, change both
|
|
92
|
+
* in one step: an item whose product is hidden here is left out, a category item keeps only products sold here (none →
|
|
93
|
+
* `'empty'`), an Optional part with nothing to pick is not offered, a required one with nothing makes it unavailable,
|
|
94
|
+
* and the D36 default and "from" price are read off what is left.
|
|
95
|
+
*/
|
|
96
|
+
/** B41: the seats a bookable demo product has free in the slot starting at `startAt` — as the host reads them. */
|
|
97
|
+
export declare function mockBookableWindow(productId: string, startAt: string): {
|
|
98
|
+
free: number;
|
|
99
|
+
slot: CFBookingSlot | null;
|
|
100
|
+
};
|
|
101
|
+
export declare const mockIsBookable: (productId: string) => boolean;
|
|
102
|
+
export declare function mockCompositeAtOutlet(composite: Omit<CFComposite, 'needsDate'>, hidden?: Set<string>,
|
|
103
|
+
/** B41: the window bookable items are judged in; absent = `by_date`. */
|
|
104
|
+
slot?: {
|
|
105
|
+
startAt: string;
|
|
106
|
+
}): CFComposite;
|
|
69
107
|
export declare const MOCK_PARKED_ORDERS: CFActiveOrder[];
|
|
70
108
|
export declare let MOCK_USER: CFActiveUser;
|
|
71
109
|
export declare let MOCK_STATION: CFActiveStation;
|
package/dist/demo/database.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Stores mock data that mimics the Render environment
|
|
4
4
|
*/
|
|
5
5
|
import { CFProductType, CFUserTypes, CurrencyCode, } from '../CommonTypes';
|
|
6
|
-
import { extendPrice, resolveUnit, toBase } from '@final-commerce/common';
|
|
6
|
+
import { cheapestCompositeItem, cheapestCompositePrice, extendPrice, resolveUnit, toBase, } from '@final-commerce/common';
|
|
7
7
|
import { BookingRatePeriod, BookingResourceKind, BookingType, ReservationStatus } from '@final-commerce/common';
|
|
8
8
|
export * from './mocks';
|
|
9
9
|
// Asset Imports - Using Remote URLs to avoid build complexity with asset copying
|
|
@@ -228,6 +228,7 @@ const createSimpleProduct = (id, name, price, image, categories, description) =>
|
|
|
228
228
|
maxPrice: price,
|
|
229
229
|
status: 'active',
|
|
230
230
|
productType: CFProductType.SIMPLE,
|
|
231
|
+
composite: null,
|
|
231
232
|
taxTable: 'tax_standard',
|
|
232
233
|
description,
|
|
233
234
|
images: [image],
|
|
@@ -263,6 +264,7 @@ const createVariableProduct = (id, name, basePrice, largePrice, image, categorie
|
|
|
263
264
|
maxPrice: largePrice,
|
|
264
265
|
status: 'active',
|
|
265
266
|
productType: CFProductType.VARIABLE,
|
|
267
|
+
composite: null,
|
|
266
268
|
taxTable: 'tax_standard',
|
|
267
269
|
description,
|
|
268
270
|
images: [image],
|
|
@@ -658,7 +660,106 @@ export const MOCK_PRODUCT_HAIRCUT = {
|
|
|
658
660
|
productType: CFProductType.BOOKING,
|
|
659
661
|
bookingRulesId: 'rule_salon_30',
|
|
660
662
|
};
|
|
663
|
+
// A composite (FT-83) as the host serves it: the merchant's price 27.00, items add only their upcharges (B31); each item
|
|
664
|
+
// keeps its own tax (`taxTable` empty). One item points at a deleted variant (unavailable), one is a whole category.
|
|
665
|
+
export const MOCK_PRODUCT_PASTE_TRIO = {
|
|
666
|
+
...createSimpleProduct('prod_paste_trio', 'Paste Trio', 2700, basilAlmondImg, [MOCK_CATEGORY_PASTES], 'Pick a paste and a spicy one.'),
|
|
667
|
+
productType: CFProductType.COMPOSITE,
|
|
668
|
+
taxTable: '',
|
|
669
|
+
// B43: a composite has no modifiers of its own; its items carry theirs.
|
|
670
|
+
modifiers: [],
|
|
671
|
+
composite: {
|
|
672
|
+
available: true,
|
|
673
|
+
basePrice: 2700,
|
|
674
|
+
fromPrice: 2800,
|
|
675
|
+
parts: [
|
|
676
|
+
{
|
|
677
|
+
_id: 'part_paste',
|
|
678
|
+
name: 'Paste',
|
|
679
|
+
required: true,
|
|
680
|
+
min: 1,
|
|
681
|
+
max: 1,
|
|
682
|
+
defaultPick: { itemId: 'item_basil', variantId: 'prod_basil_almond_var_main' },
|
|
683
|
+
items: [
|
|
684
|
+
{
|
|
685
|
+
_id: 'item_basil',
|
|
686
|
+
variantId: 'prod_basil_almond_var_main',
|
|
687
|
+
categoryId: null,
|
|
688
|
+
name: 'Basil Almond Paste',
|
|
689
|
+
extraCharge: 0,
|
|
690
|
+
quantity: 1,
|
|
691
|
+
cost: 0,
|
|
692
|
+
unavailable: null,
|
|
693
|
+
choices: [
|
|
694
|
+
{
|
|
695
|
+
productId: 'prod_basil_almond',
|
|
696
|
+
variantId: 'prod_basil_almond_var_main',
|
|
697
|
+
name: 'Basil Almond Paste',
|
|
698
|
+
attributes: [],
|
|
699
|
+
// The picked product's own modifiers (B28): taxed at its table, sent in the pick.
|
|
700
|
+
modifiers: [
|
|
701
|
+
{
|
|
702
|
+
_id: 'mod_texture',
|
|
703
|
+
name: 'Texture',
|
|
704
|
+
selectionType: 'single',
|
|
705
|
+
required: false,
|
|
706
|
+
sortOrder: 0,
|
|
707
|
+
choices: [
|
|
708
|
+
{ _id: 'choice_smooth', name: 'Smooth', price: 0, sortOrder: 0 },
|
|
709
|
+
{ _id: 'choice_chunky', name: 'Chunky', price: 50, sortOrder: 1 },
|
|
710
|
+
],
|
|
711
|
+
},
|
|
712
|
+
],
|
|
713
|
+
},
|
|
714
|
+
],
|
|
715
|
+
},
|
|
716
|
+
{
|
|
717
|
+
_id: 'item_gone',
|
|
718
|
+
variantId: 'prod_gone_var_main',
|
|
719
|
+
categoryId: null,
|
|
720
|
+
name: '',
|
|
721
|
+
extraCharge: 0,
|
|
722
|
+
quantity: 1,
|
|
723
|
+
cost: 0,
|
|
724
|
+
unavailable: 'deleted',
|
|
725
|
+
choices: [],
|
|
726
|
+
},
|
|
727
|
+
],
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
_id: 'part_spicy',
|
|
731
|
+
name: null,
|
|
732
|
+
required: true,
|
|
733
|
+
min: 1,
|
|
734
|
+
max: 2,
|
|
735
|
+
// "Pick up to 2": no preselected pick (B29 = D36) — the till shows how many are still needed.
|
|
736
|
+
defaultPick: null,
|
|
737
|
+
items: [
|
|
738
|
+
{
|
|
739
|
+
_id: 'item_spicy',
|
|
740
|
+
variantId: null,
|
|
741
|
+
categoryId: MOCK_CATEGORY_SPICY.id,
|
|
742
|
+
name: 'Spicy',
|
|
743
|
+
extraCharge: 100,
|
|
744
|
+
quantity: 1,
|
|
745
|
+
cost: 100,
|
|
746
|
+
unavailable: null,
|
|
747
|
+
choices: [
|
|
748
|
+
{
|
|
749
|
+
productId: 'prod_habanero',
|
|
750
|
+
variantId: 'prod_habanero_var_main',
|
|
751
|
+
name: 'Habanero Paste',
|
|
752
|
+
attributes: [],
|
|
753
|
+
},
|
|
754
|
+
],
|
|
755
|
+
},
|
|
756
|
+
],
|
|
757
|
+
},
|
|
758
|
+
],
|
|
759
|
+
},
|
|
760
|
+
};
|
|
661
761
|
export const MOCK_PRODUCTS = [
|
|
762
|
+
MOCK_PRODUCT_PASTE_TRIO,
|
|
662
763
|
MOCK_PRODUCT_BASIL_ALMOND,
|
|
663
764
|
MOCK_PRODUCT_BEER,
|
|
664
765
|
MOCK_PRODUCT_BEET,
|
|
@@ -676,6 +777,114 @@ export const MOCK_PRODUCTS = [
|
|
|
676
777
|
MOCK_PRODUCT_HAIRCUT,
|
|
677
778
|
];
|
|
678
779
|
export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2, MOCK_ORDER_3, MOCK_ORDER_4];
|
|
780
|
+
/** Nothing hidden by default; `setMockDatabase({ catalogVisibility })` hides products at an outlet. */
|
|
781
|
+
export const MOCK_CATALOG_VISIBILITY = [];
|
|
782
|
+
/**
|
|
783
|
+
* The host's cart stock check for composites (kaching `compositeStockRefusal`), over the demo shelves — a copy: what the
|
|
784
|
+
* cart takes of each component's variant (plain lines and components × their line quantity) against its shelf here.
|
|
785
|
+
* The demo has no pools or units, so it counts per variant; untracked and backordered variants are never short.
|
|
786
|
+
*/
|
|
787
|
+
export function mockCompositeStockRefusal(products) {
|
|
788
|
+
const components = products.flatMap((product) => product.components ?? []);
|
|
789
|
+
const demand = new Map();
|
|
790
|
+
for (const product of products) {
|
|
791
|
+
if (product.components)
|
|
792
|
+
for (const component of product.components)
|
|
793
|
+
demand.set(component.variantId, (demand.get(component.variantId) ?? 0) + component.quantity * product.quantity);
|
|
794
|
+
else
|
|
795
|
+
demand.set(product.variantId, (demand.get(product.variantId) ?? 0) + product.quantity);
|
|
796
|
+
}
|
|
797
|
+
for (const component of components) {
|
|
798
|
+
const variant = MOCK_PRODUCTS.flatMap((product) => product.variants).find((candidate) => candidate._id === component.variantId);
|
|
799
|
+
if (!variant?.manageStock || variant.allowBackorder)
|
|
800
|
+
continue;
|
|
801
|
+
const left = variant.inventory?.find((row) => row.outletId === MOCK_OUTLET.id)?.stock ?? 0;
|
|
802
|
+
if ((demand.get(component.variantId) ?? 0) > left)
|
|
803
|
+
return `${component.name}: only ${left} left`;
|
|
804
|
+
}
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
/** Product ids hidden at the demo's active outlet. */
|
|
808
|
+
export const mockHiddenProductIds = () => new Set(MOCK_CATALOG_VISIBILITY.filter((row) => row.outletId === MOCK_OUTLET.id).map((row) => row.productId));
|
|
809
|
+
/**
|
|
810
|
+
* The host's outlet rules for a composite (kaching `resolveComposite`), over the demo's static view — a copy, change both
|
|
811
|
+
* in one step: an item whose product is hidden here is left out, a category item keeps only products sold here (none →
|
|
812
|
+
* `'empty'`), an Optional part with nothing to pick is not offered, a required one with nothing makes it unavailable,
|
|
813
|
+
* and the D36 default and "from" price are read off what is left.
|
|
814
|
+
*/
|
|
815
|
+
/** B41: the seats a bookable demo product has free in the slot starting at `startAt` — as the host reads them. */
|
|
816
|
+
export function mockBookableWindow(productId, startAt) {
|
|
817
|
+
const at = new Date(startAt);
|
|
818
|
+
const slot = mockBookingAvailability(productId, at, new Date(+at + 86400000)).slots.find((candidate) => +new Date(candidate.startAt) === +at && candidate.canStart) ?? null;
|
|
819
|
+
return { free: slot?.free ?? 0, slot };
|
|
820
|
+
}
|
|
821
|
+
export const mockIsBookable = (productId) => MOCK_PRODUCTS.find((product) => product._id === productId)?.productType === CFProductType.BOOKING;
|
|
822
|
+
export function mockCompositeAtOutlet(composite, hidden = mockHiddenProductIds(),
|
|
823
|
+
/** B41: the window bookable items are judged in; absent = `by_date`. */
|
|
824
|
+
slot) {
|
|
825
|
+
// B41: a bookable item is judged by seats in the window, never by stock; with no window it waits for a date.
|
|
826
|
+
const bookable = (item) => !!item.variantId && item.choices.some((choice) => mockIsBookable(choice.productId));
|
|
827
|
+
const seatsFor = (item) => !slot
|
|
828
|
+
? 'by_date'
|
|
829
|
+
: mockBookableWindow(item.choices[0].productId, slot.startAt).free >= item.quantity
|
|
830
|
+
? null
|
|
831
|
+
: 'fully_booked';
|
|
832
|
+
const offered = (item) => !item.unavailable || item.unavailable === 'by_date';
|
|
833
|
+
// B35: a tracked variant without `quantity` on the demo shelf here (and no backorder) is sold out.
|
|
834
|
+
const soldOut = (variantId, quantity) => {
|
|
835
|
+
const variant = MOCK_PRODUCTS.flatMap((product) => product.variants).find((candidate) => candidate._id === variantId);
|
|
836
|
+
if (!variant?.manageStock || variant.allowBackorder)
|
|
837
|
+
return false;
|
|
838
|
+
return (variant.inventory?.find((row) => row.outletId === MOCK_OUTLET.id)?.stock ?? 0) < quantity;
|
|
839
|
+
};
|
|
840
|
+
// B36e: "N left" on a unit-sold tracked choice — the demo shelf already reads in the variant's own unit.
|
|
841
|
+
const withStockLeft = (choice) => {
|
|
842
|
+
const variant = MOCK_PRODUCTS.flatMap((product) => product.variants).find((candidate) => candidate._id === choice.variantId);
|
|
843
|
+
const onHand = variant?.inventory?.find((row) => row.outletId === MOCK_OUTLET.id)?.stock;
|
|
844
|
+
return variant?.unitId && variant.manageStock && typeof onHand === 'number'
|
|
845
|
+
? { ...choice, stockLeft: onHand }
|
|
846
|
+
: choice;
|
|
847
|
+
};
|
|
848
|
+
const upcharge = (item) => ({
|
|
849
|
+
extraCharge: item.extraCharge,
|
|
850
|
+
quantity: item.quantity,
|
|
851
|
+
available: offered(item),
|
|
852
|
+
});
|
|
853
|
+
const parts = composite.parts
|
|
854
|
+
.map((part) => {
|
|
855
|
+
const items = part.items.flatMap((item) => {
|
|
856
|
+
if (item.variantId) {
|
|
857
|
+
if (item.choices.some((choice) => hidden.has(choice.productId)))
|
|
858
|
+
return [];
|
|
859
|
+
if (!item.unavailable && bookable(item))
|
|
860
|
+
return [{ ...item, unavailable: seatsFor(item) }];
|
|
861
|
+
return item.unavailable || !soldOut(item.variantId, item.quantity)
|
|
862
|
+
? [{ ...item, choices: item.choices.map(withStockLeft) }]
|
|
863
|
+
: [{ ...item, unavailable: 'out_of_stock', choices: [] }];
|
|
864
|
+
}
|
|
865
|
+
const sold = item.choices.filter((choice) => !hidden.has(choice.productId));
|
|
866
|
+
const choices = sold.filter((choice) => !soldOut(choice.variantId, item.quantity));
|
|
867
|
+
const unavailable = item.unavailable ?? (!sold.length ? 'empty' : !choices.length ? 'out_of_stock' : null);
|
|
868
|
+
return [{ ...item, choices: unavailable ? [] : choices.map(withStockLeft), unavailable }];
|
|
869
|
+
});
|
|
870
|
+
const index = part.min === 1 && part.max === 1 ? cheapestCompositeItem(items.map(upcharge)) : undefined;
|
|
871
|
+
const cheapest = index === undefined ? undefined : items[index];
|
|
872
|
+
return {
|
|
873
|
+
...part,
|
|
874
|
+
items,
|
|
875
|
+
defaultPick: cheapest?.variantId ? { itemId: cheapest._id, variantId: cheapest.variantId } : null,
|
|
876
|
+
};
|
|
877
|
+
})
|
|
878
|
+
.filter((part) => part.min > 0 || part.items.some(offered));
|
|
879
|
+
const cheapest = cheapestCompositePrice(parts.map((part) => ({ min: part.min, items: part.items.map(upcharge) })));
|
|
880
|
+
return {
|
|
881
|
+
...composite,
|
|
882
|
+
available: composite.available && parts.every((part) => part.min === 0 || part.items.some(offered)),
|
|
883
|
+
needsDate: parts.some((part) => part.items.some(bookable)),
|
|
884
|
+
fromPrice: composite.basePrice === null || cheapest === undefined ? null : composite.basePrice + cheapest,
|
|
885
|
+
parts,
|
|
886
|
+
};
|
|
887
|
+
}
|
|
679
888
|
export const MOCK_PARKED_ORDERS = [MOCK_PARKED_ORDER_1, MOCK_PARKED_ORDER_2];
|
|
680
889
|
// Compatibility Exports (reassigned by setMockDatabase)
|
|
681
890
|
export let MOCK_USER = MOCK_USERS[0];
|
|
@@ -760,6 +969,9 @@ export function setMockDatabase(config) {
|
|
|
760
969
|
if (config.bookings !== undefined) {
|
|
761
970
|
MOCK_BOOKINGS.splice(0, MOCK_BOOKINGS.length, ...config.bookings);
|
|
762
971
|
}
|
|
972
|
+
if (config.catalogVisibility !== undefined) {
|
|
973
|
+
MOCK_CATALOG_VISIBILITY.splice(0, MOCK_CATALOG_VISIBILITY.length, ...config.catalogVisibility);
|
|
974
|
+
}
|
|
763
975
|
if (MOCK_OUTLETS.length > 0) {
|
|
764
976
|
Object.assign(MOCK_OUTLET_MAIN, MOCK_OUTLETS[0]);
|
|
765
977
|
if (MOCK_OUTLET_MAIN.id === undefined && MOCK_OUTLET_MAIN._id !== undefined) {
|
|
@@ -982,8 +1194,10 @@ const CLOSE_HOUR = 18;
|
|
|
982
1194
|
// Rooms, not people: a resource is whatever is scarce, and a room is the case that
|
|
983
1195
|
// reads the same in every vertical a dataset might describe.
|
|
984
1196
|
export const MOCK_BOOKING_RESOURCES = [
|
|
985
|
-
|
|
986
|
-
|
|
1197
|
+
// Two different photos, from the assets this demo already ships: a screen that picks a
|
|
1198
|
+
// resource by sight has to be fed two that look apart, not one repeated.
|
|
1199
|
+
{ id: 'res_room_1', name: 'Room 1', kind: BookingResourceKind.ROOM, image: beetImg },
|
|
1200
|
+
{ id: 'res_room_2', name: 'Room 2', kind: BookingResourceKind.ROOM, image: roastedTomatoImg },
|
|
987
1201
|
];
|
|
988
1202
|
/**
|
|
989
1203
|
* The clock this mock shop keeps — the same one `getContext` reports. They used to disagree: the
|
|
@@ -1130,6 +1344,7 @@ export const buildModifierRows = (modifiers, lineQuantity) => {
|
|
|
1130
1344
|
amount: extendPrice(modifier.unitPrice * modifier.quantity, quantity),
|
|
1131
1345
|
tax: 0,
|
|
1132
1346
|
...(modifier.taxTableId ? { taxTableId: modifier.taxTableId } : {}),
|
|
1347
|
+
...(modifier.componentIndex !== undefined ? { componentIndex: modifier.componentIndex } : {}),
|
|
1133
1348
|
}));
|
|
1134
1349
|
return { rows, modifiersTotal: rows.reduce((sum, row) => sum + row.amount, 0) };
|
|
1135
1350
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,8 @@ export declare const command: {
|
|
|
29
29
|
readonly addProductNote: import(".").AddProductNote;
|
|
30
30
|
readonly addProductFee: import(".").AddProductFee;
|
|
31
31
|
readonly getProductModifierSelections: import(".").GetProductModifierSelections;
|
|
32
|
+
readonly getCompositePrice: import(".").GetCompositePrice;
|
|
33
|
+
readonly getCompositeAvailability: import(".").GetCompositeAvailability;
|
|
32
34
|
readonly setProductModifierSelections: import(".").SetProductModifierSelections;
|
|
33
35
|
readonly setActiveProductFee: import(".").SetActiveProductFee;
|
|
34
36
|
readonly setActiveProductDiscount: import(".").SetActiveProductDiscount;
|
|
@@ -174,6 +176,8 @@ export type { GetFinalContext, GetFinalContextResponse } from './actions/get-fin
|
|
|
174
176
|
export type { AddProductNote, AddProductNoteParams, AddProductNoteResponse } from './actions/add-product-note/types';
|
|
175
177
|
export type { AddProductFee, AddProductFeeParams, AddProductFeeResponse } from './actions/add-product-fee/types';
|
|
176
178
|
export type { GetProductModifierSelections, GetProductModifierSelectionsParams, GetProductModifierSelectionsResponse, ModifierSelection, ModifierChoiceSelection, } from './actions/get-product-modifier-selections/types';
|
|
179
|
+
export type { GetCompositePrice, GetCompositePriceParams, GetCompositePriceResponse, } from './actions/get-composite-price/types';
|
|
180
|
+
export type { GetCompositeAvailability, GetCompositeAvailabilityParams, GetCompositeAvailabilityResponse, CFCompositeSlot, } from './actions/get-composite-availability/types';
|
|
177
181
|
export type { SetProductModifierSelections, SetProductModifierSelectionsParams, SetProductModifierSelectionsResponse, } from './actions/set-product-modifier-selections/types';
|
|
178
182
|
export type { SetActiveProductFee, SetActiveProductFeeParams, SetActiveProductFeeResponse, } from './actions/set-active-product-fee/types';
|
|
179
183
|
export type { SetActiveProductDiscount, SetActiveProductDiscountParams, SetActiveProductDiscountResponse, } from './actions/set-active-product-discount/types';
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,8 @@ import { updateCartItemQuantity } from './actions/update-cart-item-quantity/acti
|
|
|
28
28
|
import { addProductNote } from './actions/add-product-note/action';
|
|
29
29
|
import { addProductFee } from './actions/add-product-fee/action';
|
|
30
30
|
import { getProductModifierSelections } from './actions/get-product-modifier-selections/action';
|
|
31
|
+
import { getCompositePrice } from './actions/get-composite-price/action';
|
|
32
|
+
import { getCompositeAvailability } from './actions/get-composite-availability/action';
|
|
31
33
|
import { setProductModifierSelections } from './actions/set-product-modifier-selections/action';
|
|
32
34
|
import { setActiveProductFee } from './actions/set-active-product-fee/action';
|
|
33
35
|
import { setActiveProductDiscount } from './actions/set-active-product-discount/action';
|
|
@@ -174,6 +176,8 @@ export const command = {
|
|
|
174
176
|
addProductNote,
|
|
175
177
|
addProductFee,
|
|
176
178
|
getProductModifierSelections,
|
|
179
|
+
getCompositePrice,
|
|
180
|
+
getCompositeAvailability,
|
|
177
181
|
setProductModifierSelections,
|
|
178
182
|
setActiveProductFee,
|
|
179
183
|
setActiveProductDiscount,
|
|
@@ -13,6 +13,8 @@ import { mockRemoveOrderNote } from '../../actions/remove-order-note/mock';
|
|
|
13
13
|
import { mockAddProductDiscount } from '../../actions/add-product-discount/mock';
|
|
14
14
|
import { mockAddProductFee } from '../../actions/add-product-fee/mock';
|
|
15
15
|
import { mockGetProductModifierSelections } from '../../actions/get-product-modifier-selections/mock';
|
|
16
|
+
import { mockGetCompositePrice } from '../../actions/get-composite-price/mock';
|
|
17
|
+
import { mockGetCompositeAvailability } from '../../actions/get-composite-availability/mock';
|
|
16
18
|
import { mockSetProductModifierSelections } from '../../actions/set-product-modifier-selections/mock';
|
|
17
19
|
import { mockRemoveProductDiscount } from '../../actions/remove-product-discount/mock';
|
|
18
20
|
import { mockRemoveProductFee } from '../../actions/remove-product-fee/mock';
|
|
@@ -122,6 +124,8 @@ export const RENDER_MOCKS = {
|
|
|
122
124
|
addProductDiscount: mockAddProductDiscount,
|
|
123
125
|
addProductFee: mockAddProductFee,
|
|
124
126
|
getProductModifierSelections: mockGetProductModifierSelections,
|
|
127
|
+
getCompositePrice: mockGetCompositePrice,
|
|
128
|
+
getCompositeAvailability: mockGetCompositeAvailability,
|
|
125
129
|
setProductModifierSelections: mockSetProductModifierSelections,
|
|
126
130
|
setActiveProductFee: mockSetActiveProductFee,
|
|
127
131
|
setActiveProductDiscount: mockSetActiveProductDiscount,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, GetProductModifierSelections, SetProductModifierSelections, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, VoidOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, RedeemRefund, GetRefundPlan, CheckPermission, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, ApplyTransition, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms, GetBookingResources, GetBookingAvailability, GetBookings, HoldBooking, AddBookingToCart, RemoveBookingFromCart, CancelBooking, CreatePaymentLink, ChargeMoto, GetTimeClockStatus } from '../../index';
|
|
1
|
+
import type { ExampleFunction, GetProducts, AddCustomSale, EditCustomSale, GetCustomers, AssignCustomer, AddCustomer, EditCustomer, GetCategories, GetOrders, GetRefunds, GetTaxTables, AddProductDiscount, AddProductToCart, RemoveProductFromCart, UpdateCartItemQuantity, AddCartDiscount, GetContext, GetFinalContext, AddProductNote, AddProductFee, GetProductModifierSelections, GetCompositePrice, GetCompositeAvailability, SetProductModifierSelections, SetActiveProductFee, SetActiveProductDiscount, GetActiveProduct, SetActiveProduct, AdjustInventory, AddOrderNote, AddCartFee, ClearCart, ParkOrder, ResumeParkedOrder, DeleteParkedOrder, VoidOrder, InitiateRefund, CashPayment, GetCashRoundingAmount, TapToPayPayment, TerminalPayment, ExtensionPayment, RedeemPayment, AddNonRevenueItem, AddCustomerNote, RemoveCustomerNote, RemoveCustomerFromCart, GoToStationHome, OpenCashDrawer, ShowNotification, ShowConfirmation, AuthenticateUser, PartialPayment, SwitchUser, SetRefundStockAction, SelectAllRefundItems, ResetRefundDetails, CalculateRefundTotal, GetRemainingRefundableQuantities, ProcessPartialRefund, RedeemRefund, GetRefundPlan, CheckPermission, GetCurrentCart, Print, SetActiveOrder, GetCustomTables, GetCustomTableData, UpsertCustomTableData, DeleteCustomTableData, GetCustomExtensions, GetCurrentCompanyCustomExtensions, GetCustomExtensionCustomTables, GetCustomTableFields, GetSecretsKeys, GetSecretVal, SetSecretVal, GetUsers, GetRoles, RemoveCartDiscount, GetActiveOrder, GetActiveCustomer, SetActiveCustomer, GetActiveOutlet, GetActiveStation, GetActiveSession, GetActiveUser, SetActiveUser, SetActiveRefund, RemoveProductDiscount, RemoveProductFee, RemoveProductNote, RemoveCartFee, RemoveOrderNote, RemoveCustomSale, RemoveNonRevenueItem, CanTransition, GetAvailableTransitions, ApplyTransition, IntegrationPayment, GetSmartGridLayout, SaveSmartGridLayout, SendEmail, SendSms, GetBookingResources, GetBookingAvailability, GetBookings, HoldBooking, AddBookingToCart, RemoveBookingFromCart, CancelBooking, CreatePaymentLink, ChargeMoto, GetTimeClockStatus } from '../../index';
|
|
2
2
|
export interface RenderProviderActions {
|
|
3
3
|
exampleFunction: ExampleFunction;
|
|
4
4
|
getProducts: GetProducts;
|
|
@@ -29,6 +29,8 @@ export interface RenderProviderActions {
|
|
|
29
29
|
addProductNote: AddProductNote;
|
|
30
30
|
addProductFee: AddProductFee;
|
|
31
31
|
getProductModifierSelections: GetProductModifierSelections;
|
|
32
|
+
getCompositePrice: GetCompositePrice;
|
|
33
|
+
getCompositeAvailability: GetCompositeAvailability;
|
|
32
34
|
setProductModifierSelections: SetProductModifierSelections;
|
|
33
35
|
setActiveProductFee: SetActiveProductFee;
|
|
34
36
|
setActiveProductDiscount: SetActiveProductDiscount;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TopicEvent } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Payload for catalog-visibility-changed: a product was hidden or shown at an outlet. `getProducts` leaves hidden
|
|
4
|
+
* products out and a composite offers only items sold at the till's outlet — debounce, then re-ask `getProducts`.
|
|
5
|
+
*/
|
|
6
|
+
export interface CatalogVisibilityChangedPayload {
|
|
7
|
+
visibility: {
|
|
8
|
+
_id: string;
|
|
9
|
+
productId: string;
|
|
10
|
+
outletId: string;
|
|
11
|
+
isDeleted?: boolean;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Typed event for catalog-visibility-changed
|
|
16
|
+
*/
|
|
17
|
+
export type CatalogVisibilityChangedEvent = TopicEvent<CatalogVisibilityChangedPayload>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TopicEvent } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Payload for composite-changed (FT-83): a part or item of a composite arrived. A save replaces all of a composite's
|
|
4
|
+
* parts and items at once (old rows come as `isDeleted: true`, new ones with new ids), so one save fires this many
|
|
5
|
+
* times — debounce, then re-ask `getProducts`; never patch `product.composite` from the row.
|
|
6
|
+
*/
|
|
7
|
+
export interface CompositeChangedPayload {
|
|
8
|
+
compositeRow: {
|
|
9
|
+
_id: string;
|
|
10
|
+
compositeProductId: string;
|
|
11
|
+
isDeleted?: boolean;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Typed event for composite-changed
|
|
16
|
+
*/
|
|
17
|
+
export type CompositeChangedEvent = TopicEvent<CompositeChangedPayload>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Products Topic Definition
|
|
3
3
|
* Defines the products topic and its available event types
|
|
4
4
|
*/
|
|
5
|
-
import type { TopicDefinition } from
|
|
5
|
+
import type { TopicDefinition } from '../../types';
|
|
6
6
|
export declare const productsTopic: TopicDefinition;
|
|
7
|
-
export * from
|
|
7
|
+
export * from './types';
|