@voyantjs/bookings 0.52.1 → 0.52.3
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/README.md +16 -0
- package/dist/action-ledger-capabilities.d.ts +306 -0
- package/dist/action-ledger-capabilities.d.ts.map +1 -0
- package/dist/action-ledger-capabilities.js +92 -0
- package/dist/action-ledger-drift-remediation.d.ts +30 -0
- package/dist/action-ledger-drift-remediation.d.ts.map +1 -0
- package/dist/action-ledger-drift-remediation.js +85 -0
- package/dist/action-ledger-drift.d.ts +29 -0
- package/dist/action-ledger-drift.d.ts.map +1 -0
- package/dist/action-ledger-drift.js +217 -0
- package/dist/availability-ref.d.ts +2 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/routes-groups.d.ts +13 -13
- package/dist/routes-public.d.ts +9 -9
- package/dist/routes-shared.d.ts +13 -4
- package/dist/routes-shared.d.ts.map +1 -1
- package/dist/routes.d.ts +347 -663
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +1191 -49
- package/dist/schema-core.d.ts +3 -3
- package/dist/schema-items.d.ts +3 -3
- package/dist/service-public.d.ts +24 -24
- package/dist/service.d.ts +62 -45
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +166 -14
- package/dist/status-dispatch.d.ts +3 -1
- package/dist/status-dispatch.d.ts.map +1 -1
- package/dist/status-dispatch.js +18 -3
- package/dist/validation-public.d.ts +12 -12
- package/dist/validation-shared.d.ts +4 -4
- package/dist/validation.d.ts +41 -19
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +39 -0
- package/package.json +22 -6
package/dist/service.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { appendActionLedgerMutation, } from "@voyantjs/action-ledger";
|
|
1
2
|
import { and, asc, desc, eq, exists, gte, ilike, inArray, isNotNull, lte, ne, or, sql, } from "drizzle-orm";
|
|
3
|
+
import { BOOKING_STATUS_CAPABILITIES } from "./action-ledger-capabilities.js";
|
|
2
4
|
import { availabilitySlotsRef } from "./availability-ref.js";
|
|
3
5
|
import { exchangeRatesRef } from "./markets-ref.js";
|
|
4
6
|
import { applyTravelDetailSnapshot, } from "./pii.js";
|
|
@@ -37,6 +39,33 @@ function pickTravelDetailFields(data) {
|
|
|
37
39
|
allocations: data.allocations,
|
|
38
40
|
};
|
|
39
41
|
}
|
|
42
|
+
async function appendBookingStatusMutationLedger(db, runtime, input) {
|
|
43
|
+
if (!runtime.actionLedgerContext)
|
|
44
|
+
return;
|
|
45
|
+
await appendActionLedgerMutation(db, {
|
|
46
|
+
context: runtime.actionLedgerContext,
|
|
47
|
+
actionName: input.actionName,
|
|
48
|
+
actionVersion: "v1",
|
|
49
|
+
actionKind: "update",
|
|
50
|
+
status: "succeeded",
|
|
51
|
+
evaluatedRisk: input.evaluatedRisk ?? "medium",
|
|
52
|
+
targetType: "booking",
|
|
53
|
+
targetId: input.bookingId,
|
|
54
|
+
routeOrToolName: input.routeOrToolName,
|
|
55
|
+
capabilityId: input.capabilityId,
|
|
56
|
+
capabilityVersion: "v1",
|
|
57
|
+
authorizationSource: runtime.actionLedgerAuthorizationSource ?? "bookings.status.route",
|
|
58
|
+
causationActionId: runtime.actionLedgerCausationActionId ?? null,
|
|
59
|
+
approvalId: runtime.actionLedgerApprovalId ?? null,
|
|
60
|
+
idempotencyScope: runtime.actionLedgerIdempotencyScope ?? null,
|
|
61
|
+
idempotencyKey: runtime.actionLedgerIdempotencyKey ?? null,
|
|
62
|
+
idempotencyFingerprint: runtime.actionLedgerIdempotencyFingerprint ?? null,
|
|
63
|
+
mutationDetail: {
|
|
64
|
+
summary: `Booking status changed from ${input.fromStatus} to ${input.toStatus}`,
|
|
65
|
+
reversalKind: "none",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
}
|
|
40
69
|
/** Stable string identifier for the event. */
|
|
41
70
|
export const AVAILABILITY_SLOT_CHANGED_EVENT = "availability.slot.changed";
|
|
42
71
|
/**
|
|
@@ -577,7 +606,7 @@ async function lockAvailabilitySlot(db, slotId) {
|
|
|
577
606
|
FROM ${availabilitySlotsRef}
|
|
578
607
|
WHERE ${availabilitySlotsRef.id} = ${slotId}
|
|
579
608
|
FOR UPDATE`);
|
|
580
|
-
const row = rows[0];
|
|
609
|
+
const row = toRows(rows)[0];
|
|
581
610
|
if (!row) {
|
|
582
611
|
return null;
|
|
583
612
|
}
|
|
@@ -699,7 +728,7 @@ async function loadResourceCapacityViolations(db, travelerId, allocations) {
|
|
|
699
728
|
AND ba.status IN ('held', 'confirmed', 'fulfilled')
|
|
700
729
|
AND btd.traveler_id <> ${travelerId}
|
|
701
730
|
`);
|
|
702
|
-
const existingAssigned = counts[0]?.count ?? 0;
|
|
731
|
+
const existingAssigned = toRows(counts)[0]?.count ?? 0;
|
|
703
732
|
if (existingAssigned + 1 > resource.capacity) {
|
|
704
733
|
violations.push({
|
|
705
734
|
slotId: resource.slot_id,
|
|
@@ -1257,6 +1286,25 @@ const AGGREGATE_ACTIVE_STATUSES = [
|
|
|
1257
1286
|
"in_progress",
|
|
1258
1287
|
"completed",
|
|
1259
1288
|
];
|
|
1289
|
+
/**
|
|
1290
|
+
* Normalize `db.execute(sql)` results across drizzle drivers.
|
|
1291
|
+
* `drizzle-orm/postgres-js` returns rows directly (an array); the
|
|
1292
|
+
* `node-postgres` + `neon-serverless` drivers (used by the operator
|
|
1293
|
+
* template against local pg and Neon WS respectively) wrap them in a
|
|
1294
|
+
* `QueryResult<T>` object with `.rows`. Casting straight to
|
|
1295
|
+
* `Array<T>` and indexing produced silent `undefined`s on the wrapped
|
|
1296
|
+
* shape — the symptom was "Booking not found" on freshly-created
|
|
1297
|
+
* bookings whose status-change followup hit a FOR UPDATE SELECT.
|
|
1298
|
+
*/
|
|
1299
|
+
function toRows(result) {
|
|
1300
|
+
if (Array.isArray(result))
|
|
1301
|
+
return result;
|
|
1302
|
+
if (result && typeof result === "object" && "rows" in result) {
|
|
1303
|
+
const rows = result.rows;
|
|
1304
|
+
return Array.isArray(rows) ? rows : [];
|
|
1305
|
+
}
|
|
1306
|
+
return [];
|
|
1307
|
+
}
|
|
1260
1308
|
export const bookingsService = {
|
|
1261
1309
|
/**
|
|
1262
1310
|
* Pre-aggregated dashboard numbers for the admin bookings surface. Replaces
|
|
@@ -1533,13 +1581,53 @@ export const bookingsService = {
|
|
|
1533
1581
|
if (data.itemLines && requestedItemLines.length !== data.itemLines.length) {
|
|
1534
1582
|
return null;
|
|
1535
1583
|
}
|
|
1584
|
+
const initialStatus = data.initialStatus ?? "draft";
|
|
1585
|
+
// Map the booking lifecycle status onto the booking-item lifecycle.
|
|
1586
|
+
// Items don't have an `awaiting_payment` state — when the booking is
|
|
1587
|
+
// committed (confirmed / awaiting payment / in progress) the items
|
|
1588
|
+
// are sold, so they land in `confirmed`. Holds, cancellations,
|
|
1589
|
+
// expirations, and completions cascade their analog. Draft falls
|
|
1590
|
+
// through as draft.
|
|
1591
|
+
const initialItemStatus = initialStatus === "on_hold"
|
|
1592
|
+
? "on_hold"
|
|
1593
|
+
: initialStatus === "confirmed" ||
|
|
1594
|
+
initialStatus === "in_progress" ||
|
|
1595
|
+
initialStatus === "awaiting_payment"
|
|
1596
|
+
? "confirmed"
|
|
1597
|
+
: initialStatus === "cancelled"
|
|
1598
|
+
? "cancelled"
|
|
1599
|
+
: initialStatus === "expired"
|
|
1600
|
+
? "expired"
|
|
1601
|
+
: initialStatus === "completed"
|
|
1602
|
+
? "fulfilled"
|
|
1603
|
+
: "draft";
|
|
1604
|
+
const now = new Date();
|
|
1536
1605
|
const [booking] = await db
|
|
1537
1606
|
.insert(bookings)
|
|
1538
1607
|
.values({
|
|
1539
1608
|
bookingNumber: data.bookingNumber,
|
|
1540
|
-
status:
|
|
1609
|
+
status: initialStatus,
|
|
1610
|
+
// Mirror the lifecycle timestamps that overrideBookingStatus
|
|
1611
|
+
// stamps when the status transition happens after-the-fact, so
|
|
1612
|
+
// a booking that lands in `confirmed` straight from create is
|
|
1613
|
+
// indistinguishable downstream from one that was flipped via
|
|
1614
|
+
// the verb endpoint.
|
|
1615
|
+
confirmedAt: initialStatus === "confirmed" ? now : null,
|
|
1541
1616
|
personId: data.personId ?? null,
|
|
1542
1617
|
organizationId: data.organizationId ?? null,
|
|
1618
|
+
// Billing-contact snapshot — captured at create time so the
|
|
1619
|
+
// booking detail page renders the right payer even if the
|
|
1620
|
+
// CRM person/org record changes (or is deleted) later.
|
|
1621
|
+
contactFirstName: data.contactFirstName ?? null,
|
|
1622
|
+
contactLastName: data.contactLastName ?? null,
|
|
1623
|
+
contactEmail: data.contactEmail ?? null,
|
|
1624
|
+
contactPhone: data.contactPhone ?? null,
|
|
1625
|
+
contactPreferredLanguage: data.contactPreferredLanguage ?? null,
|
|
1626
|
+
contactCountry: data.contactCountry ?? null,
|
|
1627
|
+
contactRegion: data.contactRegion ?? null,
|
|
1628
|
+
contactCity: data.contactCity ?? null,
|
|
1629
|
+
contactAddressLine1: data.contactAddressLine1 ?? null,
|
|
1630
|
+
contactPostalCode: data.contactPostalCode ?? null,
|
|
1543
1631
|
sellCurrency: product.sellCurrency,
|
|
1544
1632
|
sellAmountCents: effectiveSellAmountCents,
|
|
1545
1633
|
priceOverride,
|
|
@@ -1589,7 +1677,7 @@ export const bookingsService = {
|
|
|
1589
1677
|
title: line.title?.trim() || unit.name,
|
|
1590
1678
|
description: line.description ?? unit.description,
|
|
1591
1679
|
itemType: "unit",
|
|
1592
|
-
status:
|
|
1680
|
+
status: initialItemStatus,
|
|
1593
1681
|
quantity: line.quantity,
|
|
1594
1682
|
sellCurrency: product.sellCurrency,
|
|
1595
1683
|
unitSellAmountCents: line.unitSellAmountCents ?? null,
|
|
@@ -1616,7 +1704,7 @@ export const bookingsService = {
|
|
|
1616
1704
|
title: unit.name,
|
|
1617
1705
|
description: unit.description,
|
|
1618
1706
|
itemType: "unit",
|
|
1619
|
-
status:
|
|
1707
|
+
status: initialItemStatus,
|
|
1620
1708
|
quantity,
|
|
1621
1709
|
sellCurrency: product.sellCurrency,
|
|
1622
1710
|
unitSellAmountCents: singleSeedItem &&
|
|
@@ -1644,7 +1732,7 @@ export const bookingsService = {
|
|
|
1644
1732
|
title: option?.name ?? product.name,
|
|
1645
1733
|
description: product.description,
|
|
1646
1734
|
itemType: "unit",
|
|
1647
|
-
status:
|
|
1735
|
+
status: initialItemStatus,
|
|
1648
1736
|
quantity: 1,
|
|
1649
1737
|
sellCurrency: product.sellCurrency,
|
|
1650
1738
|
unitSellAmountCents: effectiveSellAmountCents ?? null,
|
|
@@ -2092,7 +2180,7 @@ export const bookingsService = {
|
|
|
2092
2180
|
FROM ${bookings}
|
|
2093
2181
|
WHERE ${bookings.id} = ${id}
|
|
2094
2182
|
FOR UPDATE`);
|
|
2095
|
-
const booking = rows[0];
|
|
2183
|
+
const booking = toRows(rows)[0];
|
|
2096
2184
|
if (!booking) {
|
|
2097
2185
|
throw new BookingServiceError("not_found");
|
|
2098
2186
|
}
|
|
@@ -2147,6 +2235,14 @@ export const bookingsService = {
|
|
|
2147
2235
|
content: data.note,
|
|
2148
2236
|
});
|
|
2149
2237
|
}
|
|
2238
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2239
|
+
actionName: "booking.status.confirm",
|
|
2240
|
+
routeOrToolName: "bookings.confirm",
|
|
2241
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.confirm.id,
|
|
2242
|
+
bookingId: id,
|
|
2243
|
+
fromStatus: booking.status,
|
|
2244
|
+
toStatus: "confirmed",
|
|
2245
|
+
});
|
|
2150
2246
|
return { status: "ok", booking: row ?? null };
|
|
2151
2247
|
});
|
|
2152
2248
|
// Emit AFTER the transaction commits so subscribers can't observe a
|
|
@@ -2157,6 +2253,7 @@ export const bookingsService = {
|
|
|
2157
2253
|
bookingId: result.booking.id,
|
|
2158
2254
|
bookingNumber: result.booking.bookingNumber,
|
|
2159
2255
|
actorId: userId ?? null,
|
|
2256
|
+
suppressNotifications: data.suppressNotifications === true,
|
|
2160
2257
|
}, { category: "domain", source: "service" });
|
|
2161
2258
|
}
|
|
2162
2259
|
return result;
|
|
@@ -2176,7 +2273,7 @@ export const bookingsService = {
|
|
|
2176
2273
|
FROM ${bookings}
|
|
2177
2274
|
WHERE ${bookings.id} = ${id}
|
|
2178
2275
|
FOR UPDATE`);
|
|
2179
|
-
const booking = rows[0];
|
|
2276
|
+
const booking = toRows(rows)[0];
|
|
2180
2277
|
if (!booking) {
|
|
2181
2278
|
throw new BookingServiceError("not_found");
|
|
2182
2279
|
}
|
|
@@ -2252,6 +2349,14 @@ export const bookingsService = {
|
|
|
2252
2349
|
content: data.note,
|
|
2253
2350
|
});
|
|
2254
2351
|
}
|
|
2352
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2353
|
+
actionName: "booking.status.expire",
|
|
2354
|
+
routeOrToolName: "bookings.expire",
|
|
2355
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.expire.id,
|
|
2356
|
+
bookingId: id,
|
|
2357
|
+
fromStatus: booking.status,
|
|
2358
|
+
toStatus: "expired",
|
|
2359
|
+
});
|
|
2255
2360
|
return { status: "ok", booking: row ?? null };
|
|
2256
2361
|
});
|
|
2257
2362
|
if (result.status === "ok" && result.booking) {
|
|
@@ -2278,7 +2383,7 @@ export const bookingsService = {
|
|
|
2278
2383
|
FROM ${bookings}
|
|
2279
2384
|
WHERE ${bookings.id} = ${id}
|
|
2280
2385
|
FOR UPDATE`);
|
|
2281
|
-
const booking = rows[0];
|
|
2386
|
+
const booking = toRows(rows)[0];
|
|
2282
2387
|
if (!booking) {
|
|
2283
2388
|
throw new BookingServiceError("not_found");
|
|
2284
2389
|
}
|
|
@@ -2329,7 +2434,7 @@ export const bookingsService = {
|
|
|
2329
2434
|
FROM ${bookings}
|
|
2330
2435
|
WHERE ${bookings.id} = ${id}
|
|
2331
2436
|
FOR UPDATE`);
|
|
2332
|
-
const booking = rows[0];
|
|
2437
|
+
const booking = toRows(rows)[0];
|
|
2333
2438
|
if (!booking) {
|
|
2334
2439
|
throw new BookingServiceError("not_found");
|
|
2335
2440
|
}
|
|
@@ -2433,7 +2538,7 @@ export const bookingsService = {
|
|
|
2433
2538
|
FROM ${bookings}
|
|
2434
2539
|
WHERE ${bookings.id} = ${id}
|
|
2435
2540
|
FOR UPDATE`);
|
|
2436
|
-
const booking = rows[0];
|
|
2541
|
+
const booking = toRows(rows)[0];
|
|
2437
2542
|
if (!booking) {
|
|
2438
2543
|
throw new BookingServiceError("not_found");
|
|
2439
2544
|
}
|
|
@@ -2492,6 +2597,15 @@ export const bookingsService = {
|
|
|
2492
2597
|
}
|
|
2493
2598
|
// Clean up any booking-group membership (dissolve if ≤1 active members remain).
|
|
2494
2599
|
await cleanupGroupOnBookingCancelled(tx, id);
|
|
2600
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2601
|
+
actionName: "booking.status.cancel",
|
|
2602
|
+
routeOrToolName: "bookings.cancel",
|
|
2603
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.cancel.id,
|
|
2604
|
+
bookingId: id,
|
|
2605
|
+
fromStatus: booking.status,
|
|
2606
|
+
toStatus: "cancelled",
|
|
2607
|
+
evaluatedRisk: "high",
|
|
2608
|
+
});
|
|
2495
2609
|
return { status: "ok", booking: row ?? null, previousStatus };
|
|
2496
2610
|
});
|
|
2497
2611
|
if (result.status === "ok" && result.booking) {
|
|
@@ -2519,7 +2633,7 @@ export const bookingsService = {
|
|
|
2519
2633
|
FROM ${bookings}
|
|
2520
2634
|
WHERE ${bookings.id} = ${id}
|
|
2521
2635
|
FOR UPDATE`);
|
|
2522
|
-
const booking = rows[0];
|
|
2636
|
+
const booking = toRows(rows)[0];
|
|
2523
2637
|
if (!booking) {
|
|
2524
2638
|
throw new BookingServiceError("not_found");
|
|
2525
2639
|
}
|
|
@@ -2548,6 +2662,14 @@ export const bookingsService = {
|
|
|
2548
2662
|
content: data.note,
|
|
2549
2663
|
});
|
|
2550
2664
|
}
|
|
2665
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2666
|
+
actionName: "booking.status.start",
|
|
2667
|
+
routeOrToolName: "bookings.start",
|
|
2668
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.start.id,
|
|
2669
|
+
bookingId: id,
|
|
2670
|
+
fromStatus: booking.status,
|
|
2671
|
+
toStatus: "in_progress",
|
|
2672
|
+
});
|
|
2551
2673
|
return { status: "ok", booking: row ?? null };
|
|
2552
2674
|
});
|
|
2553
2675
|
if (result.status === "ok" && result.booking) {
|
|
@@ -2573,7 +2695,7 @@ export const bookingsService = {
|
|
|
2573
2695
|
FROM ${bookings}
|
|
2574
2696
|
WHERE ${bookings.id} = ${id}
|
|
2575
2697
|
FOR UPDATE`);
|
|
2576
|
-
const booking = rows[0];
|
|
2698
|
+
const booking = toRows(rows)[0];
|
|
2577
2699
|
if (!booking) {
|
|
2578
2700
|
throw new BookingServiceError("not_found");
|
|
2579
2701
|
}
|
|
@@ -2610,6 +2732,14 @@ export const bookingsService = {
|
|
|
2610
2732
|
content: data.note,
|
|
2611
2733
|
});
|
|
2612
2734
|
}
|
|
2735
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2736
|
+
actionName: "booking.status.complete",
|
|
2737
|
+
routeOrToolName: "bookings.complete",
|
|
2738
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.complete.id,
|
|
2739
|
+
bookingId: id,
|
|
2740
|
+
fromStatus: booking.status,
|
|
2741
|
+
toStatus: "completed",
|
|
2742
|
+
});
|
|
2613
2743
|
return { status: "ok", booking: row ?? null };
|
|
2614
2744
|
});
|
|
2615
2745
|
if (result.status === "ok" && result.booking) {
|
|
@@ -2642,7 +2772,7 @@ export const bookingsService = {
|
|
|
2642
2772
|
FROM ${bookings}
|
|
2643
2773
|
WHERE ${bookings.id} = ${id}
|
|
2644
2774
|
FOR UPDATE`);
|
|
2645
|
-
const booking = rows[0];
|
|
2775
|
+
const booking = toRows(rows)[0];
|
|
2646
2776
|
if (!booking) {
|
|
2647
2777
|
throw new BookingServiceError("not_found");
|
|
2648
2778
|
}
|
|
@@ -2678,6 +2808,15 @@ export const bookingsService = {
|
|
|
2678
2808
|
content: data.note,
|
|
2679
2809
|
});
|
|
2680
2810
|
}
|
|
2811
|
+
await appendBookingStatusMutationLedger(tx, runtime, {
|
|
2812
|
+
actionName: "booking.status.override",
|
|
2813
|
+
routeOrToolName: "bookings.override-status",
|
|
2814
|
+
capabilityId: BOOKING_STATUS_CAPABILITIES.override.id,
|
|
2815
|
+
bookingId: id,
|
|
2816
|
+
fromStatus: booking.status,
|
|
2817
|
+
toStatus: data.status,
|
|
2818
|
+
evaluatedRisk: "high",
|
|
2819
|
+
});
|
|
2681
2820
|
return {
|
|
2682
2821
|
status: "ok",
|
|
2683
2822
|
booking: row ?? null,
|
|
@@ -2694,6 +2833,19 @@ export const bookingsService = {
|
|
|
2694
2833
|
reason: data.reason,
|
|
2695
2834
|
actorId: userId ?? null,
|
|
2696
2835
|
}, { category: "domain", source: "service" });
|
|
2836
|
+
// Also emit `booking.confirmed` when the override target is
|
|
2837
|
+
// confirmed so subscribers (auto-dispatch, contract auto-gen)
|
|
2838
|
+
// fire — the dialog's "Confirm after creating" flow goes
|
|
2839
|
+
// through override-status for draft → confirmed and would
|
|
2840
|
+
// otherwise leave those subscribers silent.
|
|
2841
|
+
if (result.toStatus === "confirmed") {
|
|
2842
|
+
await runtime.eventBus?.emit("booking.confirmed", {
|
|
2843
|
+
bookingId: result.booking.id,
|
|
2844
|
+
bookingNumber: result.booking.bookingNumber,
|
|
2845
|
+
actorId: userId ?? null,
|
|
2846
|
+
suppressNotifications: data.suppressNotifications === true,
|
|
2847
|
+
}, { category: "domain", source: "service" });
|
|
2848
|
+
}
|
|
2697
2849
|
}
|
|
2698
2850
|
return { status: result.status, booking: result.booking };
|
|
2699
2851
|
}
|
|
@@ -26,5 +26,7 @@ export interface BookingStatusDispatchTarget {
|
|
|
26
26
|
* Framework-agnostic: returns the URL + body to send. Callers own the
|
|
27
27
|
* transport (fetch, axios, the React hook, server-to-server scripts, etc).
|
|
28
28
|
*/
|
|
29
|
-
export declare function dispatchBookingStatusChange(bookingId: string, current: BookingStatus, target: BookingStatus, note?: string | null
|
|
29
|
+
export declare function dispatchBookingStatusChange(bookingId: string, current: BookingStatus, target: BookingStatus, note?: string | null, options?: {
|
|
30
|
+
suppressNotifications?: boolean;
|
|
31
|
+
}): BookingStatusDispatchTarget;
|
|
30
32
|
//# sourceMappingURL=status-dispatch.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-dispatch.d.ts","sourceRoot":"","sources":["../src/status-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"status-dispatch.d.ts","sourceRoot":"","sources":["../src/status-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAEvD,MAAM,WAAW,2BAA2B;IAC1C;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,aAAa,EACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EACpB,OAAO,CAAC,EAAE;IAAE,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5C,2BAA2B,CA8C7B"}
|
package/dist/status-dispatch.js
CHANGED
|
@@ -8,10 +8,16 @@
|
|
|
8
8
|
* Framework-agnostic: returns the URL + body to send. Callers own the
|
|
9
9
|
* transport (fetch, axios, the React hook, server-to-server scripts, etc).
|
|
10
10
|
*/
|
|
11
|
-
export function dispatchBookingStatusChange(bookingId, current, target, note) {
|
|
11
|
+
export function dispatchBookingStatusChange(bookingId, current, target, note, options) {
|
|
12
12
|
const noteBody = note ? { note } : {};
|
|
13
|
+
// Only carry the suppression flag on transitions to `confirmed` —
|
|
14
|
+
// it's the only transition that triggers customer-facing
|
|
15
|
+
// notifications today. Including it elsewhere is harmless but noisy.
|
|
16
|
+
const suppress = target === "confirmed" && options?.suppressNotifications === true
|
|
17
|
+
? { suppressNotifications: true }
|
|
18
|
+
: {};
|
|
13
19
|
if (current === "on_hold" && target === "confirmed") {
|
|
14
|
-
return { path: `/v1/bookings/${bookingId}/confirm`, body: noteBody };
|
|
20
|
+
return { path: `/v1/bookings/${bookingId}/confirm`, body: { ...noteBody, ...suppress } };
|
|
15
21
|
}
|
|
16
22
|
if (current === "on_hold" && target === "expired") {
|
|
17
23
|
return { path: `/v1/bookings/${bookingId}/expire`, body: noteBody };
|
|
@@ -29,8 +35,17 @@ export function dispatchBookingStatusChange(bookingId, current, target, note) {
|
|
|
29
35
|
current === "in_progress")) {
|
|
30
36
|
return { path: `/v1/bookings/${bookingId}/cancel`, body: noteBody };
|
|
31
37
|
}
|
|
38
|
+
// The override-status route rejects empty reasons. For the common
|
|
39
|
+
// post-create transitions out of `draft` (the operator commits the
|
|
40
|
+
// booking to either confirmed-with-money-in or awaiting-payment) we
|
|
41
|
+
// don't want to force a reason prompt, so supply a benign default.
|
|
42
|
+
// Callers can still pass an explicit note to override.
|
|
43
|
+
const defaultReason = current === "draft" && (target === "confirmed" || target === "awaiting_payment")
|
|
44
|
+
? `Set to ${target} after create`
|
|
45
|
+
: "";
|
|
46
|
+
const reason = note?.trim() || defaultReason;
|
|
32
47
|
return {
|
|
33
48
|
path: `/v1/bookings/${bookingId}/override-status`,
|
|
34
|
-
body: { status: target, reason
|
|
49
|
+
body: { status: target, reason, ...(note ? { note } : {}), ...suppress },
|
|
35
50
|
};
|
|
36
51
|
}
|
|
@@ -259,11 +259,11 @@ export declare const publicBookingSessionItemSchema: z.ZodObject<{
|
|
|
259
259
|
transport: "transport";
|
|
260
260
|
}>;
|
|
261
261
|
status: z.ZodEnum<{
|
|
262
|
+
expired: "expired";
|
|
262
263
|
cancelled: "cancelled";
|
|
263
264
|
draft: "draft";
|
|
264
265
|
on_hold: "on_hold";
|
|
265
266
|
confirmed: "confirmed";
|
|
266
|
-
expired: "expired";
|
|
267
267
|
fulfilled: "fulfilled";
|
|
268
268
|
}>;
|
|
269
269
|
serviceDate: z.ZodNullable<z.ZodString>;
|
|
@@ -308,9 +308,9 @@ export declare const publicBookingSessionAllocationSchema: z.ZodObject<{
|
|
|
308
308
|
pickup: "pickup";
|
|
309
309
|
}>;
|
|
310
310
|
status: z.ZodEnum<{
|
|
311
|
+
expired: "expired";
|
|
311
312
|
cancelled: "cancelled";
|
|
312
313
|
confirmed: "confirmed";
|
|
313
|
-
expired: "expired";
|
|
314
314
|
fulfilled: "fulfilled";
|
|
315
315
|
held: "held";
|
|
316
316
|
released: "released";
|
|
@@ -342,6 +342,7 @@ export declare const publicBookingSessionSchema: z.ZodObject<{
|
|
|
342
342
|
sessionId: z.ZodString;
|
|
343
343
|
bookingNumber: z.ZodString;
|
|
344
344
|
status: z.ZodEnum<{
|
|
345
|
+
expired: "expired";
|
|
345
346
|
cancelled: "cancelled";
|
|
346
347
|
completed: "completed";
|
|
347
348
|
draft: "draft";
|
|
@@ -349,7 +350,6 @@ export declare const publicBookingSessionSchema: z.ZodObject<{
|
|
|
349
350
|
awaiting_payment: "awaiting_payment";
|
|
350
351
|
confirmed: "confirmed";
|
|
351
352
|
in_progress: "in_progress";
|
|
352
|
-
expired: "expired";
|
|
353
353
|
}>;
|
|
354
354
|
externalBookingRef: z.ZodNullable<z.ZodString>;
|
|
355
355
|
communicationLanguage: z.ZodNullable<z.ZodString>;
|
|
@@ -403,11 +403,11 @@ export declare const publicBookingSessionSchema: z.ZodObject<{
|
|
|
403
403
|
transport: "transport";
|
|
404
404
|
}>;
|
|
405
405
|
status: z.ZodEnum<{
|
|
406
|
+
expired: "expired";
|
|
406
407
|
cancelled: "cancelled";
|
|
407
408
|
draft: "draft";
|
|
408
409
|
on_hold: "on_hold";
|
|
409
410
|
confirmed: "confirmed";
|
|
410
|
-
expired: "expired";
|
|
411
411
|
fulfilled: "fulfilled";
|
|
412
412
|
}>;
|
|
413
413
|
serviceDate: z.ZodNullable<z.ZodString>;
|
|
@@ -452,9 +452,9 @@ export declare const publicBookingSessionSchema: z.ZodObject<{
|
|
|
452
452
|
pickup: "pickup";
|
|
453
453
|
}>;
|
|
454
454
|
status: z.ZodEnum<{
|
|
455
|
+
expired: "expired";
|
|
455
456
|
cancelled: "cancelled";
|
|
456
457
|
confirmed: "confirmed";
|
|
457
|
-
expired: "expired";
|
|
458
458
|
fulfilled: "fulfilled";
|
|
459
459
|
held: "held";
|
|
460
460
|
released: "released";
|
|
@@ -559,6 +559,7 @@ export declare const publicBookingSessionRepriceResultSchema: z.ZodObject<{
|
|
|
559
559
|
sessionId: z.ZodString;
|
|
560
560
|
bookingNumber: z.ZodString;
|
|
561
561
|
status: z.ZodEnum<{
|
|
562
|
+
expired: "expired";
|
|
562
563
|
cancelled: "cancelled";
|
|
563
564
|
completed: "completed";
|
|
564
565
|
draft: "draft";
|
|
@@ -566,7 +567,6 @@ export declare const publicBookingSessionRepriceResultSchema: z.ZodObject<{
|
|
|
566
567
|
awaiting_payment: "awaiting_payment";
|
|
567
568
|
confirmed: "confirmed";
|
|
568
569
|
in_progress: "in_progress";
|
|
569
|
-
expired: "expired";
|
|
570
570
|
}>;
|
|
571
571
|
externalBookingRef: z.ZodNullable<z.ZodString>;
|
|
572
572
|
communicationLanguage: z.ZodNullable<z.ZodString>;
|
|
@@ -620,11 +620,11 @@ export declare const publicBookingSessionRepriceResultSchema: z.ZodObject<{
|
|
|
620
620
|
transport: "transport";
|
|
621
621
|
}>;
|
|
622
622
|
status: z.ZodEnum<{
|
|
623
|
+
expired: "expired";
|
|
623
624
|
cancelled: "cancelled";
|
|
624
625
|
draft: "draft";
|
|
625
626
|
on_hold: "on_hold";
|
|
626
627
|
confirmed: "confirmed";
|
|
627
|
-
expired: "expired";
|
|
628
628
|
fulfilled: "fulfilled";
|
|
629
629
|
}>;
|
|
630
630
|
serviceDate: z.ZodNullable<z.ZodString>;
|
|
@@ -669,9 +669,9 @@ export declare const publicBookingSessionRepriceResultSchema: z.ZodObject<{
|
|
|
669
669
|
pickup: "pickup";
|
|
670
670
|
}>;
|
|
671
671
|
status: z.ZodEnum<{
|
|
672
|
+
expired: "expired";
|
|
672
673
|
cancelled: "cancelled";
|
|
673
674
|
confirmed: "confirmed";
|
|
674
|
-
expired: "expired";
|
|
675
675
|
fulfilled: "fulfilled";
|
|
676
676
|
held: "held";
|
|
677
677
|
released: "released";
|
|
@@ -756,8 +756,8 @@ export declare const publicBookingOverviewFulfillmentSchema: z.ZodObject<{
|
|
|
756
756
|
wallet: "wallet";
|
|
757
757
|
}>;
|
|
758
758
|
status: z.ZodEnum<{
|
|
759
|
-
pending: "pending";
|
|
760
759
|
failed: "failed";
|
|
760
|
+
pending: "pending";
|
|
761
761
|
issued: "issued";
|
|
762
762
|
reissued: "reissued";
|
|
763
763
|
revoked: "revoked";
|
|
@@ -768,6 +768,7 @@ export declare const publicBookingOverviewSchema: z.ZodObject<{
|
|
|
768
768
|
bookingId: z.ZodString;
|
|
769
769
|
bookingNumber: z.ZodString;
|
|
770
770
|
status: z.ZodEnum<{
|
|
771
|
+
expired: "expired";
|
|
771
772
|
cancelled: "cancelled";
|
|
772
773
|
completed: "completed";
|
|
773
774
|
draft: "draft";
|
|
@@ -775,7 +776,6 @@ export declare const publicBookingOverviewSchema: z.ZodObject<{
|
|
|
775
776
|
awaiting_payment: "awaiting_payment";
|
|
776
777
|
confirmed: "confirmed";
|
|
777
778
|
in_progress: "in_progress";
|
|
778
|
-
expired: "expired";
|
|
779
779
|
}>;
|
|
780
780
|
sellCurrency: z.ZodString;
|
|
781
781
|
sellAmountCents: z.ZodNullable<z.ZodNumber>;
|
|
@@ -813,11 +813,11 @@ export declare const publicBookingOverviewSchema: z.ZodObject<{
|
|
|
813
813
|
transport: "transport";
|
|
814
814
|
}>;
|
|
815
815
|
status: z.ZodEnum<{
|
|
816
|
+
expired: "expired";
|
|
816
817
|
cancelled: "cancelled";
|
|
817
818
|
draft: "draft";
|
|
818
819
|
on_hold: "on_hold";
|
|
819
820
|
confirmed: "confirmed";
|
|
820
|
-
expired: "expired";
|
|
821
821
|
fulfilled: "fulfilled";
|
|
822
822
|
}>;
|
|
823
823
|
serviceDate: z.ZodNullable<z.ZodString>;
|
|
@@ -881,8 +881,8 @@ export declare const publicBookingOverviewSchema: z.ZodObject<{
|
|
|
881
881
|
wallet: "wallet";
|
|
882
882
|
}>;
|
|
883
883
|
status: z.ZodEnum<{
|
|
884
|
-
pending: "pending";
|
|
885
884
|
failed: "failed";
|
|
885
|
+
pending: "pending";
|
|
886
886
|
issued: "issued";
|
|
887
887
|
reissued: "reissued";
|
|
888
888
|
revoked: "revoked";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
export declare const bookingStatusSchema: z.ZodEnum<{
|
|
3
|
+
expired: "expired";
|
|
3
4
|
cancelled: "cancelled";
|
|
4
5
|
completed: "completed";
|
|
5
6
|
draft: "draft";
|
|
@@ -7,7 +8,6 @@ export declare const bookingStatusSchema: z.ZodEnum<{
|
|
|
7
8
|
awaiting_payment: "awaiting_payment";
|
|
8
9
|
confirmed: "confirmed";
|
|
9
10
|
in_progress: "in_progress";
|
|
10
|
-
expired: "expired";
|
|
11
11
|
}>;
|
|
12
12
|
export declare const supplierConfirmationStatusSchema: z.ZodEnum<{
|
|
13
13
|
cancelled: "cancelled";
|
|
@@ -49,11 +49,11 @@ export declare const bookingItemTypeSchema: z.ZodEnum<{
|
|
|
49
49
|
transport: "transport";
|
|
50
50
|
}>;
|
|
51
51
|
export declare const bookingItemStatusSchema: z.ZodEnum<{
|
|
52
|
+
expired: "expired";
|
|
52
53
|
cancelled: "cancelled";
|
|
53
54
|
draft: "draft";
|
|
54
55
|
on_hold: "on_hold";
|
|
55
56
|
confirmed: "confirmed";
|
|
56
|
-
expired: "expired";
|
|
57
57
|
fulfilled: "fulfilled";
|
|
58
58
|
}>;
|
|
59
59
|
export declare const bookingItemParticipantRoleSchema: z.ZodEnum<{
|
|
@@ -72,9 +72,9 @@ export declare const bookingAllocationTypeSchema: z.ZodEnum<{
|
|
|
72
72
|
pickup: "pickup";
|
|
73
73
|
}>;
|
|
74
74
|
export declare const bookingAllocationStatusSchema: z.ZodEnum<{
|
|
75
|
+
expired: "expired";
|
|
75
76
|
cancelled: "cancelled";
|
|
76
77
|
confirmed: "confirmed";
|
|
77
|
-
expired: "expired";
|
|
78
78
|
fulfilled: "fulfilled";
|
|
79
79
|
held: "held";
|
|
80
80
|
released: "released";
|
|
@@ -96,8 +96,8 @@ export declare const bookingFulfillmentDeliveryChannelSchema: z.ZodEnum<{
|
|
|
96
96
|
wallet: "wallet";
|
|
97
97
|
}>;
|
|
98
98
|
export declare const bookingFulfillmentStatusSchema: z.ZodEnum<{
|
|
99
|
-
pending: "pending";
|
|
100
99
|
failed: "failed";
|
|
100
|
+
pending: "pending";
|
|
101
101
|
issued: "issued";
|
|
102
102
|
reissued: "reissued";
|
|
103
103
|
revoked: "revoked";
|