@final-commerce/command-frame 0.6.2-staging3.1 → 0.7.0-staging.10

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 (83) hide show
  1. package/dist/CommonTypes.d.ts +26 -14
  2. package/dist/actions/add-booking-to-cart/action.d.ts +6 -0
  3. package/dist/actions/add-booking-to-cart/action.js +8 -0
  4. package/dist/actions/add-booking-to-cart/mock.d.ts +2 -0
  5. package/dist/actions/add-booking-to-cart/mock.js +42 -0
  6. package/dist/actions/add-booking-to-cart/types.d.ts +23 -0
  7. package/dist/actions/add-product-to-cart/mock.js +1 -18
  8. package/dist/actions/add-product-to-cart/types.d.ts +0 -10
  9. package/dist/actions/cancel-booking/action.d.ts +6 -0
  10. package/dist/actions/cancel-booking/action.js +8 -0
  11. package/dist/actions/cancel-booking/mock.d.ts +2 -0
  12. package/dist/actions/cancel-booking/mock.js +10 -0
  13. package/dist/actions/cancel-booking/types.d.ts +10 -0
  14. package/dist/actions/get-booking-availability/action.d.ts +6 -0
  15. package/dist/actions/get-booking-availability/action.js +8 -0
  16. package/dist/actions/get-booking-availability/mock.d.ts +2 -0
  17. package/dist/actions/get-booking-availability/mock.js +6 -0
  18. package/dist/actions/get-booking-availability/types.d.ts +18 -0
  19. package/dist/actions/get-booking-resources/action.d.ts +6 -0
  20. package/dist/actions/get-booking-resources/action.js +8 -0
  21. package/dist/actions/get-booking-resources/mock.d.ts +2 -0
  22. package/dist/actions/get-booking-resources/mock.js +7 -0
  23. package/dist/actions/get-booking-resources/types.d.ts +12 -0
  24. package/dist/actions/get-booking-resources/types.js +1 -0
  25. package/dist/actions/get-bookings/action.d.ts +6 -0
  26. package/dist/actions/get-bookings/action.js +8 -0
  27. package/dist/actions/get-bookings/mock.d.ts +2 -0
  28. package/dist/actions/get-bookings/mock.js +20 -0
  29. package/dist/actions/get-bookings/types.d.ts +18 -0
  30. package/dist/actions/get-bookings/types.js +1 -0
  31. package/dist/actions/get-context/mock.js +4 -0
  32. package/dist/actions/get-refund-plan/types.d.ts +5 -2
  33. package/dist/actions/get-remaining-refundable-quantities/mock.js +1 -0
  34. package/dist/actions/get-remaining-refundable-quantities/types.d.ts +8 -0
  35. package/dist/actions/hold-booking/action.d.ts +6 -0
  36. package/dist/actions/hold-booking/action.js +8 -0
  37. package/dist/actions/hold-booking/mock.d.ts +2 -0
  38. package/dist/actions/hold-booking/mock.js +33 -0
  39. package/dist/actions/hold-booking/types.d.ts +24 -0
  40. package/dist/actions/hold-booking/types.js +1 -0
  41. package/dist/actions/process-partial-refund/types.d.ts +2 -2
  42. package/dist/actions/remove-booking-from-cart/action.d.ts +6 -0
  43. package/dist/actions/remove-booking-from-cart/action.js +8 -0
  44. package/dist/actions/remove-booking-from-cart/mock.d.ts +2 -0
  45. package/dist/actions/remove-booking-from-cart/mock.js +26 -0
  46. package/dist/actions/remove-booking-from-cart/types.d.ts +12 -0
  47. package/dist/actions/remove-booking-from-cart/types.js +1 -0
  48. package/dist/demo/database.d.ts +12 -24
  49. package/dist/demo/database.js +121 -62
  50. package/dist/index.d.ts +16 -4
  51. package/dist/index.js +15 -4
  52. package/dist/projects/render/mocks.js +14 -4
  53. package/dist/projects/render/types.d.ts +8 -3
  54. package/dist/pubsub/topics/bookings/booking-created/types.d.ts +6 -0
  55. package/dist/pubsub/topics/bookings/booking-created/types.js +1 -0
  56. package/dist/pubsub/topics/bookings/booking-setup-changed/types.d.ts +15 -0
  57. package/dist/pubsub/topics/bookings/booking-setup-changed/types.js +1 -0
  58. package/dist/pubsub/topics/bookings/booking-updated/types.d.ts +6 -0
  59. package/dist/pubsub/topics/bookings/booking-updated/types.js +1 -0
  60. package/dist/pubsub/topics/bookings/index.d.ts +3 -0
  61. package/dist/pubsub/topics/bookings/index.js +27 -0
  62. package/dist/pubsub/topics/bookings/types.d.ts +8 -0
  63. package/dist/pubsub/topics/bookings/types.js +3 -0
  64. package/dist/pubsub/topics/cart/types.d.ts +2 -4
  65. package/dist/pubsub/topics/cart/types.js +0 -1
  66. package/dist/pubsub/topics/index.d.ts +17 -16
  67. package/dist/pubsub/topics/index.js +17 -16
  68. package/dist/pubsub/topics/types.d.ts +2 -0
  69. package/package.json +2 -2
  70. package/dist/actions/get-product-modifier-selections/action.d.ts +0 -6
  71. package/dist/actions/get-product-modifier-selections/action.js +0 -8
  72. package/dist/actions/get-product-modifier-selections/mock.d.ts +0 -2
  73. package/dist/actions/get-product-modifier-selections/mock.js +0 -30
  74. package/dist/actions/get-product-modifier-selections/types.d.ts +0 -23
  75. package/dist/actions/set-product-modifier-selections/action.d.ts +0 -6
  76. package/dist/actions/set-product-modifier-selections/action.js +0 -8
  77. package/dist/actions/set-product-modifier-selections/mock.d.ts +0 -2
  78. package/dist/actions/set-product-modifier-selections/mock.js +0 -49
  79. package/dist/actions/set-product-modifier-selections/types.d.ts +0 -27
  80. package/dist/pubsub/topics/cart/product-modifiers-updated/types.d.ts +0 -16
  81. /package/dist/actions/{get-product-modifier-selections → add-booking-to-cart}/types.js +0 -0
  82. /package/dist/actions/{set-product-modifier-selections → cancel-booking}/types.js +0 -0
  83. /package/dist/{pubsub/topics/cart/product-modifiers-updated → actions/get-booking-availability}/types.js +0 -0
@@ -0,0 +1,26 @@
1
+ import { MOCK_BOOKINGS, MOCK_CART, mockPublishEvent } from '../../demo/database';
2
+ export const mockRemoveBookingFromCart = async (params) => {
3
+ console.log('[Mock] removeBookingFromCart called', params);
4
+ const reservations = MOCK_CART.reservations ?? [];
5
+ const cartIndex = reservations.findIndex(({ internalId }) => internalId === params.reservationInternalId);
6
+ const [removed] = cartIndex >= 0 ? reservations.splice(cartIndex, 1) : [];
7
+ if (removed) {
8
+ const line = removed.total || removed.price * (removed.quantity ?? 1);
9
+ MOCK_CART.subtotal -= line;
10
+ MOCK_CART.total -= line;
11
+ MOCK_CART.amountToBeCharged = MOCK_CART.total;
12
+ MOCK_CART.remainingBalance = MOCK_CART.total;
13
+ mockPublishEvent('cart', 'reservation-removed', { reservation: removed });
14
+ }
15
+ // The hold has to go back, or the mock is a trap: `addBookingToCart` pushes into the very list
16
+ // availability reads, so add → remove → add the same slot used to refuse forever with "that
17
+ // window has just been taken". The reservation id is `res_<booking.id>`, the link back to the row.
18
+ const bookingId = removed?.bookingId ?? params.reservationInternalId.replace(/^res_/, '');
19
+ const index = MOCK_BOOKINGS.findIndex(({ id }) => id === bookingId);
20
+ const [released] = index >= 0 ? MOCK_BOOKINGS.splice(index, 1) : [];
21
+ return {
22
+ reservationInternalId: params.reservationInternalId,
23
+ booking: released,
24
+ timestamp: new Date().toISOString(),
25
+ };
26
+ };
@@ -0,0 +1,12 @@
1
+ import { CFBooking } from '../../CommonTypes';
2
+ export interface RemoveBookingFromCartParams {
3
+ /** The reservation's own id, as `addBookingToCart` returned it. */
4
+ reservationInternalId: string;
5
+ }
6
+ export interface RemoveBookingFromCartResponse {
7
+ reservationInternalId: string;
8
+ /** The released hold, so the caller can see it is no longer held. */
9
+ booking?: CFBooking;
10
+ timestamp: string;
11
+ }
12
+ export type RemoveBookingFromCart = (params: RemoveBookingFromCartParams) => Promise<RemoveBookingFromCartResponse>;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,7 +2,7 @@
2
2
  * Mock Database for Standalone/Demo Mode
3
3
  * Stores mock data that mimics the Render environment
4
4
  */
5
- import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails, CFSmartGridLayout, CFCartLineModifier, CFProdModifierBreakdown, CFModifierSelection, CFResolvedModifier } from '../CommonTypes';
5
+ import { CFActiveCompany, CFActiveUser, CFActiveStation, CFActiveOutlet, CFActiveOrder, CFCustomer, CFProduct, CFActiveCart, CFCategory, CFActiveProduct, CFSession, CFActiveRefundDetails, CFSmartGridLayout, CFBooking, CFBookingAvailability, CFBookingResource } 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 {
@@ -15,6 +15,10 @@ export interface MockDatabaseConfig {
15
15
  products?: CFProduct[];
16
16
  orders?: CFActiveOrder[];
17
17
  parkedOrders?: CFActiveOrder[];
18
+ /** Who is scarce: the staff, rooms or machines the dataset's services are booked against. */
19
+ bookingResources?: CFBookingResource[];
20
+ /** Windows already taken when the dataset loads, so a calendar does not open empty. */
21
+ bookings?: CFBooking[];
18
22
  }
19
23
  export declare const MOCK_COMPANY: CFActiveCompany;
20
24
  export declare const MOCK_OUTLET_MAIN: CFActiveOutlet;
@@ -59,6 +63,7 @@ export declare const MOCK_STATIONS: import("@final-commerce/common/pos-types").A
59
63
  export declare const MOCK_OUTLETS: import("@final-commerce/common/pos-types").ActiveOutlet[];
60
64
  export declare const MOCK_CUSTOMERS: import("@final-commerce/common/pos-types").ActiveCustomer[];
61
65
  export declare const MOCK_CATEGORIES: import("@final-commerce/common/pos-types").Category[];
66
+ export declare const MOCK_PRODUCT_HAIRCUT: CFProduct;
62
67
  export declare const MOCK_PRODUCTS: import("@final-commerce/common/pos-types").FullProduct[];
63
68
  export declare const MOCK_ORDERS: import("@final-commerce/common/pos-types").ActiveOrder[];
64
69
  export declare const MOCK_PARKED_ORDERS: CFActiveOrder[];
@@ -87,26 +92,9 @@ export declare const createOrderFromCart: (paymentType: string, amount: number,
87
92
  * open with `amountToBeCharged` reset to what's left, and returns null.
88
93
  */
89
94
  export declare const applyMockPayment: (amount: number, paymentType: string, processor?: string) => CFActiveOrder | null;
90
- /**
91
- * Price the cashier's raw modifier answers into the rows a CART line carries (FT-0010).
92
- *
93
- * Here rather than in an action folder because two mocks need it — addProductToCart and
94
- * setProductModifierSelections — and this module is already where the shared mock helpers
95
- * live (`safeSerialize`, `resetMockCart`, `mockPublishEvent`).
96
- *
97
- * Note the two shapes that share the name `modifiers` and are NOT interchangeable:
98
- * `FullProduct.modifiers` is `ResolvedModifier[]` (the menu — question + every choice),
99
- * `ActiveProduct.modifiers` is `CartLineModifier[]` (one row per CHOSEN choice). The mock
100
- * builds a cart line by spreading the product, so the menu must be stripped off the line
101
- * before anything reads it, or every surface renders the catalogue as if it were picked.
102
- *
103
- * Names and unitPrice are snapshotted, as the real host does — a later rename never
104
- * rewrites an open cart. No `total`: a cart row is per line UNIT, and the host extends it.
105
- * Rule validation (required/min/max) is deliberately not mocked; the real host owns it.
106
- */
107
- /** Extend a line's priced modifier rows by the line quantity. Mirrors kaching's `buildProdModifiers`. */
108
- export declare const buildModifierRows: (modifiers: CFCartLineModifier[] | undefined, lineQuantity: number | undefined) => {
109
- rows: CFProdModifierBreakdown[];
110
- modifiersTotal: number;
111
- };
112
- export declare const buildCartLineModifiers: (menu: CFResolvedModifier[] | undefined, selections: CFModifierSelection[] | undefined, productTaxTableId?: string) => CFCartLineModifier[];
95
+ export declare const MOCK_BOOKING_RULES_ID = "rule_salon_30";
96
+ export declare const MOCK_BOOKING_RESOURCES: CFBookingResource[];
97
+ export declare const MOCK_BOOKINGS: CFBooking[];
98
+ /** Live = confirmed, or held and not yet expired. An expired hold occupies nothing. */
99
+ export declare const mockLiveBookings: () => CFBooking[];
100
+ export declare const mockBookingAvailability: (productId: string, from: Date, to: Date, resourceId?: string) => CFBookingAvailability;
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { CFProductType, CFUserTypes, CurrencyCode, } from '../CommonTypes';
6
6
  import { extendPrice, resolveUnit, toBase } from '@final-commerce/common';
7
+ import { BookingRatePeriod, BookingResourceKind, BookingType, ReservationStatus } from '@final-commerce/common';
7
8
  export * from './mocks';
8
9
  // Asset Imports - Using Remote URLs to avoid build complexity with asset copying
9
10
  const ASSETS_BASE_URL = 'https://raw.githubusercontent.com/Final-Commerce/command-frame/refs/heads/main/src/demo/assets';
@@ -649,6 +650,14 @@ export const MOCK_CATEGORIES = [
649
650
  MOCK_CATEGORY_VEGAN,
650
651
  MOCK_CATEGORY_SPICY,
651
652
  ];
653
+ // A service, not a thing on a shelf: no stock, sold as a slot of somebody's time.
654
+ // `bookingRulesId` is what tells a catalogue screen to ask for slots instead of stock.
655
+ export const MOCK_PRODUCT_HAIRCUT = {
656
+ ...createSimpleProduct('prod_haircut', 'Haircut', 4500, '', [MOCK_CATEGORY_SPECIALTY], 'Cut and finish, 30 minutes.'),
657
+ images: [],
658
+ productType: CFProductType.BOOKING,
659
+ bookingRulesId: 'rule_salon_30',
660
+ };
652
661
  export const MOCK_PRODUCTS = [
653
662
  MOCK_PRODUCT_BASIL_ALMOND,
654
663
  MOCK_PRODUCT_BEER,
@@ -664,6 +673,7 @@ export const MOCK_PRODUCTS = [
664
673
  MOCK_PRODUCT_CHILI_GARLIC,
665
674
  MOCK_PRODUCT_HABANERO,
666
675
  MOCK_PRODUCT_BLACK_GARLIC,
676
+ MOCK_PRODUCT_HAIRCUT,
667
677
  ];
668
678
  export const MOCK_ORDERS = [MOCK_ORDER_1, MOCK_ORDER_2, MOCK_ORDER_3, MOCK_ORDER_4];
669
679
  export const MOCK_PARKED_ORDERS = [MOCK_PARKED_ORDER_1, MOCK_PARKED_ORDER_2];
@@ -678,6 +688,7 @@ export let MOCK_CART = {
678
688
  remainingBalance: 0,
679
689
  products: [],
680
690
  customSales: [],
691
+ reservations: [],
681
692
  nonRevenueItems: [],
682
693
  customer: null,
683
694
  };
@@ -698,6 +709,7 @@ export const resetMockCart = () => {
698
709
  remainingBalance: 0,
699
710
  products: [],
700
711
  customSales: [],
712
+ reservations: [],
701
713
  nonRevenueItems: [],
702
714
  customer: null,
703
715
  };
@@ -742,6 +754,12 @@ export function setMockDatabase(config) {
742
754
  if (config.parkedOrders !== undefined) {
743
755
  MOCK_PARKED_ORDERS.splice(0, MOCK_PARKED_ORDERS.length, ...config.parkedOrders);
744
756
  }
757
+ if (config.bookingResources !== undefined) {
758
+ MOCK_BOOKING_RESOURCES.splice(0, MOCK_BOOKING_RESOURCES.length, ...config.bookingResources);
759
+ }
760
+ if (config.bookings !== undefined) {
761
+ MOCK_BOOKINGS.splice(0, MOCK_BOOKINGS.length, ...config.bookings);
762
+ }
745
763
  if (MOCK_OUTLETS.length > 0) {
746
764
  Object.assign(MOCK_OUTLET_MAIN, MOCK_OUTLETS[0]);
747
765
  if (MOCK_OUTLET_MAIN.id === undefined && MOCK_OUTLET_MAIN._id !== undefined) {
@@ -878,6 +896,30 @@ export const createOrderFromCart = (paymentType, amount, processor = 'cash') =>
878
896
  billing: MOCK_CART.customer?.billing || null,
879
897
  shipping: MOCK_CART.customer?.shipping || null,
880
898
  lineItems,
899
+ // A paid booking is a sale: it belongs on the order (and thus the receipt),
900
+ // in its own array rather than among the line items, and CONFIRMED — payment
901
+ // is what turns a held window into a kept appointment.
902
+ reservations: (MOCK_CART.reservations ?? []).map((reservation) => ({
903
+ internalId: reservation.internalId,
904
+ bookingId: reservation.bookingId,
905
+ productId: reservation.productId,
906
+ variantId: reservation.variantId,
907
+ resourceId: reservation.resourceId,
908
+ name: reservation.name,
909
+ resourceName: reservation.resourceName,
910
+ price: reservation.price,
911
+ quantity: reservation.quantity,
912
+ total: reservation.total,
913
+ taxTableId: reservation.taxTableId,
914
+ startAt: reservation.startAt,
915
+ endAt: reservation.endAt,
916
+ bufferEndAt: reservation.bufferEndAt,
917
+ // The mock computes no tax anywhere — line items ship `taxes: []` too.
918
+ taxes: [],
919
+ // Neither `expiresAt` nor a status comes along: a booking's state lives on its own
920
+ // row — which is what `getBookings` reads — and a copy frozen on the order would be
921
+ // wrong from the next moment on.
922
+ })),
881
923
  customSales: [],
882
924
  balance: 0,
883
925
  user: employeeUser,
@@ -914,71 +956,88 @@ export const applyMockPayment = (amount, paymentType, processor = 'cash') => {
914
956
  mockPublishEvent('payments', 'payment-done', { order });
915
957
  return order;
916
958
  };
917
- /**
918
- * Price the cashier's raw modifier answers into the rows a CART line carries (FT-0010).
919
- *
920
- * Here rather than in an action folder because two mocks need it — addProductToCart and
921
- * setProductModifierSelections — and this module is already where the shared mock helpers
922
- * live (`safeSerialize`, `resetMockCart`, `mockPublishEvent`).
923
- *
924
- * Note the two shapes that share the name `modifiers` and are NOT interchangeable:
925
- * `FullProduct.modifiers` is `ResolvedModifier[]` (the menu — question + every choice),
926
- * `ActiveProduct.modifiers` is `CartLineModifier[]` (one row per CHOSEN choice). The mock
927
- * builds a cart line by spreading the product, so the menu must be stripped off the line
928
- * before anything reads it, or every surface renders the catalogue as if it were picked.
929
- *
930
- * Names and unitPrice are snapshotted, as the real host does — a later rename never
931
- * rewrites an open cart. No `total`: a cart row is per line UNIT, and the host extends it.
932
- * Rule validation (required/min/max) is deliberately not mocked; the real host owns it.
933
- */
934
- /** Extend a line's priced modifier rows by the line quantity. Mirrors kaching's `buildProdModifiers`. */
935
- export const buildModifierRows = (modifiers, lineQuantity) => {
936
- const quantity = lineQuantity ?? 1;
937
- const rows = (modifiers ?? []).map((modifier) => ({
938
- modifierId: modifier.modifierId,
939
- modifierName: modifier.modifierName,
940
- choiceId: modifier.choiceId,
941
- choiceName: modifier.choiceName,
942
- label: modifier.label ?? `${modifier.modifierName} - ${modifier.choiceName}`,
943
- unitPrice: modifier.unitPrice,
944
- quantity: modifier.quantity,
945
- // extendPrice, not a raw multiply: a fractional line quantity (1.5 kg) must not
946
- // leave fractional minor units on the row.
947
- amount: extendPrice(modifier.unitPrice * modifier.quantity, quantity),
948
- tax: 0,
949
- ...(modifier.taxTableId ? { taxTableId: modifier.taxTableId } : {}),
950
- ...(modifier.taxRateId ? { taxRateId: modifier.taxRateId } : {})
951
- }));
952
- return { rows, modifiersTotal: rows.reduce((sum, row) => sum + row.amount, 0) };
953
- };
954
- export const buildCartLineModifiers = (menu, selections, productTaxTableId) => {
955
- if (!menu?.length || !selections?.length)
956
- return [];
957
- const byModifier = new Map(menu.map((modifier) => [modifier._id, modifier]));
958
- const rows = [];
959
- for (const selection of selections) {
960
- const modifier = byModifier.get(selection.modifierId);
961
- if (!modifier)
959
+ // ── Booking (FT-0064) ────────────────────────────────────────────────────────────
960
+ // A salon: one service, two people who can perform it, a 30-minute slot with a
961
+ // 5-minute turnaround, open 9–18. Enough to click through a booking screen with no
962
+ // server. Availability here is COMPUTED, exactly as the host computes it — a mock
963
+ // that returned a fixed list of slots would hide the one behaviour that matters:
964
+ // a slot disappears once somebody takes it.
965
+ export const MOCK_BOOKING_RULES_ID = 'rule_salon_30';
966
+ const SLOT_MINUTES = 30;
967
+ const BUFFER_MINUTES = 5;
968
+ const OPEN_HOUR = 9;
969
+ const CLOSE_HOUR = 18;
970
+ // Rooms, not people: a resource is whatever is scarce, and a room is the case that
971
+ // reads the same in every vertical a dataset might describe.
972
+ export const MOCK_BOOKING_RESOURCES = [
973
+ { id: 'res_room_1', name: 'Room 1', kind: BookingResourceKind.ROOM },
974
+ { id: 'res_room_2', name: 'Room 2', kind: BookingResourceKind.ROOM },
975
+ ];
976
+ const at = (dayOffset, hour, minute = 0) => {
977
+ const date = new Date();
978
+ date.setDate(date.getDate() + dayOffset);
979
+ date.setHours(hour, minute, 0, 0);
980
+ return date;
981
+ };
982
+ const booking = (id, resourceId, start, status, customerName) => ({
983
+ id,
984
+ productId: MOCK_PRODUCT_HAIRCUT._id,
985
+ resourceId,
986
+ startAt: start.toISOString(),
987
+ endAt: new Date(start.getTime() + SLOT_MINUTES * 60000).toISOString(),
988
+ bufferEndAt: new Date(start.getTime() + (SLOT_MINUTES + BUFFER_MINUTES) * 60000).toISOString(),
989
+ status,
990
+ productName: MOCK_PRODUCT_HAIRCUT.name,
991
+ resourceName: MOCK_BOOKING_RESOURCES.find((resource) => resource.id === resourceId)?.name,
992
+ customerName,
993
+ });
994
+ export const MOCK_BOOKINGS = [
995
+ booking('bk_1', 'res_room_1', at(0, 10), ReservationStatus.CONFIRMED, 'Alex Green'),
996
+ booking('bk_2', 'res_room_2', at(0, 11, 30), ReservationStatus.CONFIRMED, 'Dana White'),
997
+ booking('bk_3', 'res_room_1', at(1, 9, 30), ReservationStatus.CONFIRMED, 'Sam Blue'),
998
+ ];
999
+ /** Live = confirmed, or held and not yet expired. An expired hold occupies nothing. */
1000
+ export const mockLiveBookings = () => MOCK_BOOKINGS.filter(({ status, expiresAt }) => status === ReservationStatus.CONFIRMED ||
1001
+ (status === ReservationStatus.HELD && (!expiresAt || new Date(expiresAt) > new Date())));
1002
+ const takenBy = (resourceId, startAt, bufferEndAt) => mockLiveBookings().some((entry) => entry.resourceId === resourceId && new Date(entry.startAt) < bufferEndAt && new Date(entry.bufferEndAt) > startAt);
1003
+ export const mockBookingAvailability = (productId, from, to, resourceId) => {
1004
+ const serving = resourceId
1005
+ ? MOCK_BOOKING_RESOURCES.filter((resource) => resource.id === resourceId)
1006
+ : MOCK_BOOKING_RESOURCES;
1007
+ const slots = [];
1008
+ const step = (SLOT_MINUTES + BUFFER_MINUTES) * 60000;
1009
+ for (let day = 0; day < 14; day += 1) {
1010
+ const open = at(day, OPEN_HOUR);
1011
+ if (open < from || open > to)
962
1012
  continue;
963
- const byChoice = new Map(modifier.choices.map((choice) => [choice._id, choice]));
964
- for (const picked of selection.choices ?? []) {
965
- const choice = byChoice.get(picked.choiceId);
966
- // `quantity` is units per ONE line unit; 0 means "not chosen" and carries no row.
967
- if (!choice || !(picked.quantity > 0))
1013
+ const close = at(day, CLOSE_HOUR);
1014
+ for (let start = open.getTime(); start + SLOT_MINUTES * 60000 <= close.getTime(); start += step) {
1015
+ const startAt = new Date(start);
1016
+ const endAt = new Date(start + SLOT_MINUTES * 60000);
1017
+ const bufferEndAt = new Date(start + (SLOT_MINUTES + BUFFER_MINUTES) * 60000);
1018
+ if (bufferEndAt < new Date())
968
1019
  continue;
969
- rows.push({
970
- modifierId: modifier._id,
971
- modifierName: modifier.name,
972
- choiceId: choice._id,
973
- choiceName: choice.name,
974
- // The cart's display label, like CustomFee.label — "Toppings - Avocado".
975
- label: `${modifier.name} - ${choice.name}`,
976
- unitPrice: choice.price,
977
- quantity: picked.quantity,
978
- // Modifier tax follows the parent product's table, as a fee's does.
979
- ...(productTaxTableId ? { taxTableId: productTaxTableId } : {}),
1020
+ const resources = serving.map((resource) => {
1021
+ const free = takenBy(resource.id, startAt, bufferEndAt) ? 0 : 1;
1022
+ return { resourceId: resource.id, name: resource.name, capacity: 1, booked: 1 - free, free };
1023
+ });
1024
+ slots.push({
1025
+ startAt: startAt.toISOString(),
1026
+ endAt: endAt.toISOString(),
1027
+ bufferEndAt: bufferEndAt.toISOString(),
1028
+ canStart: true,
1029
+ capacity: resources.length,
1030
+ booked: resources.reduce((sum, entry) => sum + entry.booked, 0),
1031
+ free: resources.reduce((sum, entry) => sum + entry.free, 0),
1032
+ resources,
980
1033
  });
981
1034
  }
982
1035
  }
983
- return rows;
1036
+ return {
1037
+ productId,
1038
+ bookingRulesId: MOCK_BOOKING_RULES_ID,
1039
+ bookingType: BookingType.APPOINTMENT,
1040
+ ratePeriod: BookingRatePeriod.SLOT,
1041
+ slots,
1042
+ };
984
1043
  };
package/dist/index.d.ts CHANGED
@@ -2,6 +2,13 @@ export declare const command: {
2
2
  readonly exampleFunction: import(".").ExampleFunction;
3
3
  readonly generateAPIKey: import(".").GenerateAPIKey;
4
4
  readonly getProducts: import(".").GetProducts;
5
+ readonly getBookingResources: import(".").GetBookingResources;
6
+ readonly getBookingAvailability: import(".").GetBookingAvailability;
7
+ readonly getBookings: import(".").GetBookings;
8
+ readonly holdBooking: import(".").HoldBooking;
9
+ readonly addBookingToCart: import(".").AddBookingToCart;
10
+ readonly removeBookingFromCart: import(".").RemoveBookingFromCart;
11
+ readonly cancelBooking: import(".").CancelBooking;
5
12
  readonly addCustomSale: import(".").AddCustomSale;
6
13
  readonly editCustomSale: import(".").EditCustomSale;
7
14
  readonly addNonRevenueItem: import(".").AddNonRevenueItem;
@@ -21,8 +28,6 @@ export declare const command: {
21
28
  readonly getFinalContext: import(".").GetFinalContext;
22
29
  readonly addProductNote: import(".").AddProductNote;
23
30
  readonly addProductFee: import(".").AddProductFee;
24
- readonly getProductModifierSelections: import(".").GetProductModifierSelections;
25
- readonly setProductModifierSelections: import(".").SetProductModifierSelections;
26
31
  readonly setActiveProductFee: import(".").SetActiveProductFee;
27
32
  readonly setActiveProductDiscount: import(".").SetActiveProductDiscount;
28
33
  readonly getActiveProduct: import(".").GetActiveProduct;
@@ -121,6 +126,13 @@ export declare const command: {
121
126
  export type { ExampleFunction, ExampleFunctionParams, ExampleFunctionResponse } from './actions/example-function/types';
122
127
  export type { GenerateAPIKey, GenerateAPIKeyParams, GenerateAPIKeyResponse } from './actions/generate-api-key/types';
123
128
  export type { GetProducts, GetProductsParams, GetProductsResponse } from './actions/get-products/types';
129
+ export type { GetBookingResources, GetBookingResourcesParams, GetBookingResourcesResponse, } from './actions/get-booking-resources/types';
130
+ export type { GetBookingAvailability, GetBookingAvailabilityParams, GetBookingAvailabilityResponse, } from './actions/get-booking-availability/types';
131
+ export type { GetBookings, GetBookingsParams, GetBookingsResponse } from './actions/get-bookings/types';
132
+ export type { HoldBooking, HoldBookingParams, HoldBookingResponse } from './actions/hold-booking/types';
133
+ export type { AddBookingToCart, AddBookingToCartParams, AddBookingToCartResponse, } from './actions/add-booking-to-cart/types';
134
+ export type { RemoveBookingFromCart, RemoveBookingFromCartParams, RemoveBookingFromCartResponse, } from './actions/remove-booking-from-cart/types';
135
+ export type { CancelBooking, CancelBookingParams, CancelBookingResponse } from './actions/cancel-booking/types';
124
136
  export type { AddCustomSale, AddCustomSaleParams, AddCustomSaleResponse } from './actions/add-custom-sale/types';
125
137
  export type { EditCustomSale, EditCustomSaleParams, EditCustomSaleResponse } from './actions/edit-custom-sale/types';
126
138
  export type { AddNonRevenueItem, AddNonRevenueItemParams, AddNonRevenueItemResponse, } from './actions/add-non-revenue-item/types';
@@ -159,8 +171,6 @@ export type { GetContext, GetContextResponse, GetContextResponseManage, GetConte
159
171
  export type { GetFinalContext, GetFinalContextResponse } from './actions/get-final-context/types';
160
172
  export type { AddProductNote, AddProductNoteParams, AddProductNoteResponse } from './actions/add-product-note/types';
161
173
  export type { AddProductFee, AddProductFeeParams, AddProductFeeResponse } from './actions/add-product-fee/types';
162
- export type { GetProductModifierSelections, GetProductModifierSelectionsParams, GetProductModifierSelectionsResponse, ModifierSelection, ModifierChoiceSelection, } from './actions/get-product-modifier-selections/types';
163
- export type { SetProductModifierSelections, SetProductModifierSelectionsParams, SetProductModifierSelectionsResponse, } from './actions/set-product-modifier-selections/types';
164
174
  export type { SetActiveProductFee, SetActiveProductFeeParams, SetActiveProductFeeResponse, } from './actions/set-active-product-fee/types';
165
175
  export type { SetActiveProductDiscount, SetActiveProductDiscountParams, SetActiveProductDiscountResponse, } from './actions/set-active-product-discount/types';
166
176
  export type { GetActiveProduct, GetActiveProductResponse } from './actions/get-active-product/types';
@@ -249,6 +259,7 @@ export { variantsTopic } from './pubsub/topics/variants';
249
259
  export { transactionsTopic } from './pubsub/topics/transactions';
250
260
  export { categoriesTopic } from './pubsub/topics/categories';
251
261
  export { attributesTopic } from './pubsub/topics/attributes';
262
+ export { bookingsTopic } from './pubsub/topics/bookings';
252
263
  export type { CustomerCreatedPayload, CustomerUpdatedPayload, CustomerNoteAddedPayload, CustomerNoteDeletedPayload, CustomerAssignedPayload, CustomerUnassignedPayload, CustomerActiveSetPayload, CustomerActiveGetPayload, CustomerCreatedEvent, CustomerUpdatedEvent, CustomerNoteAddedEvent, CustomerNoteDeletedEvent, CustomerAssignedEvent, CustomerUnassignedEvent, CustomerActiveSetEvent, CustomerActiveGetEvent, CustomersEventType, CustomersEventPayload, } from './pubsub/topics/customers/types';
253
264
  export type { OrderCreatedPayload, OrderUpdatedPayload, OrderVoidedPayload, OrderActiveSetPayload, OrderActiveGetPayload, OrderCreatedEvent, OrderUpdatedEvent, OrderVoidedEvent, OrderActiveSetEvent, OrderActiveGetEvent, OrderStateTransitionCompletedPayload, OrderStateTransitionBlockedPayload, OrderStateTransitionCompletedEvent, OrderStateTransitionBlockedEvent, OrdersEventType, OrdersEventPayload, } from './pubsub/topics/orders/types';
254
265
  export type { RefundCreatedPayload, RefundUpdatedPayload, RefundActiveSetPayload, RefundActiveGetPayload, RefundCreatedEvent, RefundUpdatedEvent, RefundActiveSetEvent, RefundActiveGetEvent, RefundsEventType, RefundsEventPayload, } from './pubsub/topics/refunds/types';
@@ -259,6 +270,7 @@ export type { SessionActiveSetPayload, SessionActiveGetPayload, SessionActiveSet
259
270
  export type { UserActiveSetPayload, UserActiveGetPayload, UserActiveSetEvent, UserActiveGetEvent, UserCreatedPayload, UserCreatedEvent, UserUpdatedPayload, UserUpdatedEvent, UsersEventType, UsersEventPayload, } from './pubsub/topics/users/types';
260
271
  export type { VariantCreatedPayload, VariantCreatedEvent, VariantUpdatedPayload, VariantUpdatedEvent, VariantsEventType, VariantsEventPayload, } from './pubsub/topics/variants/types';
261
272
  export type { TransactionCreatedPayload, TransactionCreatedEvent, TransactionUpdatedPayload, TransactionUpdatedEvent, TransactionsEventType, TransactionsEventPayload, } from './pubsub/topics/transactions/types';
273
+ export type { BookingCreatedPayload, BookingCreatedEvent, BookingUpdatedPayload, BookingUpdatedEvent, BookingSetupChangedPayload, BookingSetupChangedEvent, BookingsEventType, BookingsEventPayload, } from './pubsub/topics/bookings/types';
262
274
  export type { CategoryCreatedPayload, CategoryCreatedEvent, CategoryUpdatedPayload, CategoryUpdatedEvent, CategoriesEventType, CategoriesEventPayload, } from './pubsub/topics/categories/types';
263
275
  export type { AttributeCreatedPayload, AttributeCreatedEvent, AttributeUpdatedPayload, AttributeUpdatedEvent, AttributesEventType, AttributesEventPayload, } from './pubsub/topics/attributes/types';
264
276
  export type { CartCreatedPayload, CartCustomerAssignedPayload, ProductAddedPayload, ProductDeletedPayload, CartDiscountAddedPayload, CartDiscountRemovedPayload, CartFeeAddedPayload, CartFeeRemovedPayload, ProductDiscountAddedPayload, ProductDiscountRemovedPayload, ProductFeeAddedPayload, ProductFeeRemovedPayload, ProductNoteAddedPayload, ProductNoteRemovedPayload, CartCreatedEvent, CartCustomerAssignedEvent, ProductAddedEvent, ProductDeletedEvent, CartDiscountAddedEvent, CartDiscountRemovedEvent, CartFeeAddedEvent, CartFeeRemovedEvent, ProductDiscountAddedEvent, ProductDiscountRemovedEvent, ProductFeeAddedEvent, ProductFeeRemovedEvent, ProductNoteAddedEvent, ProductNoteRemovedEvent, CartEventType, CartEventPayload, } from './pubsub/topics/cart/types';
package/dist/index.js CHANGED
@@ -1,6 +1,13 @@
1
1
  // Import actions from new folder structure
2
2
  import { exampleFunction } from './actions/example-function/action';
3
3
  import { getProducts } from './actions/get-products/action';
4
+ import { getBookingResources } from './actions/get-booking-resources/action';
5
+ import { getBookingAvailability } from './actions/get-booking-availability/action';
6
+ import { getBookings } from './actions/get-bookings/action';
7
+ import { holdBooking } from './actions/hold-booking/action';
8
+ import { addBookingToCart } from './actions/add-booking-to-cart/action';
9
+ import { removeBookingFromCart } from './actions/remove-booking-from-cart/action';
10
+ import { cancelBooking } from './actions/cancel-booking/action';
4
11
  import { addCustomSale } from './actions/add-custom-sale/action';
5
12
  import { editCustomSale } from './actions/edit-custom-sale/action';
6
13
  import { addNonRevenueItem } from './actions/add-non-revenue-item/action';
@@ -20,8 +27,6 @@ import { updateCartItemQuantity } from './actions/update-cart-item-quantity/acti
20
27
  // Product Actions
21
28
  import { addProductNote } from './actions/add-product-note/action';
22
29
  import { addProductFee } from './actions/add-product-fee/action';
23
- import { getProductModifierSelections } from './actions/get-product-modifier-selections/action';
24
- import { setProductModifierSelections } from './actions/set-product-modifier-selections/action';
25
30
  import { setActiveProductFee } from './actions/set-active-product-fee/action';
26
31
  import { setActiveProductDiscount } from './actions/set-active-product-discount/action';
27
32
  import { getActiveProduct } from './actions/get-active-product/action';
@@ -139,6 +144,13 @@ export const command = {
139
144
  exampleFunction,
140
145
  generateAPIKey,
141
146
  getProducts,
147
+ getBookingResources,
148
+ getBookingAvailability,
149
+ getBookings,
150
+ holdBooking,
151
+ addBookingToCart,
152
+ removeBookingFromCart,
153
+ cancelBooking,
142
154
  addCustomSale,
143
155
  editCustomSale,
144
156
  addNonRevenueItem,
@@ -159,8 +171,6 @@ export const command = {
159
171
  // Product Actions
160
172
  addProductNote,
161
173
  addProductFee,
162
- getProductModifierSelections,
163
- setProductModifierSelections,
164
174
  setActiveProductFee,
165
175
  setActiveProductDiscount,
166
176
  getActiveProduct,
@@ -305,6 +315,7 @@ export { variantsTopic } from './pubsub/topics/variants';
305
315
  export { transactionsTopic } from './pubsub/topics/transactions';
306
316
  export { categoriesTopic } from './pubsub/topics/categories';
307
317
  export { attributesTopic } from './pubsub/topics/attributes';
318
+ export { bookingsTopic } from './pubsub/topics/bookings';
308
319
  // Export Custom Tables Types
309
320
  export { AttributeType } from './common-types/attribute-type';
310
321
  // State Machine Fragments
@@ -12,8 +12,6 @@ import { mockAddOrderNote } from '../../actions/add-order-note/mock';
12
12
  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
- import { mockGetProductModifierSelections } from '../../actions/get-product-modifier-selections/mock';
16
- import { mockSetProductModifierSelections } from '../../actions/set-product-modifier-selections/mock';
17
15
  import { mockRemoveProductDiscount } from '../../actions/remove-product-discount/mock';
18
16
  import { mockRemoveProductFee } from '../../actions/remove-product-fee/mock';
19
17
  import { mockSetActiveProductFee } from '../../actions/set-active-product-fee/mock';
@@ -44,6 +42,13 @@ import { mockGetCurrentCart } from '../../actions/get-current-cart/mock';
44
42
  import { mockGetCustomers } from '../../actions/get-customers/mock';
45
43
  import { mockGetOrders } from '../../actions/get-orders/mock';
46
44
  import { mockGetProducts } from '../../actions/get-products/mock';
45
+ import { mockGetBookingResources } from '../../actions/get-booking-resources/mock';
46
+ import { mockGetBookingAvailability } from '../../actions/get-booking-availability/mock';
47
+ import { mockGetBookings } from '../../actions/get-bookings/mock';
48
+ import { mockHoldBooking } from '../../actions/hold-booking/mock';
49
+ import { mockAddBookingToCart } from '../../actions/add-booking-to-cart/mock';
50
+ import { mockRemoveBookingFromCart } from '../../actions/remove-booking-from-cart/mock';
51
+ import { mockCancelBooking } from '../../actions/cancel-booking/mock';
47
52
  import { mockGetRefunds } from '../../actions/get-refunds/mock';
48
53
  import { mockGetTaxTables } from '../../actions/get-tax-tables/mock';
49
54
  import { mockGetRemainingRefundableQuantities } from '../../actions/get-remaining-refundable-quantities/mock';
@@ -114,8 +119,6 @@ export const RENDER_MOCKS = {
114
119
  addOrderNote: mockAddOrderNote,
115
120
  addProductDiscount: mockAddProductDiscount,
116
121
  addProductFee: mockAddProductFee,
117
- getProductModifierSelections: mockGetProductModifierSelections,
118
- setProductModifierSelections: mockSetProductModifierSelections,
119
122
  setActiveProductFee: mockSetActiveProductFee,
120
123
  setActiveProductDiscount: mockSetActiveProductDiscount,
121
124
  getActiveProduct: mockGetActiveProduct,
@@ -142,6 +145,13 @@ export const RENDER_MOCKS = {
142
145
  getCustomers: mockGetCustomers,
143
146
  getOrders: mockGetOrders,
144
147
  getProducts: mockGetProducts,
148
+ getBookingResources: mockGetBookingResources,
149
+ getBookingAvailability: mockGetBookingAvailability,
150
+ getBookings: mockGetBookings,
151
+ holdBooking: mockHoldBooking,
152
+ addBookingToCart: mockAddBookingToCart,
153
+ removeBookingFromCart: mockRemoveBookingFromCart,
154
+ cancelBooking: mockCancelBooking,
145
155
  getRefunds: mockGetRefunds,
146
156
  getTaxTables: mockGetTaxTables,
147
157
  getRemainingRefundableQuantities: mockGetRemainingRefundableQuantities,
@@ -1,7 +1,14 @@
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, 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, 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;
5
+ getBookingResources: GetBookingResources;
6
+ getBookingAvailability: GetBookingAvailability;
7
+ getBookings: GetBookings;
8
+ holdBooking: HoldBooking;
9
+ addBookingToCart: AddBookingToCart;
10
+ removeBookingFromCart: RemoveBookingFromCart;
11
+ cancelBooking: CancelBooking;
5
12
  addCustomSale: AddCustomSale;
6
13
  editCustomSale: EditCustomSale;
7
14
  getCustomers: GetCustomers;
@@ -21,8 +28,6 @@ export interface RenderProviderActions {
21
28
  getFinalContext: GetFinalContext;
22
29
  addProductNote: AddProductNote;
23
30
  addProductFee: AddProductFee;
24
- getProductModifierSelections: GetProductModifierSelections;
25
- setProductModifierSelections: SetProductModifierSelections;
26
31
  setActiveProductFee: SetActiveProductFee;
27
32
  setActiveProductDiscount: SetActiveProductDiscount;
28
33
  getActiveProduct: GetActiveProduct;
@@ -0,0 +1,6 @@
1
+ import type { CFBooking } from '../../../../CommonTypes';
2
+ import type { TopicEvent } from '../../../types';
3
+ export interface BookingCreatedPayload {
4
+ booking: CFBooking;
5
+ }
6
+ export type BookingCreatedEvent = TopicEvent<BookingCreatedPayload>;
@@ -0,0 +1,15 @@
1
+ import type { TopicEvent } from '../../../types';
2
+ /**
3
+ * What a booking can be MADE of changed — a rule set, a resource, who serves a product, or where
4
+ * a resource works. Occupancy is untouched.
5
+ *
6
+ * Deliberately carries no row: the change can span several collections at once (a rule set edited
7
+ * AND a product↔resource link removed), and a subscriber cannot act on a partial picture anyway.
8
+ * The only correct reaction is to re-ask `getBookingResources` and `getBookingAvailability`,
9
+ * because both previous answers were computed from the old setup.
10
+ */
11
+ export interface BookingSetupChangedPayload {
12
+ /** Which collection moved, when the host knows: `booking-rules`, `booking-resources`, … */
13
+ collection?: string;
14
+ }
15
+ export type BookingSetupChangedEvent = TopicEvent<BookingSetupChangedPayload>;
@@ -0,0 +1,6 @@
1
+ import type { CFBooking } from '../../../../CommonTypes';
2
+ import type { TopicEvent } from '../../../types';
3
+ export interface BookingUpdatedPayload {
4
+ booking: CFBooking;
5
+ }
6
+ export type BookingUpdatedEvent = TopicEvent<BookingUpdatedPayload>;
@@ -0,0 +1,3 @@
1
+ import type { TopicDefinition } from '../../types';
2
+ export declare const bookingsTopic: TopicDefinition;
3
+ export * from './types';
@@ -0,0 +1,27 @@
1
+ export const bookingsTopic = {
2
+ id: 'bookings',
3
+ name: 'Bookings',
4
+ description: 'Topic for bookings synced from the database. A booking IS the occupancy, so this is the ' +
5
+ 'signal that somebody else took (or freed) a window: re-ask getBookingAvailability when it ' +
6
+ 'fires instead of polling the server on a timer.',
7
+ eventTypes: [
8
+ {
9
+ id: 'booking-created',
10
+ name: 'Booking Created',
11
+ description: 'Published when a booking made elsewhere — another till, the back office — is synced in',
12
+ },
13
+ {
14
+ id: 'booking-updated',
15
+ name: 'Booking Updated',
16
+ description: 'Published when a synced booking changes: confirmed after payment, cancelled, or expired',
17
+ },
18
+ {
19
+ id: 'booking-setup-changed',
20
+ name: 'Booking Setup Changed',
21
+ description: 'Published when what a booking can be MADE of changes: a rule set, a resource, who serves ' +
22
+ 'a product, or where a resource works. Occupancy is untouched — re-ask getBookingResources ' +
23
+ 'and getBookingAvailability, because both answers were computed from the old setup.',
24
+ },
25
+ ],
26
+ };
27
+ export * from './types';