@final-commerce/command-frame 0.7.0-staging.3 → 0.7.0-staging.5
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.
|
@@ -1,8 +1,44 @@
|
|
|
1
|
+
import { ReservationStatus } from '@final-commerce/common';
|
|
2
|
+
import { MOCK_CART, MOCK_PRODUCTS, mockPublishEvent } from '../../demo/database';
|
|
1
3
|
import { mockHoldBooking } from '../hold-booking/mock';
|
|
2
4
|
export const mockAddBookingToCart = async (params) => {
|
|
3
5
|
console.log('[Mock] addBookingToCart called', params);
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
+
// One call, two effects — the window is claimed AND the service is in the cart. The claim goes
|
|
7
|
+
// first and its refusal propagates: a cart line for a window somebody else took is worse than
|
|
8
|
+
// no line at all.
|
|
6
9
|
const { booking } = await mockHoldBooking(params);
|
|
7
|
-
|
|
10
|
+
const product = MOCK_PRODUCTS.find(({ _id }) => _id === params.productId);
|
|
11
|
+
const variant = params.variantId
|
|
12
|
+
? product?.variants?.find(({ _id }) => _id === params.variantId)
|
|
13
|
+
: product?.variants?.[0];
|
|
14
|
+
const price = variant?.price ?? product?.minPrice ?? 0;
|
|
15
|
+
const reservation = {
|
|
16
|
+
internalId: `res_${booking.id}`,
|
|
17
|
+
bookingId: booking.id,
|
|
18
|
+
productId: params.productId,
|
|
19
|
+
variantId: variant?._id ?? null,
|
|
20
|
+
resourceId: params.resourceId,
|
|
21
|
+
name: product?.name ?? 'Booking',
|
|
22
|
+
resourceName: booking.resourceName,
|
|
23
|
+
price,
|
|
24
|
+
quantity: 1,
|
|
25
|
+
total: price,
|
|
26
|
+
taxTableId: product?.taxTable,
|
|
27
|
+
startAt: booking.startAt,
|
|
28
|
+
endAt: booking.endAt,
|
|
29
|
+
bufferEndAt: booking.bufferEndAt,
|
|
30
|
+
status: ReservationStatus.HELD,
|
|
31
|
+
expiresAt: booking.expiresAt,
|
|
32
|
+
};
|
|
33
|
+
if (!MOCK_CART.reservations)
|
|
34
|
+
MOCK_CART.reservations = [];
|
|
35
|
+
MOCK_CART.reservations.push(reservation);
|
|
36
|
+
MOCK_CART.subtotal += price;
|
|
37
|
+
MOCK_CART.total += price;
|
|
38
|
+
MOCK_CART.amountToBeCharged = MOCK_CART.total;
|
|
39
|
+
MOCK_CART.remainingBalance = MOCK_CART.total;
|
|
40
|
+
// The cart topic, not the bookings one: a screen that only watches bookings still has to
|
|
41
|
+
// repaint its cart, and every other cart mutation announces itself the same way.
|
|
42
|
+
mockPublishEvent('cart', 'reservation-added', { reservation });
|
|
43
|
+
return { booking, reservationInternalId: reservation.internalId, timestamp: new Date().toISOString() };
|
|
8
44
|
};
|
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
import { MOCK_BOOKINGS } from '../../demo/database';
|
|
1
|
+
import { MOCK_BOOKINGS, MOCK_CART, mockPublishEvent } from '../../demo/database';
|
|
2
2
|
export const mockRemoveBookingFromCart = async (params) => {
|
|
3
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
|
+
}
|
|
4
15
|
// The hold has to go back, or the mock is a trap: `addBookingToCart` pushes into the very list
|
|
5
16
|
// availability reads, so add → remove → add the same slot used to refuse forever with "that
|
|
6
|
-
// window has just been taken". The reservation id
|
|
7
|
-
|
|
8
|
-
const bookingId = params.reservationInternalId.replace(/^res_/, '');
|
|
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_/, '');
|
|
9
19
|
const index = MOCK_BOOKINGS.findIndex(({ id }) => id === bookingId);
|
|
10
20
|
const [released] = index >= 0 ? MOCK_BOOKINGS.splice(index, 1) : [];
|
|
11
21
|
return {
|
package/dist/demo/database.d.ts
CHANGED
|
@@ -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;
|
package/dist/demo/database.js
CHANGED
|
@@ -688,6 +688,7 @@ export let MOCK_CART = {
|
|
|
688
688
|
remainingBalance: 0,
|
|
689
689
|
products: [],
|
|
690
690
|
customSales: [],
|
|
691
|
+
reservations: [],
|
|
691
692
|
nonRevenueItems: [],
|
|
692
693
|
customer: null,
|
|
693
694
|
};
|
|
@@ -708,6 +709,7 @@ export const resetMockCart = () => {
|
|
|
708
709
|
remainingBalance: 0,
|
|
709
710
|
products: [],
|
|
710
711
|
customSales: [],
|
|
712
|
+
reservations: [],
|
|
711
713
|
nonRevenueItems: [],
|
|
712
714
|
customer: null,
|
|
713
715
|
};
|
|
@@ -752,6 +754,12 @@ export function setMockDatabase(config) {
|
|
|
752
754
|
if (config.parkedOrders !== undefined) {
|
|
753
755
|
MOCK_PARKED_ORDERS.splice(0, MOCK_PARKED_ORDERS.length, ...config.parkedOrders);
|
|
754
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
|
+
}
|
|
755
763
|
if (MOCK_OUTLETS.length > 0) {
|
|
756
764
|
Object.assign(MOCK_OUTLET_MAIN, MOCK_OUTLETS[0]);
|
|
757
765
|
if (MOCK_OUTLET_MAIN.id === undefined && MOCK_OUTLET_MAIN._id !== undefined) {
|
|
@@ -888,6 +896,30 @@ export const createOrderFromCart = (paymentType, amount, processor = 'cash') =>
|
|
|
888
896
|
billing: MOCK_CART.customer?.billing || null,
|
|
889
897
|
shipping: MOCK_CART.customer?.shipping || null,
|
|
890
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
|
+
// `expiresAt` deliberately does not come along: a paid booking has no
|
|
920
|
+
// clock left to run out, which is what CONFIRMED means.
|
|
921
|
+
status: ReservationStatus.CONFIRMED,
|
|
922
|
+
})),
|
|
891
923
|
customSales: [],
|
|
892
924
|
balance: 0,
|
|
893
925
|
user: employeeUser,
|
|
@@ -935,9 +967,11 @@ const SLOT_MINUTES = 30;
|
|
|
935
967
|
const BUFFER_MINUTES = 5;
|
|
936
968
|
const OPEN_HOUR = 9;
|
|
937
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.
|
|
938
972
|
export const MOCK_BOOKING_RESOURCES = [
|
|
939
|
-
{ id: '
|
|
940
|
-
{ id: '
|
|
973
|
+
{ id: 'res_room_1', name: 'Room 1', kind: BookingResourceKind.ROOM },
|
|
974
|
+
{ id: 'res_room_2', name: 'Room 2', kind: BookingResourceKind.ROOM },
|
|
941
975
|
];
|
|
942
976
|
const at = (dayOffset, hour, minute = 0) => {
|
|
943
977
|
const date = new Date();
|
|
@@ -958,9 +992,9 @@ const booking = (id, resourceId, start, status, customerName) => ({
|
|
|
958
992
|
customerName,
|
|
959
993
|
});
|
|
960
994
|
export const MOCK_BOOKINGS = [
|
|
961
|
-
booking('bk_1', '
|
|
962
|
-
booking('bk_2', '
|
|
963
|
-
booking('bk_3', '
|
|
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'),
|
|
964
998
|
];
|
|
965
999
|
/** Live = confirmed, or held and not yet expired. An expired hold occupies nothing. */
|
|
966
1000
|
export const mockLiveBookings = () => MOCK_BOOKINGS.filter(({ status, expiresAt }) => status === ReservationStatus.CONFIRMED ||
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@final-commerce/command-frame",
|
|
3
|
-
"version": "0.7.0-staging.
|
|
3
|
+
"version": "0.7.0-staging.5",
|
|
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.3.0-staging.
|
|
60
|
+
"@final-commerce/common": "2.3.0-staging.4"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
63
|
"@commitlint/cli": "^19.0.0",
|