feat(backend): auto-assign + transactional double-booking guard + working-hours slots
POST /book and POST /appointments now resolve the specialist via autoAssign (or isAvailable-guard a chosen one) inside BEGIN IMMEDIATE...COMMIT, returning 409 on conflict. Slots endpoint derives the day window from real working_hours and ranks the best specialist per slot. settings/employees expose + persist the new fields. Adds booking-e2e.mjs and adapts e2e-test.mjs fixtures to in-hours slots.
This commit is contained in:
@@ -17,13 +17,16 @@ const FIELDS = [
|
||||
"require_deposit",
|
||||
"deposit_pct",
|
||||
"timezone",
|
||||
"auto_assign_specialist",
|
||||
"working_hours",
|
||||
] as const;
|
||||
|
||||
settingsRouter.get("/", (req: AuthedRequest, res) => {
|
||||
const b = db
|
||||
.prepare(
|
||||
`SELECT id, name, industry, currency, currency_symbol, phone, address, slug, booking_enabled,
|
||||
cancel_window_hours, cancel_penalty_pct, require_deposit, deposit_pct, timezone
|
||||
cancel_window_hours, cancel_penalty_pct, require_deposit, deposit_pct, timezone,
|
||||
auto_assign_specialist, working_hours
|
||||
FROM businesses WHERE id = ?`
|
||||
)
|
||||
.get(req.user!.business_id) as any;
|
||||
@@ -39,6 +42,12 @@ settingsRouter.patch("/", ownerOnly, (req: AuthedRequest, res) => {
|
||||
for (const f of FIELDS) {
|
||||
if (body[f] !== undefined) merged[f] = body[f];
|
||||
}
|
||||
if (merged.working_hours && typeof merged.working_hours !== "string") {
|
||||
merged.working_hours = JSON.stringify(merged.working_hours);
|
||||
}
|
||||
if (merged.auto_assign_specialist !== undefined) {
|
||||
merged.auto_assign_specialist = merged.auto_assign_specialist ? 1 : 0;
|
||||
}
|
||||
// slug uniqueness check
|
||||
if (merged.slug !== undefined) {
|
||||
merged.slug = String(merged.slug).trim().toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
||||
@@ -51,7 +60,7 @@ settingsRouter.patch("/", ownerOnly, (req: AuthedRequest, res) => {
|
||||
merged.id = req.user!.business_id;
|
||||
db.prepare(`UPDATE businesses SET ${sets.join(", ")} WHERE id = @id`).run(merged);
|
||||
const updated = db
|
||||
.prepare(`SELECT id, name, industry, currency, currency_symbol, phone, address, slug, booking_enabled, cancel_window_hours, cancel_penalty_pct, require_deposit, deposit_pct, timezone FROM businesses WHERE id = ?`)
|
||||
.prepare(`SELECT id, name, industry, currency, currency_symbol, phone, address, slug, booking_enabled, cancel_window_hours, cancel_penalty_pct, require_deposit, deposit_pct, timezone, auto_assign_specialist, working_hours FROM businesses WHERE id = ?`)
|
||||
.get(req.user!.business_id);
|
||||
res.json({ settings: updated });
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user