@final-commerce/command-frame 0.6.0 → 0.7.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 +11 -1
- package/dist/actions/add-booking-to-cart/action.d.ts +6 -0
- package/dist/actions/add-booking-to-cart/action.js +8 -0
- package/dist/actions/add-booking-to-cart/mock.d.ts +2 -0
- package/dist/actions/add-booking-to-cart/mock.js +8 -0
- package/dist/actions/add-booking-to-cart/types.d.ts +23 -0
- package/dist/actions/add-booking-to-cart/types.js +1 -0
- package/dist/actions/cancel-booking/action.d.ts +6 -0
- package/dist/actions/cancel-booking/action.js +8 -0
- package/dist/actions/cancel-booking/mock.d.ts +2 -0
- package/dist/actions/cancel-booking/mock.js +10 -0
- package/dist/actions/cancel-booking/types.d.ts +10 -0
- package/dist/actions/cancel-booking/types.js +1 -0
- package/dist/actions/get-booking-availability/action.d.ts +6 -0
- package/dist/actions/get-booking-availability/action.js +8 -0
- package/dist/actions/get-booking-availability/mock.d.ts +2 -0
- package/dist/actions/get-booking-availability/mock.js +6 -0
- package/dist/actions/get-booking-availability/types.d.ts +18 -0
- package/dist/actions/get-booking-availability/types.js +1 -0
- package/dist/actions/get-booking-resources/action.d.ts +6 -0
- package/dist/actions/get-booking-resources/action.js +8 -0
- package/dist/actions/get-booking-resources/mock.d.ts +2 -0
- package/dist/actions/get-booking-resources/mock.js +7 -0
- package/dist/actions/get-booking-resources/types.d.ts +12 -0
- package/dist/actions/get-booking-resources/types.js +1 -0
- package/dist/actions/get-bookings/action.d.ts +6 -0
- package/dist/actions/get-bookings/action.js +8 -0
- package/dist/actions/get-bookings/mock.d.ts +2 -0
- package/dist/actions/get-bookings/mock.js +20 -0
- package/dist/actions/get-bookings/types.d.ts +18 -0
- package/dist/actions/get-bookings/types.js +1 -0
- package/dist/actions/hold-booking/action.d.ts +6 -0
- package/dist/actions/hold-booking/action.js +8 -0
- package/dist/actions/hold-booking/mock.d.ts +2 -0
- package/dist/actions/hold-booking/mock.js +33 -0
- package/dist/actions/hold-booking/types.d.ts +24 -0
- package/dist/actions/hold-booking/types.js +1 -0
- package/dist/actions/remove-booking-from-cart/action.d.ts +6 -0
- package/dist/actions/remove-booking-from-cart/action.js +8 -0
- package/dist/actions/remove-booking-from-cart/mock.d.ts +2 -0
- package/dist/actions/remove-booking-from-cart/mock.js +16 -0
- package/dist/actions/remove-booking-from-cart/types.d.ts +12 -0
- package/dist/actions/remove-booking-from-cart/types.js +1 -0
- package/dist/demo/database.d.ts +8 -1
- package/dist/demo/database.js +93 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +15 -0
- package/dist/projects/render/mocks.js +14 -0
- package/dist/projects/render/types.d.ts +8 -1
- package/dist/pubsub/topics/bookings/booking-created/types.d.ts +6 -0
- package/dist/pubsub/topics/bookings/booking-created/types.js +1 -0
- package/dist/pubsub/topics/bookings/booking-setup-changed/types.d.ts +15 -0
- package/dist/pubsub/topics/bookings/booking-setup-changed/types.js +1 -0
- package/dist/pubsub/topics/bookings/booking-updated/types.d.ts +6 -0
- package/dist/pubsub/topics/bookings/booking-updated/types.js +1 -0
- package/dist/pubsub/topics/bookings/index.d.ts +3 -0
- package/dist/pubsub/topics/bookings/index.js +27 -0
- package/dist/pubsub/topics/bookings/types.d.ts +8 -0
- package/dist/pubsub/topics/bookings/types.js +3 -0
- package/dist/pubsub/topics/index.d.ts +17 -16
- package/dist/pubsub/topics/index.js +17 -16
- package/dist/pubsub/topics/types.d.ts +2 -0
- package/package.json +2 -2
package/dist/CommonTypes.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from './common-types';
|
|
2
|
-
import type { Tax, Tip, Address, MetadataItem, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment } from '@final-commerce/common/pos-types';
|
|
2
|
+
import type { Tax, Tip, Address, MetadataItem, PosDataItem, CartFeeTaxEntry, CartFeeItem, CartDiscountItem, OrderNote, NonRevenueItem, DiscountDetail, FeeDetail, DiscountLineItem, FeeLineItem, LineItem, TipPayment, RefundedTipPayment, PaymentMethod, Discount, CustomFee, Summary, CustomSale, RefundedCustomSale, RefundItem, RefundedLineItem, ActiveStation, ActiveSession, ActiveOutlet, ActiveUser, ActiveUserRole, ActiveOrder, ActiveCart, ActivePark, ActiveCompany, ActiveCustomSales, ActiveProduct, ActiveCustomer, FullProduct, ProductVariant, Inventory, CustomerNote, Attribute, AttributeOption, Category, Transaction, ActiveSplitPayment, BookingAvailability, BookingSlot, BookingSlotResource, BookingResource, Booking, CartReservation, OrderReservation } from '@final-commerce/common/pos-types';
|
|
3
3
|
export { CurrencyCode, ProductType as CFProductType, UserTypes as CFUserTypes } from '@final-commerce/common';
|
|
4
4
|
/** Open record used as a base for active entities. */
|
|
5
5
|
export type CFActiveEntity = Record<string, unknown>;
|
|
@@ -18,6 +18,16 @@ export type CFTransaction = Transaction;
|
|
|
18
18
|
export type CFCategory = Category;
|
|
19
19
|
export type CFProductVariant = ProductVariant;
|
|
20
20
|
export type CFProduct = FullProduct;
|
|
21
|
+
export type CFBookingAvailability = BookingAvailability;
|
|
22
|
+
export type CFBookingSlot = BookingSlot;
|
|
23
|
+
export type CFBookingSlotResource = BookingSlotResource;
|
|
24
|
+
export type CFBookingResource = BookingResource;
|
|
25
|
+
export type CFBooking = Booking;
|
|
26
|
+
/** A service sitting in the cart, and the same sale once it is on an order. A flow that draws a
|
|
27
|
+
* cart or a receipt needs both by name — reaching into the package's dist for them is not an
|
|
28
|
+
* interface. */
|
|
29
|
+
export type CFCartReservation = CartReservation;
|
|
30
|
+
export type CFOrderReservation = OrderReservation;
|
|
21
31
|
export type CFActiveProduct = ActiveProduct;
|
|
22
32
|
export type CFCustomer = ActiveCustomer;
|
|
23
33
|
export type CFActiveCustomer = ActiveCustomer;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Add booking to cart action
|
|
3
|
+
* Calls the addBookingToCart action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const addBookingToCart = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('addBookingToCart', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { mockHoldBooking } from '../hold-booking/mock';
|
|
2
|
+
export const mockAddBookingToCart = async (params) => {
|
|
3
|
+
console.log('[Mock] addBookingToCart called', params);
|
|
4
|
+
// Same claim as holdBooking — including its refusal when the window is already taken. The mock
|
|
5
|
+
// cart is not modelled here; what a booking screen must handle is the refusal, not the line.
|
|
6
|
+
const { booking } = await mockHoldBooking(params);
|
|
7
|
+
return { booking, reservationInternalId: `res_${booking.id}`, timestamp: new Date().toISOString() };
|
|
8
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CFBooking } from '../../CommonTypes';
|
|
2
|
+
export interface AddBookingToCartParams {
|
|
3
|
+
/** The bookable product (`productType: 'booking'`). */
|
|
4
|
+
productId: string;
|
|
5
|
+
/** Which resource serves it: a member of staff, a room, a scooter. */
|
|
6
|
+
resourceId: string;
|
|
7
|
+
/** Must be the START of a slot getBookingAvailability offered, ISO 8601. */
|
|
8
|
+
startAt: string;
|
|
9
|
+
/** End of the window — the slot's own `endAt`, or the last slot's for a stay. */
|
|
10
|
+
endAt: string;
|
|
11
|
+
/** The variant being sold. Defaults to the product's only variant. */
|
|
12
|
+
variantId?: string;
|
|
13
|
+
/** Whom the booking is for. Omit for a walk-in. */
|
|
14
|
+
customerId?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface AddBookingToCartResponse {
|
|
17
|
+
/** The claim the cart now stands on: `id` cancels or releases it, `expiresAt` is your clock. */
|
|
18
|
+
booking: CFBooking;
|
|
19
|
+
/** Identity of the reservation inside the cart and, later, the order. */
|
|
20
|
+
reservationInternalId: string;
|
|
21
|
+
timestamp: string;
|
|
22
|
+
}
|
|
23
|
+
export type AddBookingToCart = (params: AddBookingToCartParams) => Promise<AddBookingToCartResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MOCK_BOOKINGS } from '../../demo/database';
|
|
2
|
+
import { ReservationStatus } from '@final-commerce/common';
|
|
3
|
+
export const mockCancelBooking = async (params) => {
|
|
4
|
+
console.log('[Mock] cancelBooking called', params);
|
|
5
|
+
const booking = MOCK_BOOKINGS.find(({ id }) => id === params.bookingId);
|
|
6
|
+
if (!booking)
|
|
7
|
+
throw new Error(`No booking ${params.bookingId}`);
|
|
8
|
+
booking.status = ReservationStatus.CANCELLED;
|
|
9
|
+
return { booking, timestamp: new Date().toISOString() };
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CFBooking } from '../../CommonTypes';
|
|
2
|
+
export interface CancelBookingParams {
|
|
3
|
+
/** `id` of the booking returned by holdBooking or getBookings. */
|
|
4
|
+
bookingId: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CancelBookingResponse {
|
|
7
|
+
booking: CFBooking;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
}
|
|
10
|
+
export type CancelBooking = (params: CancelBookingParams) => Promise<CancelBookingResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get booking availability action
|
|
3
|
+
* Calls the getBookingAvailability action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const getBookingAvailability = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('getBookingAvailability', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { mockBookingAvailability } from '../../demo/database';
|
|
2
|
+
export const mockGetBookingAvailability = async (params) => {
|
|
3
|
+
console.log('[Mock] getBookingAvailability called', params);
|
|
4
|
+
const availability = mockBookingAvailability(params.productId, new Date(params.from), new Date(params.to), params.resourceId);
|
|
5
|
+
return { availability, timestamp: new Date().toISOString() };
|
|
6
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CFBookingAvailability } from '../../CommonTypes';
|
|
2
|
+
export interface GetBookingAvailabilityParams {
|
|
3
|
+
/** The bookable product (`productType: 'booking'`) whose calendar you are drawing. */
|
|
4
|
+
productId: string;
|
|
5
|
+
/** Range start, ISO 8601. */
|
|
6
|
+
from: string;
|
|
7
|
+
/** Range end, ISO 8601. */
|
|
8
|
+
to: string;
|
|
9
|
+
/** Narrow the answer to one resource — "only Marco", "only room 4". */
|
|
10
|
+
resourceId?: string;
|
|
11
|
+
/** Narrow to the resources standing at one outlet. */
|
|
12
|
+
outletId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface GetBookingAvailabilityResponse {
|
|
15
|
+
availability: CFBookingAvailability;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
}
|
|
18
|
+
export type GetBookingAvailability = (params: GetBookingAvailabilityParams) => Promise<GetBookingAvailabilityResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get booking resources action
|
|
3
|
+
* Calls the getBookingResources action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const getBookingResources = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('getBookingResources', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { MOCK_BOOKING_RESOURCES } from '../../demo/database';
|
|
2
|
+
export const mockGetBookingResources = async (params) => {
|
|
3
|
+
console.log('[Mock] getBookingResources called', params);
|
|
4
|
+
// A resource knows nothing about outlets — where it works lives in its own records, which the
|
|
5
|
+
// host reads. The mock has no such records, so `outletId` narrows nothing here.
|
|
6
|
+
return { resources: MOCK_BOOKING_RESOURCES, timestamp: new Date().toISOString() };
|
|
7
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { CFBookingResource } from '../../CommonTypes';
|
|
2
|
+
export interface GetBookingResourcesParams {
|
|
3
|
+
/** Only the resources that serve this bookable product. Omit for the whole company. */
|
|
4
|
+
productId?: string;
|
|
5
|
+
/** Only resources standing at this outlet (a resource with no outlet serves all of them). */
|
|
6
|
+
outletId?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface GetBookingResourcesResponse {
|
|
9
|
+
resources: CFBookingResource[];
|
|
10
|
+
timestamp: string;
|
|
11
|
+
}
|
|
12
|
+
export type GetBookingResources = (params?: GetBookingResourcesParams) => Promise<GetBookingResourcesResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MOCK_BOOKINGS, mockLiveBookings } from '../../demo/database';
|
|
2
|
+
export const mockGetBookings = async (params) => {
|
|
3
|
+
console.log('[Mock] getBookings called', params);
|
|
4
|
+
let bookings = params?.includeExpired ? MOCK_BOOKINGS : mockLiveBookings();
|
|
5
|
+
if (params?.resourceId)
|
|
6
|
+
bookings = bookings.filter((entry) => entry.resourceId === params.resourceId);
|
|
7
|
+
if (params?.productId)
|
|
8
|
+
bookings = bookings.filter((entry) => entry.productId === params.productId);
|
|
9
|
+
if (params?.customerId)
|
|
10
|
+
bookings = bookings.filter((entry) => entry.customerId === params.customerId);
|
|
11
|
+
if (params?.from) {
|
|
12
|
+
const from = new Date(params.from);
|
|
13
|
+
bookings = bookings.filter((entry) => new Date(entry.bufferEndAt) > from);
|
|
14
|
+
}
|
|
15
|
+
if (params?.to) {
|
|
16
|
+
const to = new Date(params.to);
|
|
17
|
+
bookings = bookings.filter((entry) => new Date(entry.startAt) < to);
|
|
18
|
+
}
|
|
19
|
+
return { bookings, timestamp: new Date().toISOString() };
|
|
20
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CFBooking } from '../../CommonTypes';
|
|
2
|
+
export interface GetBookingsParams {
|
|
3
|
+
/** Everything taking this resource's time — the one query a day view needs. */
|
|
4
|
+
resourceId?: string;
|
|
5
|
+
productId?: string;
|
|
6
|
+
/** This customer's appointments. */
|
|
7
|
+
customerId?: string;
|
|
8
|
+
/** Bookings whose window overlaps this range, ISO 8601. */
|
|
9
|
+
from?: string;
|
|
10
|
+
to?: string;
|
|
11
|
+
/** Defaults to live bookings only (confirmed, plus holds that have not expired). */
|
|
12
|
+
includeExpired?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GetBookingsResponse {
|
|
15
|
+
bookings: CFBooking[];
|
|
16
|
+
timestamp: string;
|
|
17
|
+
}
|
|
18
|
+
export type GetBookings = (params?: GetBookingsParams) => Promise<GetBookingsResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { MOCK_BOOKINGS, MOCK_BOOKING_RESOURCES, mockLiveBookings } from '../../demo/database';
|
|
2
|
+
import { ReservationStatus } from '@final-commerce/common';
|
|
3
|
+
const BUFFER_MINUTES = 5;
|
|
4
|
+
const HOLD_MINUTES = 10;
|
|
5
|
+
export const mockHoldBooking = async (params) => {
|
|
6
|
+
console.log('[Mock] holdBooking called', params);
|
|
7
|
+
const startAt = new Date(params.startAt);
|
|
8
|
+
const endAt = new Date(params.endAt);
|
|
9
|
+
const bufferEndAt = new Date(endAt.getTime() + BUFFER_MINUTES * 60000);
|
|
10
|
+
// The mock refuses a taken window like the host does. A mock that always said yes would
|
|
11
|
+
// let a booking screen ship without ever handling the one error it will actually meet.
|
|
12
|
+
const clash = mockLiveBookings().some((entry) => entry.resourceId === params.resourceId &&
|
|
13
|
+
new Date(entry.startAt) < bufferEndAt &&
|
|
14
|
+
new Date(entry.bufferEndAt) > startAt);
|
|
15
|
+
if (clash)
|
|
16
|
+
throw new Error('That window has just been taken — pick another slot.');
|
|
17
|
+
const booking = {
|
|
18
|
+
id: `bk_mock_${Date.now()}`,
|
|
19
|
+
productId: params.productId,
|
|
20
|
+
resourceId: params.resourceId,
|
|
21
|
+
variantId: params.variantId,
|
|
22
|
+
startAt: startAt.toISOString(),
|
|
23
|
+
endAt: endAt.toISOString(),
|
|
24
|
+
bufferEndAt: bufferEndAt.toISOString(),
|
|
25
|
+
customerId: params.customerId,
|
|
26
|
+
status: ReservationStatus.HELD,
|
|
27
|
+
expiresAt: new Date(Date.now() + HOLD_MINUTES * 60000).toISOString(),
|
|
28
|
+
resourceName: MOCK_BOOKING_RESOURCES.find(({ id }) => id === params.resourceId)?.name,
|
|
29
|
+
};
|
|
30
|
+
// Held in the same list availability reads, so the slot really does disappear.
|
|
31
|
+
MOCK_BOOKINGS.push(booking);
|
|
32
|
+
return { booking, timestamp: new Date().toISOString() };
|
|
33
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CFBooking } from '../../CommonTypes';
|
|
2
|
+
export interface HoldBookingParams {
|
|
3
|
+
productId: string;
|
|
4
|
+
/** Which resource serves it: a member of staff, a room, a scooter. */
|
|
5
|
+
resourceId: string;
|
|
6
|
+
/** Must be the START of a slot the host offered, ISO 8601. */
|
|
7
|
+
startAt: string;
|
|
8
|
+
/**
|
|
9
|
+
* End of the window — the `endAt` of the slot you picked, or of the last slot in a stay.
|
|
10
|
+
* Required: the server refuses a window it cannot line up with its own grid, and the till
|
|
11
|
+
* has no local copy of the rules to derive it from.
|
|
12
|
+
*/
|
|
13
|
+
endAt: string;
|
|
14
|
+
/** The variant being sold, when the flow already knows which one. */
|
|
15
|
+
variantId?: string;
|
|
16
|
+
/** Whom the booking is for. Omit for a walk-in. */
|
|
17
|
+
customerId?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface HoldBookingResponse {
|
|
20
|
+
/** The claim. `expiresAt` says how long it survives unpaid; `id` is what you confirm or cancel. */
|
|
21
|
+
booking: CFBooking;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
}
|
|
24
|
+
export type HoldBooking = (params: HoldBookingParams) => Promise<HoldBookingResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remove booking from cart action
|
|
3
|
+
* Calls the removeBookingFromCart action on the parent window
|
|
4
|
+
*/
|
|
5
|
+
import { commandFrameClient } from '../../client';
|
|
6
|
+
export const removeBookingFromCart = async (params) => {
|
|
7
|
+
return await commandFrameClient.call('removeBookingFromCart', params);
|
|
8
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MOCK_BOOKINGS } from '../../demo/database';
|
|
2
|
+
export const mockRemoveBookingFromCart = async (params) => {
|
|
3
|
+
console.log('[Mock] removeBookingFromCart called', params);
|
|
4
|
+
// The hold has to go back, or the mock is a trap: `addBookingToCart` pushes into the very list
|
|
5
|
+
// availability reads, so add → remove → add the same slot used to refuse forever with "that
|
|
6
|
+
// window has just been taken". The reservation id the mock hands out is `res_<booking.id>`,
|
|
7
|
+
// which is the only link back to the row.
|
|
8
|
+
const bookingId = params.reservationInternalId.replace(/^res_/, '');
|
|
9
|
+
const index = MOCK_BOOKINGS.findIndex(({ id }) => id === bookingId);
|
|
10
|
+
const [released] = index >= 0 ? MOCK_BOOKINGS.splice(index, 1) : [];
|
|
11
|
+
return {
|
|
12
|
+
reservationInternalId: params.reservationInternalId,
|
|
13
|
+
booking: released,
|
|
14
|
+
timestamp: new Date().toISOString(),
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -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 {};
|
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 } 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 {
|
|
@@ -59,6 +59,7 @@ export declare const MOCK_STATIONS: import("@final-commerce/common/pos-types").A
|
|
|
59
59
|
export declare const MOCK_OUTLETS: import("@final-commerce/common/pos-types").ActiveOutlet[];
|
|
60
60
|
export declare const MOCK_CUSTOMERS: import("@final-commerce/common/pos-types").ActiveCustomer[];
|
|
61
61
|
export declare const MOCK_CATEGORIES: import("@final-commerce/common/pos-types").Category[];
|
|
62
|
+
export declare const MOCK_PRODUCT_HAIRCUT: CFProduct;
|
|
62
63
|
export declare const MOCK_PRODUCTS: import("@final-commerce/common/pos-types").FullProduct[];
|
|
63
64
|
export declare const MOCK_ORDERS: import("@final-commerce/common/pos-types").ActiveOrder[];
|
|
64
65
|
export declare const MOCK_PARKED_ORDERS: CFActiveOrder[];
|
|
@@ -87,3 +88,9 @@ export declare const createOrderFromCart: (paymentType: string, amount: number,
|
|
|
87
88
|
* open with `amountToBeCharged` reset to what's left, and returns null.
|
|
88
89
|
*/
|
|
89
90
|
export declare const applyMockPayment: (amount: number, paymentType: string, processor?: string) => CFActiveOrder | null;
|
|
91
|
+
export declare const MOCK_BOOKING_RULES_ID = "rule_salon_30";
|
|
92
|
+
export declare const MOCK_BOOKING_RESOURCES: CFBookingResource[];
|
|
93
|
+
export declare const MOCK_BOOKINGS: CFBooking[];
|
|
94
|
+
/** Live = confirmed, or held and not yet expired. An expired hold occupies nothing. */
|
|
95
|
+
export declare const mockLiveBookings: () => CFBooking[];
|
|
96
|
+
export declare const mockBookingAvailability: (productId: string, from: Date, to: Date, resourceId?: string) => CFBookingAvailability;
|
package/dist/demo/database.js
CHANGED
|
@@ -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];
|
|
@@ -914,3 +924,86 @@ export const applyMockPayment = (amount, paymentType, processor = 'cash') => {
|
|
|
914
924
|
mockPublishEvent('payments', 'payment-done', { order });
|
|
915
925
|
return order;
|
|
916
926
|
};
|
|
927
|
+
// ── Booking (FT-0064) ────────────────────────────────────────────────────────────
|
|
928
|
+
// A salon: one service, two people who can perform it, a 30-minute slot with a
|
|
929
|
+
// 5-minute turnaround, open 9–18. Enough to click through a booking screen with no
|
|
930
|
+
// server. Availability here is COMPUTED, exactly as the host computes it — a mock
|
|
931
|
+
// that returned a fixed list of slots would hide the one behaviour that matters:
|
|
932
|
+
// a slot disappears once somebody takes it.
|
|
933
|
+
export const MOCK_BOOKING_RULES_ID = 'rule_salon_30';
|
|
934
|
+
const SLOT_MINUTES = 30;
|
|
935
|
+
const BUFFER_MINUTES = 5;
|
|
936
|
+
const OPEN_HOUR = 9;
|
|
937
|
+
const CLOSE_HOUR = 18;
|
|
938
|
+
export const MOCK_BOOKING_RESOURCES = [
|
|
939
|
+
{ id: 'res_marco', name: 'Marco', kind: BookingResourceKind.STAFF },
|
|
940
|
+
{ id: 'res_jessica', name: 'Jessica', kind: BookingResourceKind.STAFF },
|
|
941
|
+
];
|
|
942
|
+
const at = (dayOffset, hour, minute = 0) => {
|
|
943
|
+
const date = new Date();
|
|
944
|
+
date.setDate(date.getDate() + dayOffset);
|
|
945
|
+
date.setHours(hour, minute, 0, 0);
|
|
946
|
+
return date;
|
|
947
|
+
};
|
|
948
|
+
const booking = (id, resourceId, start, status, customerName) => ({
|
|
949
|
+
id,
|
|
950
|
+
productId: MOCK_PRODUCT_HAIRCUT._id,
|
|
951
|
+
resourceId,
|
|
952
|
+
startAt: start.toISOString(),
|
|
953
|
+
endAt: new Date(start.getTime() + SLOT_MINUTES * 60000).toISOString(),
|
|
954
|
+
bufferEndAt: new Date(start.getTime() + (SLOT_MINUTES + BUFFER_MINUTES) * 60000).toISOString(),
|
|
955
|
+
status,
|
|
956
|
+
productName: MOCK_PRODUCT_HAIRCUT.name,
|
|
957
|
+
resourceName: MOCK_BOOKING_RESOURCES.find((resource) => resource.id === resourceId)?.name,
|
|
958
|
+
customerName,
|
|
959
|
+
});
|
|
960
|
+
export const MOCK_BOOKINGS = [
|
|
961
|
+
booking('bk_1', 'res_marco', at(0, 10), ReservationStatus.CONFIRMED, 'Alex Green'),
|
|
962
|
+
booking('bk_2', 'res_jessica', at(0, 11, 30), ReservationStatus.CONFIRMED, 'Dana White'),
|
|
963
|
+
booking('bk_3', 'res_marco', at(1, 9, 30), ReservationStatus.CONFIRMED, 'Sam Blue'),
|
|
964
|
+
];
|
|
965
|
+
/** Live = confirmed, or held and not yet expired. An expired hold occupies nothing. */
|
|
966
|
+
export const mockLiveBookings = () => MOCK_BOOKINGS.filter(({ status, expiresAt }) => status === ReservationStatus.CONFIRMED ||
|
|
967
|
+
(status === ReservationStatus.HELD && (!expiresAt || new Date(expiresAt) > new Date())));
|
|
968
|
+
const takenBy = (resourceId, startAt, bufferEndAt) => mockLiveBookings().some((entry) => entry.resourceId === resourceId && new Date(entry.startAt) < bufferEndAt && new Date(entry.bufferEndAt) > startAt);
|
|
969
|
+
export const mockBookingAvailability = (productId, from, to, resourceId) => {
|
|
970
|
+
const serving = resourceId
|
|
971
|
+
? MOCK_BOOKING_RESOURCES.filter((resource) => resource.id === resourceId)
|
|
972
|
+
: MOCK_BOOKING_RESOURCES;
|
|
973
|
+
const slots = [];
|
|
974
|
+
const step = (SLOT_MINUTES + BUFFER_MINUTES) * 60000;
|
|
975
|
+
for (let day = 0; day < 14; day += 1) {
|
|
976
|
+
const open = at(day, OPEN_HOUR);
|
|
977
|
+
if (open < from || open > to)
|
|
978
|
+
continue;
|
|
979
|
+
const close = at(day, CLOSE_HOUR);
|
|
980
|
+
for (let start = open.getTime(); start + SLOT_MINUTES * 60000 <= close.getTime(); start += step) {
|
|
981
|
+
const startAt = new Date(start);
|
|
982
|
+
const endAt = new Date(start + SLOT_MINUTES * 60000);
|
|
983
|
+
const bufferEndAt = new Date(start + (SLOT_MINUTES + BUFFER_MINUTES) * 60000);
|
|
984
|
+
if (bufferEndAt < new Date())
|
|
985
|
+
continue;
|
|
986
|
+
const resources = serving.map((resource) => {
|
|
987
|
+
const free = takenBy(resource.id, startAt, bufferEndAt) ? 0 : 1;
|
|
988
|
+
return { resourceId: resource.id, name: resource.name, capacity: 1, booked: 1 - free, free };
|
|
989
|
+
});
|
|
990
|
+
slots.push({
|
|
991
|
+
startAt: startAt.toISOString(),
|
|
992
|
+
endAt: endAt.toISOString(),
|
|
993
|
+
bufferEndAt: bufferEndAt.toISOString(),
|
|
994
|
+
canStart: true,
|
|
995
|
+
capacity: resources.length,
|
|
996
|
+
booked: resources.reduce((sum, entry) => sum + entry.booked, 0),
|
|
997
|
+
free: resources.reduce((sum, entry) => sum + entry.free, 0),
|
|
998
|
+
resources,
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return {
|
|
1003
|
+
productId,
|
|
1004
|
+
bookingRulesId: MOCK_BOOKING_RULES_ID,
|
|
1005
|
+
bookingType: BookingType.APPOINTMENT,
|
|
1006
|
+
ratePeriod: BookingRatePeriod.SLOT,
|
|
1007
|
+
slots,
|
|
1008
|
+
};
|
|
1009
|
+
};
|
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;
|
|
@@ -116,6 +123,13 @@ export declare const command: {
|
|
|
116
123
|
export type { ExampleFunction, ExampleFunctionParams, ExampleFunctionResponse } from './actions/example-function/types';
|
|
117
124
|
export type { GenerateAPIKey, GenerateAPIKeyParams, GenerateAPIKeyResponse } from './actions/generate-api-key/types';
|
|
118
125
|
export type { GetProducts, GetProductsParams, GetProductsResponse } from './actions/get-products/types';
|
|
126
|
+
export type { GetBookingResources, GetBookingResourcesParams, GetBookingResourcesResponse, } from './actions/get-booking-resources/types';
|
|
127
|
+
export type { GetBookingAvailability, GetBookingAvailabilityParams, GetBookingAvailabilityResponse, } from './actions/get-booking-availability/types';
|
|
128
|
+
export type { GetBookings, GetBookingsParams, GetBookingsResponse } from './actions/get-bookings/types';
|
|
129
|
+
export type { HoldBooking, HoldBookingParams, HoldBookingResponse } from './actions/hold-booking/types';
|
|
130
|
+
export type { AddBookingToCart, AddBookingToCartParams, AddBookingToCartResponse, } from './actions/add-booking-to-cart/types';
|
|
131
|
+
export type { RemoveBookingFromCart, RemoveBookingFromCartParams, RemoveBookingFromCartResponse, } from './actions/remove-booking-from-cart/types';
|
|
132
|
+
export type { CancelBooking, CancelBookingParams, CancelBookingResponse } from './actions/cancel-booking/types';
|
|
119
133
|
export type { AddCustomSale, AddCustomSaleParams, AddCustomSaleResponse } from './actions/add-custom-sale/types';
|
|
120
134
|
export type { EditCustomSale, EditCustomSaleParams, EditCustomSaleResponse } from './actions/edit-custom-sale/types';
|
|
121
135
|
export type { AddNonRevenueItem, AddNonRevenueItemParams, AddNonRevenueItemResponse, } from './actions/add-non-revenue-item/types';
|
|
@@ -239,6 +253,7 @@ export { variantsTopic } from './pubsub/topics/variants';
|
|
|
239
253
|
export { transactionsTopic } from './pubsub/topics/transactions';
|
|
240
254
|
export { categoriesTopic } from './pubsub/topics/categories';
|
|
241
255
|
export { attributesTopic } from './pubsub/topics/attributes';
|
|
256
|
+
export { bookingsTopic } from './pubsub/topics/bookings';
|
|
242
257
|
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';
|
|
243
258
|
export type { OrderCreatedPayload, OrderUpdatedPayload, OrderVoidedPayload, OrderActiveSetPayload, OrderActiveGetPayload, OrderCreatedEvent, OrderUpdatedEvent, OrderVoidedEvent, OrderActiveSetEvent, OrderActiveGetEvent, OrderStateTransitionCompletedPayload, OrderStateTransitionBlockedPayload, OrderStateTransitionCompletedEvent, OrderStateTransitionBlockedEvent, OrdersEventType, OrdersEventPayload, } from './pubsub/topics/orders/types';
|
|
244
259
|
export type { RefundCreatedPayload, RefundUpdatedPayload, RefundActiveSetPayload, RefundActiveGetPayload, RefundCreatedEvent, RefundUpdatedEvent, RefundActiveSetEvent, RefundActiveGetEvent, RefundsEventType, RefundsEventPayload, } from './pubsub/topics/refunds/types';
|
|
@@ -249,6 +264,7 @@ export type { SessionActiveSetPayload, SessionActiveGetPayload, SessionActiveSet
|
|
|
249
264
|
export type { UserActiveSetPayload, UserActiveGetPayload, UserActiveSetEvent, UserActiveGetEvent, UserCreatedPayload, UserCreatedEvent, UserUpdatedPayload, UserUpdatedEvent, UsersEventType, UsersEventPayload, } from './pubsub/topics/users/types';
|
|
250
265
|
export type { VariantCreatedPayload, VariantCreatedEvent, VariantUpdatedPayload, VariantUpdatedEvent, VariantsEventType, VariantsEventPayload, } from './pubsub/topics/variants/types';
|
|
251
266
|
export type { TransactionCreatedPayload, TransactionCreatedEvent, TransactionUpdatedPayload, TransactionUpdatedEvent, TransactionsEventType, TransactionsEventPayload, } from './pubsub/topics/transactions/types';
|
|
267
|
+
export type { BookingCreatedPayload, BookingCreatedEvent, BookingUpdatedPayload, BookingUpdatedEvent, BookingSetupChangedPayload, BookingSetupChangedEvent, BookingsEventType, BookingsEventPayload, } from './pubsub/topics/bookings/types';
|
|
252
268
|
export type { CategoryCreatedPayload, CategoryCreatedEvent, CategoryUpdatedPayload, CategoryUpdatedEvent, CategoriesEventType, CategoriesEventPayload, } from './pubsub/topics/categories/types';
|
|
253
269
|
export type { AttributeCreatedPayload, AttributeCreatedEvent, AttributeUpdatedPayload, AttributeUpdatedEvent, AttributesEventType, AttributesEventPayload, } from './pubsub/topics/attributes/types';
|
|
254
270
|
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';
|
|
@@ -133,6 +140,13 @@ export const command = {
|
|
|
133
140
|
exampleFunction,
|
|
134
141
|
generateAPIKey,
|
|
135
142
|
getProducts,
|
|
143
|
+
getBookingResources,
|
|
144
|
+
getBookingAvailability,
|
|
145
|
+
getBookings,
|
|
146
|
+
holdBooking,
|
|
147
|
+
addBookingToCart,
|
|
148
|
+
removeBookingFromCart,
|
|
149
|
+
cancelBooking,
|
|
136
150
|
addCustomSale,
|
|
137
151
|
editCustomSale,
|
|
138
152
|
addNonRevenueItem,
|
|
@@ -293,6 +307,7 @@ export { variantsTopic } from './pubsub/topics/variants';
|
|
|
293
307
|
export { transactionsTopic } from './pubsub/topics/transactions';
|
|
294
308
|
export { categoriesTopic } from './pubsub/topics/categories';
|
|
295
309
|
export { attributesTopic } from './pubsub/topics/attributes';
|
|
310
|
+
export { bookingsTopic } from './pubsub/topics/bookings';
|
|
296
311
|
// Export Custom Tables Types
|
|
297
312
|
export { AttributeType } from './common-types/attribute-type';
|
|
298
313
|
// State Machine Fragments
|
|
@@ -39,6 +39,13 @@ import { mockGetCurrentCart } from '../../actions/get-current-cart/mock';
|
|
|
39
39
|
import { mockGetCustomers } from '../../actions/get-customers/mock';
|
|
40
40
|
import { mockGetOrders } from '../../actions/get-orders/mock';
|
|
41
41
|
import { mockGetProducts } from '../../actions/get-products/mock';
|
|
42
|
+
import { mockGetBookingResources } from '../../actions/get-booking-resources/mock';
|
|
43
|
+
import { mockGetBookingAvailability } from '../../actions/get-booking-availability/mock';
|
|
44
|
+
import { mockGetBookings } from '../../actions/get-bookings/mock';
|
|
45
|
+
import { mockHoldBooking } from '../../actions/hold-booking/mock';
|
|
46
|
+
import { mockAddBookingToCart } from '../../actions/add-booking-to-cart/mock';
|
|
47
|
+
import { mockRemoveBookingFromCart } from '../../actions/remove-booking-from-cart/mock';
|
|
48
|
+
import { mockCancelBooking } from '../../actions/cancel-booking/mock';
|
|
42
49
|
import { mockGetRefunds } from '../../actions/get-refunds/mock';
|
|
43
50
|
import { mockGetTaxTables } from '../../actions/get-tax-tables/mock';
|
|
44
51
|
import { mockGetRemainingRefundableQuantities } from '../../actions/get-remaining-refundable-quantities/mock';
|
|
@@ -133,6 +140,13 @@ export const RENDER_MOCKS = {
|
|
|
133
140
|
getCustomers: mockGetCustomers,
|
|
134
141
|
getOrders: mockGetOrders,
|
|
135
142
|
getProducts: mockGetProducts,
|
|
143
|
+
getBookingResources: mockGetBookingResources,
|
|
144
|
+
getBookingAvailability: mockGetBookingAvailability,
|
|
145
|
+
getBookings: mockGetBookings,
|
|
146
|
+
holdBooking: mockHoldBooking,
|
|
147
|
+
addBookingToCart: mockAddBookingToCart,
|
|
148
|
+
removeBookingFromCart: mockRemoveBookingFromCart,
|
|
149
|
+
cancelBooking: mockCancelBooking,
|
|
136
150
|
getRefunds: mockGetRefunds,
|
|
137
151
|
getTaxTables: mockGetTaxTables,
|
|
138
152
|
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, 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 } 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 } 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;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './booking-created/types';
|
|
2
|
+
export * from './booking-updated/types';
|
|
3
|
+
export * from './booking-setup-changed/types';
|
|
4
|
+
import type { BookingCreatedPayload } from './booking-created/types';
|
|
5
|
+
import type { BookingUpdatedPayload } from './booking-updated/types';
|
|
6
|
+
import type { BookingSetupChangedPayload } from './booking-setup-changed/types';
|
|
7
|
+
export type BookingsEventPayload = BookingCreatedPayload | BookingUpdatedPayload | BookingSetupChangedPayload;
|
|
8
|
+
export type BookingsEventType = 'booking-created' | 'booking-updated' | 'booking-setup-changed';
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
* Pub/Sub Topics
|
|
3
3
|
* Export all available topics and their types
|
|
4
4
|
*/
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
17
|
-
export * from
|
|
18
|
-
export * from
|
|
19
|
-
export * from
|
|
20
|
-
export * from
|
|
5
|
+
export * from './customers';
|
|
6
|
+
export * from './orders';
|
|
7
|
+
export * from './bookings';
|
|
8
|
+
export * from './refunds';
|
|
9
|
+
export * from './products';
|
|
10
|
+
export * from './cart';
|
|
11
|
+
export * from './payments';
|
|
12
|
+
export * from './custom-tables';
|
|
13
|
+
export * from './print';
|
|
14
|
+
export * from './outlet';
|
|
15
|
+
export * from './station';
|
|
16
|
+
export * from './session';
|
|
17
|
+
export * from './users';
|
|
18
|
+
export * from './variants';
|
|
19
|
+
export * from './transactions';
|
|
20
|
+
export * from './categories';
|
|
21
|
+
export * from './attributes';
|
|
@@ -2,19 +2,20 @@
|
|
|
2
2
|
* Pub/Sub Topics
|
|
3
3
|
* Export all available topics and their types
|
|
4
4
|
*/
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from
|
|
11
|
-
export * from
|
|
12
|
-
export * from
|
|
13
|
-
export * from
|
|
14
|
-
export * from
|
|
15
|
-
export * from
|
|
16
|
-
export * from
|
|
17
|
-
export * from
|
|
18
|
-
export * from
|
|
19
|
-
export * from
|
|
20
|
-
export * from
|
|
5
|
+
export * from './customers';
|
|
6
|
+
export * from './orders';
|
|
7
|
+
export * from './bookings';
|
|
8
|
+
export * from './refunds';
|
|
9
|
+
export * from './products';
|
|
10
|
+
export * from './cart';
|
|
11
|
+
export * from './payments';
|
|
12
|
+
export * from './custom-tables';
|
|
13
|
+
export * from './print';
|
|
14
|
+
export * from './outlet';
|
|
15
|
+
export * from './station';
|
|
16
|
+
export * from './session';
|
|
17
|
+
export * from './users';
|
|
18
|
+
export * from './variants';
|
|
19
|
+
export * from './transactions';
|
|
20
|
+
export * from './categories';
|
|
21
|
+
export * from './attributes';
|
|
@@ -15,6 +15,7 @@ import { VariantsEventType, VariantsEventPayload } from "./variants/types";
|
|
|
15
15
|
import { TransactionsEventType, TransactionsEventPayload } from "./transactions/types";
|
|
16
16
|
import { CategoriesEventType, CategoriesEventPayload } from "./categories/types";
|
|
17
17
|
import { AttributesEventType, AttributesEventPayload } from "./attributes/types";
|
|
18
|
+
import { BookingsEventType, BookingsEventPayload } from "./bookings/types";
|
|
18
19
|
export interface TopicEventPayloadMap {
|
|
19
20
|
customers: Record<CustomersEventType, CustomersEventPayload>;
|
|
20
21
|
orders: Record<OrdersEventType, OrdersEventPayload>;
|
|
@@ -33,4 +34,5 @@ export interface TopicEventPayloadMap {
|
|
|
33
34
|
transactions: Record<TransactionsEventType, TransactionsEventPayload>;
|
|
34
35
|
categories: Record<CategoriesEventType, CategoriesEventPayload>;
|
|
35
36
|
attributes: Record<AttributesEventType, AttributesEventPayload>;
|
|
37
|
+
bookings: Record<BookingsEventType, BookingsEventPayload>;
|
|
36
38
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@final-commerce/command-frame",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0-staging.1",
|
|
4
4
|
"description": "Commands Frame library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"ignoreBranchesMissingTickets": true
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@final-commerce/common": "2.
|
|
60
|
+
"@final-commerce/common": "2.3.0-staging.1"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@commitlint/cli": "^19.0.0",
|