@voyantjs/hospitality 0.9.0 → 0.11.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/pricing-ref.d.ts +239 -0
- package/dist/pricing-ref.d.ts.map +1 -0
- package/dist/pricing-ref.js +25 -0
- package/dist/routes-accommodation.d.ts +2 -2
- package/dist/routes-inventory.d.ts +1 -1
- package/dist/routes-operations.d.ts +2 -2
- package/dist/routes-stays.d.ts +1 -1
- package/dist/routes.d.ts +4 -4
- package/dist/service.d.ts +177 -4
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +414 -1
- package/package.json +7 -6
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local reference to `pricing.price_schedules`. Hospitality reads this
|
|
3
|
+
* table to resolve per-date rate variations on
|
|
4
|
+
* `hospitalityService.resolveStayDailyRates`, but doesn't pull
|
|
5
|
+
* `@voyantjs/pricing` as a hard dep — the FK rule (intra-domain FKs
|
|
6
|
+
* OK, cross-domain MUST be plain text) means we mirror only the
|
|
7
|
+
* columns we read.
|
|
8
|
+
*/
|
|
9
|
+
export declare const priceSchedulesRef: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
10
|
+
name: "price_schedules";
|
|
11
|
+
schema: undefined;
|
|
12
|
+
columns: {
|
|
13
|
+
id: import("drizzle-orm/pg-core").PgColumn<{
|
|
14
|
+
name: string;
|
|
15
|
+
tableName: "price_schedules";
|
|
16
|
+
dataType: "string";
|
|
17
|
+
columnType: "PgText";
|
|
18
|
+
data: string;
|
|
19
|
+
driverParam: string;
|
|
20
|
+
notNull: true;
|
|
21
|
+
hasDefault: true;
|
|
22
|
+
isPrimaryKey: true;
|
|
23
|
+
isAutoincrement: false;
|
|
24
|
+
hasRuntimeDefault: true;
|
|
25
|
+
enumValues: [string, ...string[]];
|
|
26
|
+
baseColumn: never;
|
|
27
|
+
identity: undefined;
|
|
28
|
+
generated: undefined;
|
|
29
|
+
}, {}, {}>;
|
|
30
|
+
priceCatalogId: import("drizzle-orm/pg-core").PgColumn<{
|
|
31
|
+
name: string;
|
|
32
|
+
tableName: "price_schedules";
|
|
33
|
+
dataType: "string";
|
|
34
|
+
columnType: "PgText";
|
|
35
|
+
data: string;
|
|
36
|
+
driverParam: string;
|
|
37
|
+
notNull: true;
|
|
38
|
+
hasDefault: false;
|
|
39
|
+
isPrimaryKey: false;
|
|
40
|
+
isAutoincrement: false;
|
|
41
|
+
hasRuntimeDefault: false;
|
|
42
|
+
enumValues: [string, ...string[]];
|
|
43
|
+
baseColumn: never;
|
|
44
|
+
identity: undefined;
|
|
45
|
+
generated: undefined;
|
|
46
|
+
}, {}, {}>;
|
|
47
|
+
code: import("drizzle-orm/pg-core").PgColumn<{
|
|
48
|
+
name: "code";
|
|
49
|
+
tableName: "price_schedules";
|
|
50
|
+
dataType: "string";
|
|
51
|
+
columnType: "PgText";
|
|
52
|
+
data: string;
|
|
53
|
+
driverParam: string;
|
|
54
|
+
notNull: false;
|
|
55
|
+
hasDefault: false;
|
|
56
|
+
isPrimaryKey: false;
|
|
57
|
+
isAutoincrement: false;
|
|
58
|
+
hasRuntimeDefault: false;
|
|
59
|
+
enumValues: [string, ...string[]];
|
|
60
|
+
baseColumn: never;
|
|
61
|
+
identity: undefined;
|
|
62
|
+
generated: undefined;
|
|
63
|
+
}, {}, {}>;
|
|
64
|
+
name: import("drizzle-orm/pg-core").PgColumn<{
|
|
65
|
+
name: "name";
|
|
66
|
+
tableName: "price_schedules";
|
|
67
|
+
dataType: "string";
|
|
68
|
+
columnType: "PgText";
|
|
69
|
+
data: string;
|
|
70
|
+
driverParam: string;
|
|
71
|
+
notNull: true;
|
|
72
|
+
hasDefault: false;
|
|
73
|
+
isPrimaryKey: false;
|
|
74
|
+
isAutoincrement: false;
|
|
75
|
+
hasRuntimeDefault: false;
|
|
76
|
+
enumValues: [string, ...string[]];
|
|
77
|
+
baseColumn: never;
|
|
78
|
+
identity: undefined;
|
|
79
|
+
generated: undefined;
|
|
80
|
+
}, {}, {}>;
|
|
81
|
+
recurrenceRule: import("drizzle-orm/pg-core").PgColumn<{
|
|
82
|
+
name: "recurrence_rule";
|
|
83
|
+
tableName: "price_schedules";
|
|
84
|
+
dataType: "string";
|
|
85
|
+
columnType: "PgText";
|
|
86
|
+
data: string;
|
|
87
|
+
driverParam: string;
|
|
88
|
+
notNull: true;
|
|
89
|
+
hasDefault: false;
|
|
90
|
+
isPrimaryKey: false;
|
|
91
|
+
isAutoincrement: false;
|
|
92
|
+
hasRuntimeDefault: false;
|
|
93
|
+
enumValues: [string, ...string[]];
|
|
94
|
+
baseColumn: never;
|
|
95
|
+
identity: undefined;
|
|
96
|
+
generated: undefined;
|
|
97
|
+
}, {}, {}>;
|
|
98
|
+
timezone: import("drizzle-orm/pg-core").PgColumn<{
|
|
99
|
+
name: "timezone";
|
|
100
|
+
tableName: "price_schedules";
|
|
101
|
+
dataType: "string";
|
|
102
|
+
columnType: "PgText";
|
|
103
|
+
data: string;
|
|
104
|
+
driverParam: string;
|
|
105
|
+
notNull: false;
|
|
106
|
+
hasDefault: false;
|
|
107
|
+
isPrimaryKey: false;
|
|
108
|
+
isAutoincrement: false;
|
|
109
|
+
hasRuntimeDefault: false;
|
|
110
|
+
enumValues: [string, ...string[]];
|
|
111
|
+
baseColumn: never;
|
|
112
|
+
identity: undefined;
|
|
113
|
+
generated: undefined;
|
|
114
|
+
}, {}, {}>;
|
|
115
|
+
validFrom: import("drizzle-orm/pg-core").PgColumn<{
|
|
116
|
+
name: "valid_from";
|
|
117
|
+
tableName: "price_schedules";
|
|
118
|
+
dataType: "string";
|
|
119
|
+
columnType: "PgDateString";
|
|
120
|
+
data: string;
|
|
121
|
+
driverParam: string;
|
|
122
|
+
notNull: false;
|
|
123
|
+
hasDefault: false;
|
|
124
|
+
isPrimaryKey: false;
|
|
125
|
+
isAutoincrement: false;
|
|
126
|
+
hasRuntimeDefault: false;
|
|
127
|
+
enumValues: undefined;
|
|
128
|
+
baseColumn: never;
|
|
129
|
+
identity: undefined;
|
|
130
|
+
generated: undefined;
|
|
131
|
+
}, {}, {}>;
|
|
132
|
+
validTo: import("drizzle-orm/pg-core").PgColumn<{
|
|
133
|
+
name: "valid_to";
|
|
134
|
+
tableName: "price_schedules";
|
|
135
|
+
dataType: "string";
|
|
136
|
+
columnType: "PgDateString";
|
|
137
|
+
data: string;
|
|
138
|
+
driverParam: string;
|
|
139
|
+
notNull: false;
|
|
140
|
+
hasDefault: false;
|
|
141
|
+
isPrimaryKey: false;
|
|
142
|
+
isAutoincrement: false;
|
|
143
|
+
hasRuntimeDefault: false;
|
|
144
|
+
enumValues: undefined;
|
|
145
|
+
baseColumn: never;
|
|
146
|
+
identity: undefined;
|
|
147
|
+
generated: undefined;
|
|
148
|
+
}, {}, {}>;
|
|
149
|
+
weekdays: import("drizzle-orm/pg-core").PgColumn<{
|
|
150
|
+
name: "weekdays";
|
|
151
|
+
tableName: "price_schedules";
|
|
152
|
+
dataType: "json";
|
|
153
|
+
columnType: "PgJsonb";
|
|
154
|
+
data: string[];
|
|
155
|
+
driverParam: unknown;
|
|
156
|
+
notNull: false;
|
|
157
|
+
hasDefault: false;
|
|
158
|
+
isPrimaryKey: false;
|
|
159
|
+
isAutoincrement: false;
|
|
160
|
+
hasRuntimeDefault: false;
|
|
161
|
+
enumValues: undefined;
|
|
162
|
+
baseColumn: never;
|
|
163
|
+
identity: undefined;
|
|
164
|
+
generated: undefined;
|
|
165
|
+
}, {}, {
|
|
166
|
+
$type: string[];
|
|
167
|
+
}>;
|
|
168
|
+
priority: import("drizzle-orm/pg-core").PgColumn<{
|
|
169
|
+
name: "priority";
|
|
170
|
+
tableName: "price_schedules";
|
|
171
|
+
dataType: "number";
|
|
172
|
+
columnType: "PgInteger";
|
|
173
|
+
data: number;
|
|
174
|
+
driverParam: string | number;
|
|
175
|
+
notNull: true;
|
|
176
|
+
hasDefault: false;
|
|
177
|
+
isPrimaryKey: false;
|
|
178
|
+
isAutoincrement: false;
|
|
179
|
+
hasRuntimeDefault: false;
|
|
180
|
+
enumValues: undefined;
|
|
181
|
+
baseColumn: never;
|
|
182
|
+
identity: undefined;
|
|
183
|
+
generated: undefined;
|
|
184
|
+
}, {}, {}>;
|
|
185
|
+
active: import("drizzle-orm/pg-core").PgColumn<{
|
|
186
|
+
name: "active";
|
|
187
|
+
tableName: "price_schedules";
|
|
188
|
+
dataType: "boolean";
|
|
189
|
+
columnType: "PgBoolean";
|
|
190
|
+
data: boolean;
|
|
191
|
+
driverParam: boolean;
|
|
192
|
+
notNull: true;
|
|
193
|
+
hasDefault: false;
|
|
194
|
+
isPrimaryKey: false;
|
|
195
|
+
isAutoincrement: false;
|
|
196
|
+
hasRuntimeDefault: false;
|
|
197
|
+
enumValues: undefined;
|
|
198
|
+
baseColumn: never;
|
|
199
|
+
identity: undefined;
|
|
200
|
+
generated: undefined;
|
|
201
|
+
}, {}, {}>;
|
|
202
|
+
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
203
|
+
name: "created_at";
|
|
204
|
+
tableName: "price_schedules";
|
|
205
|
+
dataType: "date";
|
|
206
|
+
columnType: "PgTimestamp";
|
|
207
|
+
data: Date;
|
|
208
|
+
driverParam: string;
|
|
209
|
+
notNull: true;
|
|
210
|
+
hasDefault: false;
|
|
211
|
+
isPrimaryKey: false;
|
|
212
|
+
isAutoincrement: false;
|
|
213
|
+
hasRuntimeDefault: false;
|
|
214
|
+
enumValues: undefined;
|
|
215
|
+
baseColumn: never;
|
|
216
|
+
identity: undefined;
|
|
217
|
+
generated: undefined;
|
|
218
|
+
}, {}, {}>;
|
|
219
|
+
updatedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
220
|
+
name: "updated_at";
|
|
221
|
+
tableName: "price_schedules";
|
|
222
|
+
dataType: "date";
|
|
223
|
+
columnType: "PgTimestamp";
|
|
224
|
+
data: Date;
|
|
225
|
+
driverParam: string;
|
|
226
|
+
notNull: true;
|
|
227
|
+
hasDefault: false;
|
|
228
|
+
isPrimaryKey: false;
|
|
229
|
+
isAutoincrement: false;
|
|
230
|
+
hasRuntimeDefault: false;
|
|
231
|
+
enumValues: undefined;
|
|
232
|
+
baseColumn: never;
|
|
233
|
+
identity: undefined;
|
|
234
|
+
generated: undefined;
|
|
235
|
+
}, {}, {}>;
|
|
236
|
+
};
|
|
237
|
+
dialect: "pg";
|
|
238
|
+
}>;
|
|
239
|
+
//# sourceMappingURL=pricing-ref.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing-ref.d.ts","sourceRoot":"","sources":["../src/pricing-ref.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAc5B,CAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { typeId, typeIdRef } from "@voyantjs/db/lib/typeid-column";
|
|
2
|
+
import { boolean, date, integer, jsonb, pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
|
3
|
+
/**
|
|
4
|
+
* Local reference to `pricing.price_schedules`. Hospitality reads this
|
|
5
|
+
* table to resolve per-date rate variations on
|
|
6
|
+
* `hospitalityService.resolveStayDailyRates`, but doesn't pull
|
|
7
|
+
* `@voyantjs/pricing` as a hard dep — the FK rule (intra-domain FKs
|
|
8
|
+
* OK, cross-domain MUST be plain text) means we mirror only the
|
|
9
|
+
* columns we read.
|
|
10
|
+
*/
|
|
11
|
+
export const priceSchedulesRef = pgTable("price_schedules", {
|
|
12
|
+
id: typeId("price_schedules").primaryKey(),
|
|
13
|
+
priceCatalogId: typeIdRef("price_catalog_id").notNull(),
|
|
14
|
+
code: text("code"),
|
|
15
|
+
name: text("name").notNull(),
|
|
16
|
+
recurrenceRule: text("recurrence_rule").notNull(),
|
|
17
|
+
timezone: text("timezone"),
|
|
18
|
+
validFrom: date("valid_from"),
|
|
19
|
+
validTo: date("valid_to"),
|
|
20
|
+
weekdays: jsonb("weekdays").$type(),
|
|
21
|
+
priority: integer("priority").notNull(),
|
|
22
|
+
active: boolean("active").notNull(),
|
|
23
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull(),
|
|
24
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull(),
|
|
25
|
+
});
|
|
@@ -747,10 +747,10 @@ export declare const hospitalityAccommodationRoutes: import("hono/hono-base").Ho
|
|
|
747
747
|
description: string | null;
|
|
748
748
|
code: string;
|
|
749
749
|
active: boolean;
|
|
750
|
+
priceCatalogId: string | null;
|
|
750
751
|
sortOrder: number;
|
|
751
752
|
propertyId: string;
|
|
752
753
|
mealPlanId: string | null;
|
|
753
|
-
priceCatalogId: string | null;
|
|
754
754
|
cancellationPolicyId: string | null;
|
|
755
755
|
marketId: string | null;
|
|
756
756
|
currencyCode: string;
|
|
@@ -920,9 +920,9 @@ export declare const hospitalityAccommodationRoutes: import("hono/hono-base").Ho
|
|
|
920
920
|
id: string;
|
|
921
921
|
createdAt: string;
|
|
922
922
|
updatedAt: string;
|
|
923
|
+
active: boolean;
|
|
923
924
|
productId: string | null;
|
|
924
925
|
optionId: string | null;
|
|
925
|
-
active: boolean;
|
|
926
926
|
sortOrder: number;
|
|
927
927
|
roomTypeId: string;
|
|
928
928
|
ratePlanId: string;
|
|
@@ -848,12 +848,12 @@ export declare const hospitalityInventoryRoutes: import("hono/hono-base").HonoBa
|
|
|
848
848
|
updatedAt: string;
|
|
849
849
|
status: "in_progress" | "completed" | "cancelled" | "open";
|
|
850
850
|
notes: string | null;
|
|
851
|
+
priority: number;
|
|
851
852
|
completedAt: string | null;
|
|
852
853
|
propertyId: string;
|
|
853
854
|
roomUnitId: string;
|
|
854
855
|
stayBookingItemId: string | null;
|
|
855
856
|
taskType: string;
|
|
856
|
-
priority: number;
|
|
857
857
|
dueAt: string | null;
|
|
858
858
|
startedAt: string | null;
|
|
859
859
|
assignedTo: string | null;
|
|
@@ -848,12 +848,12 @@ export declare const hospitalityOperationsRoutes: import("hono/hono-base").HonoB
|
|
|
848
848
|
updatedAt: string;
|
|
849
849
|
status: "in_progress" | "completed" | "cancelled" | "open";
|
|
850
850
|
notes: string | null;
|
|
851
|
+
priority: number;
|
|
851
852
|
completedAt: string | null;
|
|
852
853
|
propertyId: string;
|
|
853
854
|
roomUnitId: string;
|
|
854
855
|
stayBookingItemId: string | null;
|
|
855
856
|
taskType: string;
|
|
856
|
-
priority: number;
|
|
857
857
|
dueAt: string | null;
|
|
858
858
|
startedAt: string | null;
|
|
859
859
|
assignedTo: string | null;
|
|
@@ -1031,10 +1031,10 @@ export declare const hospitalityOperationsRoutes: import("hono/hono-base").HonoB
|
|
|
1031
1031
|
active: boolean;
|
|
1032
1032
|
validFrom: string | null;
|
|
1033
1033
|
validTo: string | null;
|
|
1034
|
+
priority: number;
|
|
1034
1035
|
propertyId: string;
|
|
1035
1036
|
roomTypeId: string | null;
|
|
1036
1037
|
ratePlanId: string | null;
|
|
1037
|
-
priority: number;
|
|
1038
1038
|
minNights: number | null;
|
|
1039
1039
|
maxNights: number | null;
|
|
1040
1040
|
minAdvanceDays: number | null;
|
package/dist/routes-stays.d.ts
CHANGED
|
@@ -53,10 +53,10 @@ export declare const hospitalityStayRoutes: import("hono/hono-base").HonoBase<En
|
|
|
53
53
|
active: boolean;
|
|
54
54
|
validFrom: string | null;
|
|
55
55
|
validTo: string | null;
|
|
56
|
+
priority: number;
|
|
56
57
|
propertyId: string;
|
|
57
58
|
roomTypeId: string | null;
|
|
58
59
|
ratePlanId: string | null;
|
|
59
|
-
priority: number;
|
|
60
60
|
minNights: number | null;
|
|
61
61
|
maxNights: number | null;
|
|
62
62
|
minAdvanceDays: number | null;
|
package/dist/routes.d.ts
CHANGED
|
@@ -747,10 +747,10 @@ export declare const hospitalityRoutes: import("hono/hono-base").HonoBase<Env, i
|
|
|
747
747
|
description: string | null;
|
|
748
748
|
code: string;
|
|
749
749
|
active: boolean;
|
|
750
|
+
priceCatalogId: string | null;
|
|
750
751
|
sortOrder: number;
|
|
751
752
|
propertyId: string;
|
|
752
753
|
mealPlanId: string | null;
|
|
753
|
-
priceCatalogId: string | null;
|
|
754
754
|
cancellationPolicyId: string | null;
|
|
755
755
|
marketId: string | null;
|
|
756
756
|
currencyCode: string;
|
|
@@ -920,9 +920,9 @@ export declare const hospitalityRoutes: import("hono/hono-base").HonoBase<Env, i
|
|
|
920
920
|
id: string;
|
|
921
921
|
createdAt: string;
|
|
922
922
|
updatedAt: string;
|
|
923
|
+
active: boolean;
|
|
923
924
|
productId: string | null;
|
|
924
925
|
optionId: string | null;
|
|
925
|
-
active: boolean;
|
|
926
926
|
sortOrder: number;
|
|
927
927
|
roomTypeId: string;
|
|
928
928
|
ratePlanId: string;
|
|
@@ -2041,12 +2041,12 @@ export declare const hospitalityRoutes: import("hono/hono-base").HonoBase<Env, i
|
|
|
2041
2041
|
updatedAt: string;
|
|
2042
2042
|
status: "in_progress" | "completed" | "cancelled" | "open";
|
|
2043
2043
|
notes: string | null;
|
|
2044
|
+
priority: number;
|
|
2044
2045
|
completedAt: string | null;
|
|
2045
2046
|
propertyId: string;
|
|
2046
2047
|
roomUnitId: string;
|
|
2047
2048
|
stayBookingItemId: string | null;
|
|
2048
2049
|
taskType: string;
|
|
2049
|
-
priority: number;
|
|
2050
2050
|
dueAt: string | null;
|
|
2051
2051
|
startedAt: string | null;
|
|
2052
2052
|
assignedTo: string | null;
|
|
@@ -2224,10 +2224,10 @@ export declare const hospitalityRoutes: import("hono/hono-base").HonoBase<Env, i
|
|
|
2224
2224
|
active: boolean;
|
|
2225
2225
|
validFrom: string | null;
|
|
2226
2226
|
validTo: string | null;
|
|
2227
|
+
priority: number;
|
|
2227
2228
|
propertyId: string;
|
|
2228
2229
|
roomTypeId: string | null;
|
|
2229
2230
|
ratePlanId: string | null;
|
|
2230
|
-
priority: number;
|
|
2231
2231
|
minNights: number | null;
|
|
2232
2232
|
maxNights: number | null;
|
|
2233
2233
|
minAdvanceDays: number | null;
|
package/dist/service.d.ts
CHANGED
|
@@ -64,7 +64,180 @@ type UpdateRoomTypeRateInput = z.infer<typeof updateRoomTypeRateSchema>;
|
|
|
64
64
|
type StayFolioLineListQuery = z.infer<typeof stayFolioLineListQuerySchema>;
|
|
65
65
|
type CreateStayFolioLineInput = z.infer<typeof insertStayFolioLineSchema>;
|
|
66
66
|
type UpdateStayFolioLineInput = z.infer<typeof updateStayFolioLineSchema>;
|
|
67
|
+
/**
|
|
68
|
+
* Input for {@link reserveStay}. Mirrors the schema's stay_booking_items
|
|
69
|
+
* shape but consumes inventory atomically.
|
|
70
|
+
*/
|
|
71
|
+
export interface ReserveStayInput {
|
|
72
|
+
bookingItemId: string;
|
|
73
|
+
propertyId: string;
|
|
74
|
+
roomTypeId: string;
|
|
75
|
+
ratePlanId: string;
|
|
76
|
+
checkInDate: string;
|
|
77
|
+
checkOutDate: string;
|
|
78
|
+
roomCount?: number;
|
|
79
|
+
adults?: number;
|
|
80
|
+
children?: number;
|
|
81
|
+
infants?: number;
|
|
82
|
+
mealPlanId?: string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Per-night sell amounts. Length must equal nightCount; each row is
|
|
85
|
+
* inserted into `stay_daily_rates` for the corresponding night.
|
|
86
|
+
*/
|
|
87
|
+
dailyRates: Array<{
|
|
88
|
+
sellCurrency: string;
|
|
89
|
+
sellAmountCents?: number | null;
|
|
90
|
+
costCurrency?: string | null;
|
|
91
|
+
costAmountCents?: number | null;
|
|
92
|
+
taxAmountCents?: number | null;
|
|
93
|
+
feeAmountCents?: number | null;
|
|
94
|
+
commissionAmountCents?: number | null;
|
|
95
|
+
}>;
|
|
96
|
+
}
|
|
97
|
+
export type ReserveStayResult = {
|
|
98
|
+
status: "ok";
|
|
99
|
+
stayBookingItemId: string;
|
|
100
|
+
nightCount: number;
|
|
101
|
+
roomUnitId?: string | null;
|
|
102
|
+
} | {
|
|
103
|
+
status: "insufficient_capacity";
|
|
104
|
+
date: string;
|
|
105
|
+
available: number;
|
|
106
|
+
needed: number;
|
|
107
|
+
} | {
|
|
108
|
+
status: "stop_sell";
|
|
109
|
+
date: string;
|
|
110
|
+
} | {
|
|
111
|
+
status: "inventory_missing";
|
|
112
|
+
date: string;
|
|
113
|
+
} | {
|
|
114
|
+
status: "rate_count_mismatch";
|
|
115
|
+
expected: number;
|
|
116
|
+
received: number;
|
|
117
|
+
} | {
|
|
118
|
+
status: "no_unit_available";
|
|
119
|
+
} | {
|
|
120
|
+
status: "room_type_not_found";
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Per-night rate row produced by {@link resolveStayDailyRates}. Shape
|
|
124
|
+
* matches the input expected by {@link reserveStay}'s `dailyRates`.
|
|
125
|
+
*/
|
|
126
|
+
export interface ResolvedDailyRate {
|
|
127
|
+
date: string;
|
|
128
|
+
sellCurrency: string;
|
|
129
|
+
sellAmountCents: number | null;
|
|
130
|
+
extraAdultAmountCents: number | null;
|
|
131
|
+
extraChildAmountCents: number | null;
|
|
132
|
+
extraInfantAmountCents: number | null;
|
|
133
|
+
}
|
|
134
|
+
export type ResolveStayDailyRatesResult = {
|
|
135
|
+
status: "ok";
|
|
136
|
+
rates: ResolvedDailyRate[];
|
|
137
|
+
} | {
|
|
138
|
+
status: "rate_not_found";
|
|
139
|
+
ratePlanId: string;
|
|
140
|
+
roomTypeId: string;
|
|
141
|
+
} | {
|
|
142
|
+
status: "stop_sell";
|
|
143
|
+
date: string;
|
|
144
|
+
} | {
|
|
145
|
+
status: "closed_to_arrival";
|
|
146
|
+
date: string;
|
|
147
|
+
} | {
|
|
148
|
+
status: "closed_to_departure";
|
|
149
|
+
date: string;
|
|
150
|
+
};
|
|
151
|
+
export interface ResolveStayDailyRatesInput {
|
|
152
|
+
ratePlanId: string;
|
|
153
|
+
roomTypeId: string;
|
|
154
|
+
/** Inclusive ISO YYYY-MM-DD. */
|
|
155
|
+
startDate: string;
|
|
156
|
+
/** Exclusive ISO YYYY-MM-DD (hotel checkout convention). */
|
|
157
|
+
endDate: string;
|
|
158
|
+
}
|
|
67
159
|
export declare const hospitalityService: {
|
|
160
|
+
/**
|
|
161
|
+
* Resolve the per-night rate card for a (rate plan, room type, date
|
|
162
|
+
* range) tuple — produces the array shape that
|
|
163
|
+
* {@link reserveStay}'s `dailyRates` consumes.
|
|
164
|
+
*
|
|
165
|
+
* **Resolution rules:**
|
|
166
|
+
*
|
|
167
|
+
* 1. The base rate comes from `room_type_rates.baseAmountCents` for
|
|
168
|
+
* the (ratePlanId, roomTypeId) pair. Currently flat — every night
|
|
169
|
+
* in the range gets the same base amount.
|
|
170
|
+
* 2. `rate_plan_inventory_overrides` is consulted for restrictions
|
|
171
|
+
* only:
|
|
172
|
+
* - `stop_sell` on any night → typed `stop_sell` failure
|
|
173
|
+
* - `closed_to_arrival` on the FIRST night → `closed_to_arrival`
|
|
174
|
+
* - `closed_to_departure` on the night BEFORE the checkout date
|
|
175
|
+
* → `closed_to_departure`
|
|
176
|
+
* 3. Currency is taken from `room_type_rates.currencyCode`.
|
|
177
|
+
*
|
|
178
|
+
* **What this resolver does NOT (yet) do:**
|
|
179
|
+
*
|
|
180
|
+
* - Date-scoped rate variation (weekend bumps, seasonal pricing).
|
|
181
|
+
* The schema's `room_type_rates` is flat per (rate plan, room
|
|
182
|
+
* type); date-scoped variation lives on the linked
|
|
183
|
+
* `priceScheduleId` in the pricing module, which this resolver
|
|
184
|
+
* does not yet consult. Wiring price-schedule resolution is a
|
|
185
|
+
* follow-up.
|
|
186
|
+
* - Length-of-stay discounts.
|
|
187
|
+
* - Promo codes.
|
|
188
|
+
*
|
|
189
|
+
* Pass the result directly to `reserveStay`'s `dailyRates`.
|
|
190
|
+
*/
|
|
191
|
+
resolveStayDailyRates(db: PostgresJsDatabase, input: ResolveStayDailyRatesInput): Promise<ResolveStayDailyRatesResult>;
|
|
192
|
+
/**
|
|
193
|
+
* Atomically reserve a stay. Dispatches based on the room type's
|
|
194
|
+
* `inventoryMode`:
|
|
195
|
+
*
|
|
196
|
+
* - **pooled** (default): the property tracks "rooms-of-type-X
|
|
197
|
+
* available for date Y" in `room_inventory`. Multiple physical
|
|
198
|
+
* rooms are interchangeable; the desk picks one at check-in.
|
|
199
|
+
* Reserve decrements `available_units` per night via per-night
|
|
200
|
+
* `SELECT ... FOR UPDATE` row locks.
|
|
201
|
+
* - **serialized**: each `room_unit` is a specific physical room
|
|
202
|
+
* ("an instance"); the booking is bound to that unit at reserve
|
|
203
|
+
* time. Reserve picks the first available unit (sortOrder +
|
|
204
|
+
* room_number deterministic), `SELECT ... FOR UPDATE`s the
|
|
205
|
+
* chosen row, and persists the `roomUnitId` on
|
|
206
|
+
* `stay_booking_items`. Skips units covered by `room_blocks` /
|
|
207
|
+
* `maintenance_blocks` or already in an overlapping
|
|
208
|
+
* reserved/checked-in stay.
|
|
209
|
+
* - **virtual**: not yet supported by `reserveStay`. Falls through
|
|
210
|
+
* to pooled-mode logic, which will fail with
|
|
211
|
+
* `inventory_missing` if no `room_inventory` row exists.
|
|
212
|
+
*
|
|
213
|
+
* Concurrency: pooled-mode reserves serialize through per-night
|
|
214
|
+
* `room_inventory` locks; serialized-mode reserves serialize through
|
|
215
|
+
* per-unit `room_units` locks. Both produce typed
|
|
216
|
+
* `insufficient_capacity` / `no_unit_available` failures without
|
|
217
|
+
* mutating state.
|
|
218
|
+
*/
|
|
219
|
+
reserveStay(db: PostgresJsDatabase, input: ReserveStayInput): Promise<ReserveStayResult>;
|
|
220
|
+
/**
|
|
221
|
+
* Internal: serialized-mode (per-physical-room) reserve.
|
|
222
|
+
* Pooled-mode is in `reserveStay`.
|
|
223
|
+
*
|
|
224
|
+
* Picks the first available `room_unit` of the requested type by:
|
|
225
|
+
* - Excluding units in non-active status
|
|
226
|
+
* - Excluding units covered by an active `room_blocks` entry whose
|
|
227
|
+
* range overlaps the requested stay (per-unit OR property-wide
|
|
228
|
+
* roomType block)
|
|
229
|
+
* - Excluding units covered by an active `maintenance_blocks` entry
|
|
230
|
+
* on the same logic
|
|
231
|
+
* - Excluding units already occupied by a reserved or checked-in
|
|
232
|
+
* `stay_booking_items` whose date range overlaps
|
|
233
|
+
*
|
|
234
|
+
* The chosen unit is `SELECT ... FOR UPDATE`d so concurrent reserves
|
|
235
|
+
* on the same physical room serialize. The loser sees the unit
|
|
236
|
+
* already locked + occupied (after the first commits) and falls
|
|
237
|
+
* through to the next candidate, or `no_unit_available` if none
|
|
238
|
+
* remain.
|
|
239
|
+
*/
|
|
240
|
+
_reserveStaySerialized(db: PostgresJsDatabase, input: ReserveStayInput, nights: string[]): Promise<ReserveStayResult>;
|
|
68
241
|
listRoomTypes(db: PostgresJsDatabase, query: RoomTypeListQuery): Promise<{
|
|
69
242
|
data: {
|
|
70
243
|
id: string;
|
|
@@ -429,10 +602,10 @@ export declare const hospitalityService: {
|
|
|
429
602
|
description: string | null;
|
|
430
603
|
code: string;
|
|
431
604
|
active: boolean;
|
|
605
|
+
priceCatalogId: string | null;
|
|
432
606
|
sortOrder: number;
|
|
433
607
|
propertyId: string;
|
|
434
608
|
mealPlanId: string | null;
|
|
435
|
-
priceCatalogId: string | null;
|
|
436
609
|
cancellationPolicyId: string | null;
|
|
437
610
|
marketId: string | null;
|
|
438
611
|
currencyCode: string;
|
|
@@ -498,9 +671,9 @@ export declare const hospitalityService: {
|
|
|
498
671
|
id: string;
|
|
499
672
|
createdAt: Date;
|
|
500
673
|
updatedAt: Date;
|
|
674
|
+
active: boolean;
|
|
501
675
|
productId: string | null;
|
|
502
676
|
optionId: string | null;
|
|
503
|
-
active: boolean;
|
|
504
677
|
sortOrder: number;
|
|
505
678
|
roomTypeId: string;
|
|
506
679
|
ratePlanId: string;
|
|
@@ -581,10 +754,10 @@ export declare const hospitalityService: {
|
|
|
581
754
|
active: boolean;
|
|
582
755
|
validFrom: string | null;
|
|
583
756
|
validTo: string | null;
|
|
757
|
+
priority: number;
|
|
584
758
|
propertyId: string;
|
|
585
759
|
roomTypeId: string | null;
|
|
586
760
|
ratePlanId: string | null;
|
|
587
|
-
priority: number;
|
|
588
761
|
minNights: number | null;
|
|
589
762
|
maxNights: number | null;
|
|
590
763
|
minAdvanceDays: number | null;
|
|
@@ -1223,12 +1396,12 @@ export declare const hospitalityService: {
|
|
|
1223
1396
|
updatedAt: Date;
|
|
1224
1397
|
status: "in_progress" | "completed" | "cancelled" | "open";
|
|
1225
1398
|
notes: string | null;
|
|
1399
|
+
priority: number;
|
|
1226
1400
|
completedAt: Date | null;
|
|
1227
1401
|
propertyId: string;
|
|
1228
1402
|
roomUnitId: string;
|
|
1229
1403
|
stayBookingItemId: string | null;
|
|
1230
1404
|
taskType: string;
|
|
1231
|
-
priority: number;
|
|
1232
1405
|
dueAt: Date | null;
|
|
1233
1406
|
startedAt: Date | null;
|
|
1234
1407
|
assignedTo: string | null;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
|
package/dist/service.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { and, asc, desc, eq, gte, ilike, lte, or, sql } from "drizzle-orm";
|
|
1
|
+
import { and, asc, desc, eq, gte, ilike, inArray, lte, or, sql } from "drizzle-orm";
|
|
2
|
+
import { priceSchedulesRef } from "./pricing-ref.js";
|
|
2
3
|
import { housekeepingTasks, maintenanceBlocks, mealPlans, ratePlanInventoryOverrides, ratePlanRoomTypes, ratePlans, roomBlocks, roomInventory, roomTypeBedConfigs, roomTypeRates, roomTypes, roomUnitStatusEvents, roomUnits, stayBookingItems, stayCheckpoints, stayDailyRates, stayFolioLines, stayFolios, stayOperations, stayRules, stayServicePosts, } from "./schema.js";
|
|
3
4
|
async function paginate(rowsQuery, countQuery, limit, offset) {
|
|
4
5
|
const [data, countResult] = await Promise.all([rowsQuery, countQuery]);
|
|
@@ -7,7 +8,419 @@ async function paginate(rowsQuery, countQuery, limit, offset) {
|
|
|
7
8
|
function toDateOrNull(value) {
|
|
8
9
|
return value ? new Date(value) : null;
|
|
9
10
|
}
|
|
11
|
+
const WEEKDAY_CODES = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
|
|
12
|
+
/**
|
|
13
|
+
* Returns true when the given ISO date matches the schedule's
|
|
14
|
+
* weekdays + validFrom/validTo window.
|
|
15
|
+
*
|
|
16
|
+
* Schedule matching is intentionally simple: the
|
|
17
|
+
* `recurrenceRule` (an iCal RRULE string) is NOT parsed. Production
|
|
18
|
+
* uses set the `weekdays` JSON array (e.g. `["fri", "sat"]`) and
|
|
19
|
+
* `validFrom` / `validTo` for the date window. Anything beyond
|
|
20
|
+
* that — exception dates, monthly recurrences — needs RRULE parsing
|
|
21
|
+
* which is a follow-up.
|
|
22
|
+
*/
|
|
23
|
+
function scheduleMatchesDate(schedule, isoDate) {
|
|
24
|
+
if (schedule.validFrom && isoDate < schedule.validFrom)
|
|
25
|
+
return false;
|
|
26
|
+
if (schedule.validTo && isoDate > schedule.validTo)
|
|
27
|
+
return false;
|
|
28
|
+
if (schedule.weekdays && schedule.weekdays.length > 0) {
|
|
29
|
+
const dayCode = WEEKDAY_CODES[new Date(`${isoDate}T00:00:00Z`).getUTCDay()];
|
|
30
|
+
const normalized = schedule.weekdays.map((d) => d.toLowerCase().slice(0, 3));
|
|
31
|
+
if (!normalized.includes(dayCode))
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Pick the winning rate row for a given date from a set of candidate
|
|
38
|
+
* rate rows. Rules with a higher-priority matching schedule beat
|
|
39
|
+
* lower-priority ones; if no schedule matches, the default
|
|
40
|
+
* (null-schedule) rule is returned.
|
|
41
|
+
*/
|
|
42
|
+
function pickRateForDate(date, rateRows, schedulesById, defaultRate) {
|
|
43
|
+
let winner = defaultRate;
|
|
44
|
+
let winnerPriority = Number.NEGATIVE_INFINITY;
|
|
45
|
+
for (const row of rateRows) {
|
|
46
|
+
if (!row.priceScheduleId)
|
|
47
|
+
continue;
|
|
48
|
+
const schedule = schedulesById.get(row.priceScheduleId);
|
|
49
|
+
if (!schedule)
|
|
50
|
+
continue;
|
|
51
|
+
if (!scheduleMatchesDate(schedule, date))
|
|
52
|
+
continue;
|
|
53
|
+
if (schedule.priority > winnerPriority) {
|
|
54
|
+
winner = row;
|
|
55
|
+
winnerPriority = schedule.priority;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return winner;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Iterate the dates from `start` (inclusive) to `end` (exclusive) as
|
|
62
|
+
* ISO YYYY-MM-DD strings. Hotel "nights" — checking out on the
|
|
63
|
+
* `endDate` does not consume that date's inventory.
|
|
64
|
+
*/
|
|
65
|
+
function eachNight(startDate, endDate) {
|
|
66
|
+
const out = [];
|
|
67
|
+
const start = new Date(`${startDate}T00:00:00Z`);
|
|
68
|
+
const end = new Date(`${endDate}T00:00:00Z`);
|
|
69
|
+
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
|
|
70
|
+
throw new Error("eachNight: invalid date input");
|
|
71
|
+
}
|
|
72
|
+
for (let cursor = start; cursor < end; cursor = new Date(cursor.getTime() + 24 * 60 * 60 * 1000)) {
|
|
73
|
+
out.push(cursor.toISOString().slice(0, 10));
|
|
74
|
+
}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
10
77
|
export const hospitalityService = {
|
|
78
|
+
/**
|
|
79
|
+
* Resolve the per-night rate card for a (rate plan, room type, date
|
|
80
|
+
* range) tuple — produces the array shape that
|
|
81
|
+
* {@link reserveStay}'s `dailyRates` consumes.
|
|
82
|
+
*
|
|
83
|
+
* **Resolution rules:**
|
|
84
|
+
*
|
|
85
|
+
* 1. The base rate comes from `room_type_rates.baseAmountCents` for
|
|
86
|
+
* the (ratePlanId, roomTypeId) pair. Currently flat — every night
|
|
87
|
+
* in the range gets the same base amount.
|
|
88
|
+
* 2. `rate_plan_inventory_overrides` is consulted for restrictions
|
|
89
|
+
* only:
|
|
90
|
+
* - `stop_sell` on any night → typed `stop_sell` failure
|
|
91
|
+
* - `closed_to_arrival` on the FIRST night → `closed_to_arrival`
|
|
92
|
+
* - `closed_to_departure` on the night BEFORE the checkout date
|
|
93
|
+
* → `closed_to_departure`
|
|
94
|
+
* 3. Currency is taken from `room_type_rates.currencyCode`.
|
|
95
|
+
*
|
|
96
|
+
* **What this resolver does NOT (yet) do:**
|
|
97
|
+
*
|
|
98
|
+
* - Date-scoped rate variation (weekend bumps, seasonal pricing).
|
|
99
|
+
* The schema's `room_type_rates` is flat per (rate plan, room
|
|
100
|
+
* type); date-scoped variation lives on the linked
|
|
101
|
+
* `priceScheduleId` in the pricing module, which this resolver
|
|
102
|
+
* does not yet consult. Wiring price-schedule resolution is a
|
|
103
|
+
* follow-up.
|
|
104
|
+
* - Length-of-stay discounts.
|
|
105
|
+
* - Promo codes.
|
|
106
|
+
*
|
|
107
|
+
* Pass the result directly to `reserveStay`'s `dailyRates`.
|
|
108
|
+
*/
|
|
109
|
+
async resolveStayDailyRates(db, input) {
|
|
110
|
+
const nights = eachNight(input.startDate, input.endDate);
|
|
111
|
+
if (nights.length === 0) {
|
|
112
|
+
return { status: "ok", rates: [] };
|
|
113
|
+
}
|
|
114
|
+
// Pull every active rate row for the (ratePlanId, roomTypeId) pair.
|
|
115
|
+
// Multiple rows are allowed when each carries a different
|
|
116
|
+
// priceScheduleId (uidx_room_type_rates_plan_room_schedule); the
|
|
117
|
+
// null-schedule row is the default that applies when no schedule
|
|
118
|
+
// matches a given night.
|
|
119
|
+
const rateRows = await db
|
|
120
|
+
.select()
|
|
121
|
+
.from(roomTypeRates)
|
|
122
|
+
.where(and(eq(roomTypeRates.ratePlanId, input.ratePlanId), eq(roomTypeRates.roomTypeId, input.roomTypeId), eq(roomTypeRates.active, true)));
|
|
123
|
+
if (rateRows.length === 0) {
|
|
124
|
+
return {
|
|
125
|
+
status: "rate_not_found",
|
|
126
|
+
ratePlanId: input.ratePlanId,
|
|
127
|
+
roomTypeId: input.roomTypeId,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const defaultRate = rateRows.find((r) => r.priceScheduleId === null) ?? rateRows[0];
|
|
131
|
+
// Load schedules referenced by any non-default rate row. Cross-domain
|
|
132
|
+
// read via the local pricing-ref column mirror.
|
|
133
|
+
const scheduleIds = rateRows
|
|
134
|
+
.map((r) => r.priceScheduleId)
|
|
135
|
+
.filter((id) => Boolean(id));
|
|
136
|
+
const schedules = scheduleIds.length === 0
|
|
137
|
+
? []
|
|
138
|
+
: await db
|
|
139
|
+
.select()
|
|
140
|
+
.from(priceSchedulesRef)
|
|
141
|
+
.where(and(inArray(priceSchedulesRef.id, scheduleIds), eq(priceSchedulesRef.active, true)));
|
|
142
|
+
const schedulesById = new Map(schedules.map((s) => [s.id, s]));
|
|
143
|
+
const overrides = await db
|
|
144
|
+
.select()
|
|
145
|
+
.from(ratePlanInventoryOverrides)
|
|
146
|
+
.where(and(eq(ratePlanInventoryOverrides.ratePlanId, input.ratePlanId), eq(ratePlanInventoryOverrides.roomTypeId, input.roomTypeId), gte(ratePlanInventoryOverrides.date, nights[0]), lte(ratePlanInventoryOverrides.date, nights[nights.length - 1])));
|
|
147
|
+
const overridesByDate = new Map();
|
|
148
|
+
for (const ov of overrides) {
|
|
149
|
+
overridesByDate.set(ov.date, ov);
|
|
150
|
+
}
|
|
151
|
+
// Stop-sell on any night → reject the whole range
|
|
152
|
+
for (const date of nights) {
|
|
153
|
+
const ov = overridesByDate.get(date);
|
|
154
|
+
if (ov?.stopSell) {
|
|
155
|
+
return { status: "stop_sell", date };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Closed-to-arrival on the first night → reject
|
|
159
|
+
const firstNight = nights[0];
|
|
160
|
+
if (overridesByDate.get(firstNight)?.closedToArrival) {
|
|
161
|
+
return { status: "closed_to_arrival", date: firstNight };
|
|
162
|
+
}
|
|
163
|
+
// Closed-to-departure on the last night before checkout → reject.
|
|
164
|
+
const lastNight = nights[nights.length - 1];
|
|
165
|
+
if (overridesByDate.get(lastNight)?.closedToDeparture) {
|
|
166
|
+
return { status: "closed_to_departure", date: lastNight };
|
|
167
|
+
}
|
|
168
|
+
// For each night, pick the rate row whose linked schedule matches.
|
|
169
|
+
// Higher priority wins; if no schedule matches, fall back to the
|
|
170
|
+
// default (null-schedule) row.
|
|
171
|
+
const rates = nights.map((date) => {
|
|
172
|
+
const winner = pickRateForDate(date, rateRows, schedulesById, defaultRate);
|
|
173
|
+
return {
|
|
174
|
+
date,
|
|
175
|
+
sellCurrency: winner.currencyCode,
|
|
176
|
+
sellAmountCents: winner.baseAmountCents,
|
|
177
|
+
extraAdultAmountCents: winner.extraAdultAmountCents,
|
|
178
|
+
extraChildAmountCents: winner.extraChildAmountCents,
|
|
179
|
+
extraInfantAmountCents: winner.extraInfantAmountCents,
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
return { status: "ok", rates };
|
|
183
|
+
},
|
|
184
|
+
/**
|
|
185
|
+
* Atomically reserve a stay. Dispatches based on the room type's
|
|
186
|
+
* `inventoryMode`:
|
|
187
|
+
*
|
|
188
|
+
* - **pooled** (default): the property tracks "rooms-of-type-X
|
|
189
|
+
* available for date Y" in `room_inventory`. Multiple physical
|
|
190
|
+
* rooms are interchangeable; the desk picks one at check-in.
|
|
191
|
+
* Reserve decrements `available_units` per night via per-night
|
|
192
|
+
* `SELECT ... FOR UPDATE` row locks.
|
|
193
|
+
* - **serialized**: each `room_unit` is a specific physical room
|
|
194
|
+
* ("an instance"); the booking is bound to that unit at reserve
|
|
195
|
+
* time. Reserve picks the first available unit (sortOrder +
|
|
196
|
+
* room_number deterministic), `SELECT ... FOR UPDATE`s the
|
|
197
|
+
* chosen row, and persists the `roomUnitId` on
|
|
198
|
+
* `stay_booking_items`. Skips units covered by `room_blocks` /
|
|
199
|
+
* `maintenance_blocks` or already in an overlapping
|
|
200
|
+
* reserved/checked-in stay.
|
|
201
|
+
* - **virtual**: not yet supported by `reserveStay`. Falls through
|
|
202
|
+
* to pooled-mode logic, which will fail with
|
|
203
|
+
* `inventory_missing` if no `room_inventory` row exists.
|
|
204
|
+
*
|
|
205
|
+
* Concurrency: pooled-mode reserves serialize through per-night
|
|
206
|
+
* `room_inventory` locks; serialized-mode reserves serialize through
|
|
207
|
+
* per-unit `room_units` locks. Both produce typed
|
|
208
|
+
* `insufficient_capacity` / `no_unit_available` failures without
|
|
209
|
+
* mutating state.
|
|
210
|
+
*/
|
|
211
|
+
async reserveStay(db, input) {
|
|
212
|
+
const nights = eachNight(input.checkInDate, input.checkOutDate);
|
|
213
|
+
if (nights.length === 0) {
|
|
214
|
+
return { status: "rate_count_mismatch", expected: 0, received: input.dailyRates.length };
|
|
215
|
+
}
|
|
216
|
+
if (input.dailyRates.length !== nights.length) {
|
|
217
|
+
return {
|
|
218
|
+
status: "rate_count_mismatch",
|
|
219
|
+
expected: nights.length,
|
|
220
|
+
received: input.dailyRates.length,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// Look up the room type to dispatch by inventory mode.
|
|
224
|
+
const [roomType] = await db
|
|
225
|
+
.select({ id: roomTypes.id, inventoryMode: roomTypes.inventoryMode })
|
|
226
|
+
.from(roomTypes)
|
|
227
|
+
.where(eq(roomTypes.id, input.roomTypeId))
|
|
228
|
+
.limit(1);
|
|
229
|
+
if (!roomType) {
|
|
230
|
+
return { status: "room_type_not_found" };
|
|
231
|
+
}
|
|
232
|
+
if (roomType.inventoryMode === "serialized") {
|
|
233
|
+
return this._reserveStaySerialized(db, input, nights);
|
|
234
|
+
}
|
|
235
|
+
const roomCount = input.roomCount ?? 1;
|
|
236
|
+
return db.transaction(async (tx) => {
|
|
237
|
+
// Lock + check inventory for every night. Order by date so two
|
|
238
|
+
// concurrent reserves with overlapping ranges always grab locks in
|
|
239
|
+
// the same order — no deadlock possible.
|
|
240
|
+
for (const date of nights) {
|
|
241
|
+
const rows = await tx.execute(sql `
|
|
242
|
+
SELECT id, available_units, stop_sell
|
|
243
|
+
FROM ${roomInventory}
|
|
244
|
+
WHERE ${roomInventory.roomTypeId} = ${input.roomTypeId}
|
|
245
|
+
AND ${roomInventory.date} = ${date}
|
|
246
|
+
FOR UPDATE
|
|
247
|
+
`);
|
|
248
|
+
const row = rows[0];
|
|
249
|
+
if (!row) {
|
|
250
|
+
return { status: "inventory_missing", date };
|
|
251
|
+
}
|
|
252
|
+
if (row.stop_sell) {
|
|
253
|
+
return { status: "stop_sell", date };
|
|
254
|
+
}
|
|
255
|
+
if (row.available_units < roomCount) {
|
|
256
|
+
return {
|
|
257
|
+
status: "insufficient_capacity",
|
|
258
|
+
date,
|
|
259
|
+
available: row.available_units,
|
|
260
|
+
needed: roomCount,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// All nights have capacity. Decrement.
|
|
265
|
+
for (const date of nights) {
|
|
266
|
+
await tx
|
|
267
|
+
.update(roomInventory)
|
|
268
|
+
.set({
|
|
269
|
+
availableUnits: sql `${roomInventory.availableUnits} - ${roomCount}`,
|
|
270
|
+
heldUnits: sql `${roomInventory.heldUnits} + ${roomCount}`,
|
|
271
|
+
updatedAt: new Date(),
|
|
272
|
+
})
|
|
273
|
+
.where(and(eq(roomInventory.roomTypeId, input.roomTypeId), eq(roomInventory.date, date)));
|
|
274
|
+
}
|
|
275
|
+
// Insert the stay row.
|
|
276
|
+
const [stayRow] = await tx
|
|
277
|
+
.insert(stayBookingItems)
|
|
278
|
+
.values({
|
|
279
|
+
bookingItemId: input.bookingItemId,
|
|
280
|
+
propertyId: input.propertyId,
|
|
281
|
+
roomTypeId: input.roomTypeId,
|
|
282
|
+
ratePlanId: input.ratePlanId,
|
|
283
|
+
mealPlanId: input.mealPlanId ?? null,
|
|
284
|
+
checkInDate: input.checkInDate,
|
|
285
|
+
checkOutDate: input.checkOutDate,
|
|
286
|
+
nightCount: nights.length,
|
|
287
|
+
roomCount,
|
|
288
|
+
adults: input.adults ?? 1,
|
|
289
|
+
children: input.children ?? 0,
|
|
290
|
+
infants: input.infants ?? 0,
|
|
291
|
+
status: "reserved",
|
|
292
|
+
})
|
|
293
|
+
.returning();
|
|
294
|
+
if (!stayRow) {
|
|
295
|
+
throw new Error("reserveStay: stay_booking_items insert returned no rows");
|
|
296
|
+
}
|
|
297
|
+
// Insert the per-night rate rows in lockstep with the date range.
|
|
298
|
+
await tx.insert(stayDailyRates).values(nights.map((date, idx) => {
|
|
299
|
+
const rate = input.dailyRates[idx];
|
|
300
|
+
return {
|
|
301
|
+
stayBookingItemId: stayRow.id,
|
|
302
|
+
date,
|
|
303
|
+
sellCurrency: rate.sellCurrency,
|
|
304
|
+
sellAmountCents: rate.sellAmountCents ?? null,
|
|
305
|
+
costCurrency: rate.costCurrency ?? null,
|
|
306
|
+
costAmountCents: rate.costAmountCents ?? null,
|
|
307
|
+
taxAmountCents: rate.taxAmountCents ?? null,
|
|
308
|
+
feeAmountCents: rate.feeAmountCents ?? null,
|
|
309
|
+
commissionAmountCents: rate.commissionAmountCents ?? null,
|
|
310
|
+
};
|
|
311
|
+
}));
|
|
312
|
+
return { status: "ok", stayBookingItemId: stayRow.id, nightCount: nights.length };
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
/**
|
|
316
|
+
* Internal: serialized-mode (per-physical-room) reserve.
|
|
317
|
+
* Pooled-mode is in `reserveStay`.
|
|
318
|
+
*
|
|
319
|
+
* Picks the first available `room_unit` of the requested type by:
|
|
320
|
+
* - Excluding units in non-active status
|
|
321
|
+
* - Excluding units covered by an active `room_blocks` entry whose
|
|
322
|
+
* range overlaps the requested stay (per-unit OR property-wide
|
|
323
|
+
* roomType block)
|
|
324
|
+
* - Excluding units covered by an active `maintenance_blocks` entry
|
|
325
|
+
* on the same logic
|
|
326
|
+
* - Excluding units already occupied by a reserved or checked-in
|
|
327
|
+
* `stay_booking_items` whose date range overlaps
|
|
328
|
+
*
|
|
329
|
+
* The chosen unit is `SELECT ... FOR UPDATE`d so concurrent reserves
|
|
330
|
+
* on the same physical room serialize. The loser sees the unit
|
|
331
|
+
* already locked + occupied (after the first commits) and falls
|
|
332
|
+
* through to the next candidate, or `no_unit_available` if none
|
|
333
|
+
* remain.
|
|
334
|
+
*/
|
|
335
|
+
async _reserveStaySerialized(db, input, nights) {
|
|
336
|
+
return db.transaction(async (tx) => {
|
|
337
|
+
// Find + lock the first available unit. The query mirrors the
|
|
338
|
+
// logic enumerated in the docstring above. We use FOR UPDATE so
|
|
339
|
+
// concurrent reserves serialize on the chosen unit.
|
|
340
|
+
const candidates = await tx.execute(sql `
|
|
341
|
+
SELECT u.id
|
|
342
|
+
FROM ${roomUnits} u
|
|
343
|
+
WHERE u.room_type_id = ${input.roomTypeId}
|
|
344
|
+
AND u.status = 'active'
|
|
345
|
+
AND NOT EXISTS (
|
|
346
|
+
SELECT 1 FROM ${roomBlocks} b
|
|
347
|
+
WHERE (
|
|
348
|
+
b.room_unit_id = u.id
|
|
349
|
+
OR (b.room_type_id = u.room_type_id AND b.room_unit_id IS NULL)
|
|
350
|
+
)
|
|
351
|
+
AND b.status IN ('held', 'confirmed')
|
|
352
|
+
AND b.starts_on < ${input.checkOutDate}
|
|
353
|
+
AND b.ends_on > ${input.checkInDate}
|
|
354
|
+
)
|
|
355
|
+
AND NOT EXISTS (
|
|
356
|
+
SELECT 1 FROM ${maintenanceBlocks} m
|
|
357
|
+
WHERE (
|
|
358
|
+
m.room_unit_id = u.id
|
|
359
|
+
OR (m.room_type_id = u.room_type_id AND m.room_unit_id IS NULL)
|
|
360
|
+
)
|
|
361
|
+
AND m.status IN ('open', 'in_progress')
|
|
362
|
+
AND m.starts_on < ${input.checkOutDate}
|
|
363
|
+
AND m.ends_on > ${input.checkInDate}
|
|
364
|
+
)
|
|
365
|
+
AND NOT EXISTS (
|
|
366
|
+
SELECT 1 FROM ${stayBookingItems} s
|
|
367
|
+
WHERE s.room_unit_id = u.id
|
|
368
|
+
AND s.status IN ('reserved', 'checked_in')
|
|
369
|
+
AND s.check_in_date < ${input.checkOutDate}
|
|
370
|
+
AND s.check_out_date > ${input.checkInDate}
|
|
371
|
+
)
|
|
372
|
+
ORDER BY u.code NULLS LAST, u.room_number NULLS LAST, u.id
|
|
373
|
+
LIMIT 1
|
|
374
|
+
FOR UPDATE
|
|
375
|
+
`);
|
|
376
|
+
const candidate = candidates[0];
|
|
377
|
+
if (!candidate) {
|
|
378
|
+
return { status: "no_unit_available" };
|
|
379
|
+
}
|
|
380
|
+
const [stayRow] = await tx
|
|
381
|
+
.insert(stayBookingItems)
|
|
382
|
+
.values({
|
|
383
|
+
bookingItemId: input.bookingItemId,
|
|
384
|
+
propertyId: input.propertyId,
|
|
385
|
+
roomTypeId: input.roomTypeId,
|
|
386
|
+
roomUnitId: candidate.id,
|
|
387
|
+
ratePlanId: input.ratePlanId,
|
|
388
|
+
mealPlanId: input.mealPlanId ?? null,
|
|
389
|
+
checkInDate: input.checkInDate,
|
|
390
|
+
checkOutDate: input.checkOutDate,
|
|
391
|
+
nightCount: nights.length,
|
|
392
|
+
roomCount: input.roomCount ?? 1,
|
|
393
|
+
adults: input.adults ?? 1,
|
|
394
|
+
children: input.children ?? 0,
|
|
395
|
+
infants: input.infants ?? 0,
|
|
396
|
+
status: "reserved",
|
|
397
|
+
})
|
|
398
|
+
.returning();
|
|
399
|
+
if (!stayRow) {
|
|
400
|
+
throw new Error("_reserveStayInstance: stay_booking_items insert returned no rows");
|
|
401
|
+
}
|
|
402
|
+
await tx.insert(stayDailyRates).values(nights.map((date, idx) => {
|
|
403
|
+
const rate = input.dailyRates[idx];
|
|
404
|
+
return {
|
|
405
|
+
stayBookingItemId: stayRow.id,
|
|
406
|
+
date,
|
|
407
|
+
sellCurrency: rate.sellCurrency,
|
|
408
|
+
sellAmountCents: rate.sellAmountCents ?? null,
|
|
409
|
+
costCurrency: rate.costCurrency ?? null,
|
|
410
|
+
costAmountCents: rate.costAmountCents ?? null,
|
|
411
|
+
taxAmountCents: rate.taxAmountCents ?? null,
|
|
412
|
+
feeAmountCents: rate.feeAmountCents ?? null,
|
|
413
|
+
commissionAmountCents: rate.commissionAmountCents ?? null,
|
|
414
|
+
};
|
|
415
|
+
}));
|
|
416
|
+
return {
|
|
417
|
+
status: "ok",
|
|
418
|
+
stayBookingItemId: stayRow.id,
|
|
419
|
+
nightCount: nights.length,
|
|
420
|
+
roomUnitId: candidate.id,
|
|
421
|
+
};
|
|
422
|
+
});
|
|
423
|
+
},
|
|
11
424
|
async listRoomTypes(db, query) {
|
|
12
425
|
const conditions = [];
|
|
13
426
|
if (query.propertyId)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/hospitality",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"license": "FSL-1.1-Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,14 +25,15 @@
|
|
|
25
25
|
"drizzle-orm": "^0.45.2",
|
|
26
26
|
"hono": "^4.12.10",
|
|
27
27
|
"zod": "^4.3.6",
|
|
28
|
-
"@voyantjs/bookings": "0.
|
|
29
|
-
"@voyantjs/core": "0.
|
|
30
|
-
"@voyantjs/db": "0.
|
|
31
|
-
"@voyantjs/facilities": "0.
|
|
32
|
-
"@voyantjs/hono": "0.
|
|
28
|
+
"@voyantjs/bookings": "0.11.0",
|
|
29
|
+
"@voyantjs/core": "0.11.0",
|
|
30
|
+
"@voyantjs/db": "0.11.0",
|
|
31
|
+
"@voyantjs/facilities": "0.11.0",
|
|
32
|
+
"@voyantjs/hono": "0.11.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"typescript": "^6.0.2",
|
|
36
|
+
"@voyantjs/pricing": "0.11.0",
|
|
36
37
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
37
38
|
},
|
|
38
39
|
"files": [
|