@voyant-travel/accommodations 0.106.1 → 0.108.0

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/index.d.ts CHANGED
@@ -1,8 +1,26 @@
1
+ import type { LinkableDefinition, Module } from "@voyant-travel/core";
2
+ import type { HonoModule } from "@voyant-travel/hono/module";
3
+ /**
4
+ * Room blocks are the accommodations module's first linkable surface — a
5
+ * standard, package-owned allotment primitive that any deployment can use
6
+ * (the MICE spine merely links to it). See RFC voyant#1489.
7
+ */
8
+ export declare const roomBlockLinkable: LinkableDefinition;
9
+ export declare const accommodationsLinkable: {
10
+ roomBlock: LinkableDefinition;
11
+ };
12
+ export declare const accommodationsModule: Module;
13
+ export declare const accommodationsHonoModule: HonoModule;
14
+ export declare const accommodationsHonoModules: readonly [HonoModule];
1
15
  export * from "./booking-engine/index.js";
2
16
  export * from "./catalog-policy.js";
3
17
  export * from "./content-shape.js";
4
18
  export * from "./draft-shape.js";
19
+ export type { RoomBlockAdminRoutes } from "./routes-room-blocks.js";
20
+ export { roomBlockAdminRoutes } from "./routes-room-blocks.js";
5
21
  export * from "./service-catalog-plane.js";
6
22
  export * from "./service-content.js";
7
23
  export * from "./service-content-synthesizer.js";
24
+ export * from "./service-room-blocks.js";
25
+ export * from "./validation-room-blocks.js";
8
26
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kCAAkC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AAI5D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,kBAK/B,CAAA;AAED,eAAO,MAAM,sBAAsB;;CAElC,CAAA;AAED,eAAO,MAAM,oBAAoB,EAAE,MAKlC,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,UAGtC,CAAA;AAED,eAAO,MAAM,yBAAyB,uBAAsC,CAAA;AAE5E,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA;AAChC,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC9D,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kCAAkC,CAAA;AAChD,cAAc,0BAA0B,CAAA;AACxC,cAAc,6BAA6B,CAAA"}
package/dist/index.js CHANGED
@@ -1,7 +1,36 @@
1
+ import { roomBlockAdminRoutes } from "./routes-room-blocks.js";
2
+ /**
3
+ * Room blocks are the accommodations module's first linkable surface — a
4
+ * standard, package-owned allotment primitive that any deployment can use
5
+ * (the MICE spine merely links to it). See RFC voyant#1489.
6
+ */
7
+ export const roomBlockLinkable = {
8
+ module: "accommodations",
9
+ entity: "roomBlock",
10
+ table: "room_blocks",
11
+ idPrefix: "hrbl",
12
+ };
13
+ export const accommodationsLinkable = {
14
+ roomBlock: roomBlockLinkable,
15
+ };
16
+ export const accommodationsModule = {
17
+ name: "accommodations",
18
+ // Pickup / reversal / cutoff mutate per-night counters under a transaction.
19
+ requiresTransactionalDb: true,
20
+ linkable: accommodationsLinkable,
21
+ };
22
+ export const accommodationsHonoModule = {
23
+ module: accommodationsModule,
24
+ adminRoutes: roomBlockAdminRoutes,
25
+ };
26
+ export const accommodationsHonoModules = [accommodationsHonoModule];
1
27
  export * from "./booking-engine/index.js";
2
28
  export * from "./catalog-policy.js";
3
29
  export * from "./content-shape.js";
4
30
  export * from "./draft-shape.js";
31
+ export { roomBlockAdminRoutes } from "./routes-room-blocks.js";
5
32
  export * from "./service-catalog-plane.js";
6
33
  export * from "./service-content.js";
7
34
  export * from "./service-content-synthesizer.js";
35
+ export * from "./service-room-blocks.js";
36
+ export * from "./validation-room-blocks.js";
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Room-block admin routes. Mounted by the deployment under
3
+ * `/v1/admin/accommodations` (so these resolve at
4
+ * `/v1/admin/accommodations/room-blocks/*`). The accommodations module sets
5
+ * `requiresTransactionalDb`, so the pickup/reversal/release mutations run on
6
+ * the transactional DB. See RFC voyant#1489 §4.2/§8.
7
+ *
8
+ * Routes stay thin: validate input, call `roomBlockService`, serialize.
9
+ */
10
+ import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
11
+ type Env = {
12
+ Variables: {
13
+ db: PostgresJsDatabase;
14
+ userId?: string;
15
+ };
16
+ };
17
+ export declare const roomBlockAdminRoutes: import("hono/hono-base").HonoBase<Env, {
18
+ "/room-blocks": {
19
+ $post: {
20
+ input: {};
21
+ output: {
22
+ data: {
23
+ id: string;
24
+ createdAt: string;
25
+ updatedAt: string;
26
+ propertyId: string | null;
27
+ supplierId: string | null;
28
+ name: string;
29
+ currency: string;
30
+ status: "held" | "confirmed" | "cancelled" | "expired" | "inquiry" | "released";
31
+ metadata: {
32
+ [x: string]: import("hono/utils/types").JSONValue;
33
+ } | null;
34
+ notes: string | null;
35
+ roomTypeId: string;
36
+ programId: string | null;
37
+ netRateCents: number | null;
38
+ sellRateCents: number | null;
39
+ optionDate: string | null;
40
+ cutoffDate: string | null;
41
+ attritionTerms: {
42
+ [x: string]: import("hono/utils/types").JSONValue;
43
+ } | null;
44
+ depositTerms: {
45
+ [x: string]: import("hono/utils/types").JSONValue;
46
+ } | null;
47
+ };
48
+ };
49
+ outputFormat: "json";
50
+ status: 201;
51
+ };
52
+ };
53
+ } & {
54
+ "/room-blocks/:id": {
55
+ $get: {
56
+ input: {
57
+ param: {
58
+ id: string;
59
+ };
60
+ };
61
+ output: {
62
+ error: string;
63
+ };
64
+ outputFormat: "json";
65
+ status: 404;
66
+ } | {
67
+ input: {
68
+ param: {
69
+ id: string;
70
+ };
71
+ };
72
+ output: {
73
+ data: {
74
+ block: {
75
+ id: string;
76
+ createdAt: string;
77
+ updatedAt: string;
78
+ propertyId: string | null;
79
+ supplierId: string | null;
80
+ name: string;
81
+ currency: string;
82
+ status: "held" | "confirmed" | "cancelled" | "expired" | "inquiry" | "released";
83
+ metadata: {
84
+ [x: string]: import("hono/utils/types").JSONValue;
85
+ } | null;
86
+ notes: string | null;
87
+ roomTypeId: string;
88
+ programId: string | null;
89
+ netRateCents: number | null;
90
+ sellRateCents: number | null;
91
+ optionDate: string | null;
92
+ cutoffDate: string | null;
93
+ attritionTerms: {
94
+ [x: string]: import("hono/utils/types").JSONValue;
95
+ } | null;
96
+ depositTerms: {
97
+ [x: string]: import("hono/utils/types").JSONValue;
98
+ } | null;
99
+ };
100
+ summary: {
101
+ blockId: string;
102
+ status: import("./schema-room-blocks.js").RoomBlock["status"];
103
+ totalHeld: number;
104
+ totalPickedUp: number;
105
+ totalReleased: number;
106
+ totalRemaining: number;
107
+ pickupProgress: import("@voyant-travel/allotments").PickupProgress;
108
+ } | null;
109
+ };
110
+ };
111
+ outputFormat: "json";
112
+ status: import("hono/utils/http-status").ContentfulStatusCode;
113
+ };
114
+ };
115
+ } & {
116
+ "/room-blocks/:id/nights": {
117
+ $put: {
118
+ input: {
119
+ param: {
120
+ id: string;
121
+ };
122
+ };
123
+ output: {
124
+ error: string;
125
+ };
126
+ outputFormat: "json";
127
+ status: 404;
128
+ } | {
129
+ input: {
130
+ param: {
131
+ id: string;
132
+ };
133
+ };
134
+ output: {
135
+ data: {
136
+ blockId: string;
137
+ status: import("./schema-room-blocks.js").RoomBlock["status"];
138
+ totalHeld: number;
139
+ totalPickedUp: number;
140
+ totalReleased: number;
141
+ totalRemaining: number;
142
+ pickupProgress: import("@voyant-travel/allotments").PickupProgress;
143
+ } | null;
144
+ };
145
+ outputFormat: "json";
146
+ status: import("hono/utils/http-status").ContentfulStatusCode;
147
+ };
148
+ };
149
+ } & {
150
+ "/room-blocks/:id/pickups": {
151
+ $post: {
152
+ input: {
153
+ param: {
154
+ id: string;
155
+ };
156
+ };
157
+ output: {
158
+ data: {
159
+ id: string;
160
+ status: "active" | "reversed";
161
+ bookingId: string | null;
162
+ rooms: number;
163
+ checkIn: string;
164
+ checkOut: string;
165
+ stayBookingItemId: string | null;
166
+ blockId: string;
167
+ pickedUpAt: string;
168
+ reversedAt: string | null;
169
+ };
170
+ };
171
+ outputFormat: "json";
172
+ status: 200 | 201;
173
+ } | {
174
+ input: {
175
+ param: {
176
+ id: string;
177
+ };
178
+ };
179
+ output: {
180
+ error: string;
181
+ };
182
+ outputFormat: "json";
183
+ status: 404;
184
+ } | {
185
+ input: {
186
+ param: {
187
+ id: string;
188
+ };
189
+ };
190
+ output: {
191
+ error: string;
192
+ };
193
+ outputFormat: "json";
194
+ status: 400;
195
+ } | {
196
+ input: {
197
+ param: {
198
+ id: string;
199
+ };
200
+ };
201
+ output: {
202
+ error: string;
203
+ };
204
+ outputFormat: "json";
205
+ status: 409;
206
+ };
207
+ };
208
+ } & {
209
+ "/room-blocks/:id/pickups/reverse": {
210
+ $post: {
211
+ input: {
212
+ param: {
213
+ id: string;
214
+ };
215
+ };
216
+ output: {
217
+ error: string;
218
+ };
219
+ outputFormat: "json";
220
+ status: 404;
221
+ } | {
222
+ input: {
223
+ param: {
224
+ id: string;
225
+ };
226
+ };
227
+ output: {
228
+ data: {
229
+ id: string;
230
+ status: "active" | "reversed";
231
+ bookingId: string | null;
232
+ rooms: number;
233
+ checkIn: string;
234
+ checkOut: string;
235
+ stayBookingItemId: string | null;
236
+ blockId: string;
237
+ pickedUpAt: string;
238
+ reversedAt: string | null;
239
+ };
240
+ };
241
+ outputFormat: "json";
242
+ status: import("hono/utils/http-status").ContentfulStatusCode;
243
+ };
244
+ };
245
+ } & {
246
+ "/room-blocks/:id/release": {
247
+ $post: {
248
+ input: {
249
+ param: {
250
+ id: string;
251
+ };
252
+ };
253
+ output: {
254
+ error: string;
255
+ };
256
+ outputFormat: "json";
257
+ status: 404;
258
+ } | {
259
+ input: {
260
+ param: {
261
+ id: string;
262
+ };
263
+ };
264
+ output: {
265
+ data: {
266
+ releasedRooms: number;
267
+ block: {
268
+ id: string;
269
+ createdAt: string;
270
+ updatedAt: string;
271
+ propertyId: string | null;
272
+ supplierId: string | null;
273
+ name: string;
274
+ currency: string;
275
+ status: "held" | "confirmed" | "cancelled" | "expired" | "inquiry" | "released";
276
+ metadata: {
277
+ [x: string]: import("hono/utils/types").JSONValue;
278
+ } | null;
279
+ notes: string | null;
280
+ roomTypeId: string;
281
+ programId: string | null;
282
+ netRateCents: number | null;
283
+ sellRateCents: number | null;
284
+ optionDate: string | null;
285
+ cutoffDate: string | null;
286
+ attritionTerms: {
287
+ [x: string]: import("hono/utils/types").JSONValue;
288
+ } | null;
289
+ depositTerms: {
290
+ [x: string]: import("hono/utils/types").JSONValue;
291
+ } | null;
292
+ };
293
+ };
294
+ };
295
+ outputFormat: "json";
296
+ status: import("hono/utils/http-status").ContentfulStatusCode;
297
+ };
298
+ };
299
+ }, "/", "/room-blocks/:id/release">;
300
+ export type RoomBlockAdminRoutes = typeof roomBlockAdminRoutes;
301
+ export {};
302
+ //# sourceMappingURL=routes-room-blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-room-blocks.d.ts","sourceRoot":"","sources":["../src/routes-room-blocks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAmBjE,KAAK,GAAG,GAAG;IACT,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCA2D7B,CAAA;AAEJ,MAAM,MAAM,oBAAoB,GAAG,OAAO,oBAAoB,CAAA"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Room-block admin routes. Mounted by the deployment under
3
+ * `/v1/admin/accommodations` (so these resolve at
4
+ * `/v1/admin/accommodations/room-blocks/*`). The accommodations module sets
5
+ * `requiresTransactionalDb`, so the pickup/reversal/release mutations run on
6
+ * the transactional DB. See RFC voyant#1489 §4.2/§8.
7
+ *
8
+ * Routes stay thin: validate input, call `roomBlockService`, serialize.
9
+ */
10
+ import { parseJsonBody } from "@voyant-travel/hono";
11
+ import { Hono } from "hono";
12
+ import { createRoomBlock, getRoomBlock, pickupRoomBlock, releaseRoomBlockAtCutoff, reverseRoomBlockPickup, setRoomBlockNights, summarizeRoomBlock, } from "./service-room-blocks.js";
13
+ import { createRoomBlockSchema, reverseRoomBlockPickupSchema, roomBlockPickupSchema, setRoomBlockNightsSchema, } from "./validation-room-blocks.js";
14
+ export const roomBlockAdminRoutes = new Hono()
15
+ .post("/room-blocks", async (c) => {
16
+ const body = await parseJsonBody(c, createRoomBlockSchema);
17
+ return c.json({ data: await createRoomBlock(c.get("db"), body) }, 201);
18
+ })
19
+ .get("/room-blocks/:id", async (c) => {
20
+ const id = c.req.param("id");
21
+ const block = await getRoomBlock(c.get("db"), id);
22
+ if (!block)
23
+ return c.json({ error: "Room block not found" }, 404);
24
+ const summary = await summarizeRoomBlock(c.get("db"), id);
25
+ return c.json({ data: { block, summary } });
26
+ })
27
+ .put("/room-blocks/:id/nights", async (c) => {
28
+ const id = c.req.param("id");
29
+ const block = await getRoomBlock(c.get("db"), id);
30
+ if (!block)
31
+ return c.json({ error: "Room block not found" }, 404);
32
+ const { nights } = await parseJsonBody(c, setRoomBlockNightsSchema);
33
+ await setRoomBlockNights(c.get("db"), id, nights);
34
+ return c.json({ data: await summarizeRoomBlock(c.get("db"), id) });
35
+ })
36
+ .post("/room-blocks/:id/pickups", async (c) => {
37
+ const body = await parseJsonBody(c, roomBlockPickupSchema);
38
+ const outcome = await pickupRoomBlock(c.get("db"), { blockId: c.req.param("id"), ...body });
39
+ switch (outcome.status) {
40
+ case "ok":
41
+ return c.json({ data: outcome.pickup }, outcome.idempotent ? 200 : 201);
42
+ case "block_not_found":
43
+ return c.json({ error: "Room block not found" }, 404);
44
+ case "invalid_range":
45
+ return c.json({ error: "Invalid check-in/check-out range" }, 400);
46
+ case "block_not_active":
47
+ return c.json({ error: "Room block is no longer accepting pickups" }, 409);
48
+ case "night_unavailable":
49
+ return c.json({
50
+ error: "Insufficient inventory",
51
+ detail: { date: outcome.date, remaining: outcome.remaining, needed: outcome.needed },
52
+ }, 409);
53
+ }
54
+ })
55
+ .post("/room-blocks/:id/pickups/reverse", async (c) => {
56
+ const body = await parseJsonBody(c, reverseRoomBlockPickupSchema);
57
+ const outcome = await reverseRoomBlockPickup(c.get("db"), {
58
+ blockId: c.req.param("id"),
59
+ ...body,
60
+ });
61
+ if (outcome.status === "pickup_not_found") {
62
+ return c.json({ error: "Active pickup not found" }, 404);
63
+ }
64
+ return c.json({ data: outcome.pickup });
65
+ })
66
+ .post("/room-blocks/:id/release", async (c) => {
67
+ const outcome = await releaseRoomBlockAtCutoff(c.get("db"), { blockId: c.req.param("id") });
68
+ if (outcome.status === "block_not_found") {
69
+ return c.json({ error: "Room block not found" }, 404);
70
+ }
71
+ return c.json({ data: { releasedRooms: outcome.releasedRooms, block: outcome.block } });
72
+ });
@@ -279,7 +279,7 @@ export declare const stayBookingItems: import("drizzle-orm/pg-core").PgTableWith
279
279
  tableName: "stay_booking_items";
280
280
  dataType: "string";
281
281
  columnType: "PgEnumColumn";
282
- data: "cancelled" | "reserved" | "no_show";
282
+ data: "cancelled" | "no_show" | "reserved";
283
283
  driverParam: string;
284
284
  notNull: true;
285
285
  hasDefault: true;