import { afterAll, beforeEach, describe, expect, it } from "vitest"; import db from "../../app/db.server"; import redis from "../../app/lib/redis.server"; import { createBookingFromOrder } from "../../app/services/booking.server"; import { countActiveHolds, tryCreateHold } from "../../app/services/holds.server"; const shopDomain = "booking-integration-test.myshopify.com"; async function cleanup() { await db.booking.deleteMany({ where: { shopDomain } }); await db.location.deleteMany({ where: { shopDomain } }); await db.shop.deleteMany({ where: { shopDomain } }); } describe("createBookingFromOrder", () => { beforeEach(cleanup); afterAll(async () => { await cleanup(); await db.$disconnect(); await redis.quit(); }); it("creates a Booking from an order's dd_* attributes and releases the matching hold", async () => { const location = await db.location.create({ data: { shopDomain, name: "Test Location", address: "", timezone: "America/Toronto" }, }); const slot = { shopDomain, locationId: location.id, method: "PICKUP" as const, slotStartIso: "2026-08-25T13:00:00.000Z", }; await tryCreateHold(slot, "cart_abc123", 5); expect(await countActiveHolds(slot)).toBe(1); await createBookingFromOrder(shopDomain, { admin_graphql_api_id: "gid://shopify/Order/1", name: "#1001", cart_token: "cart_abc123", email: "shopper@example.com", note_attributes: [ { name: "dd_method", value: "PICKUP" }, { name: "dd_date", value: "2026-08-25" }, { name: "dd_start_min", value: "540" }, { name: "dd_end_min", value: "600" }, { name: "dd_location_id", value: location.id }, ], }); const booking = await db.booking.findUnique({ where: { orderId: "gid://shopify/Order/1" } }); expect(booking).not.toBeNull(); expect(booking?.method).toBe("PICKUP"); expect(booking?.status).toBe("confirmed"); expect(booking?.customerEmail).toBe("shopper@example.com"); expect(booking?.slotStart.toISOString()).toBe("2026-08-25T13:00:00.000Z"); // 9 AM EDT // The hold this order consumed should now be released. expect(await countActiveHolds(slot)).toBe(0); }); it("is idempotent — a redelivered webhook does not create a second Booking", async () => { const location = await db.location.create({ data: { shopDomain, name: "Test Location", address: "", timezone: "America/Toronto" }, }); const order = { admin_graphql_api_id: "gid://shopify/Order/2", note_attributes: [ { name: "dd_method", value: "PICKUP" }, { name: "dd_date", value: "2026-08-25" }, { name: "dd_start_min", value: "540" }, { name: "dd_end_min", value: "600" }, { name: "dd_location_id", value: location.id }, ], }; await createBookingFromOrder(shopDomain, order); await createBookingFromOrder(shopDomain, order); // redelivery const count = await db.booking.count({ where: { shopDomain, orderId: "gid://shopify/Order/2" } }); expect(count).toBe(1); }); it("does nothing for an order with no scheduling attributes", async () => { await createBookingFromOrder(shopDomain, { admin_graphql_api_id: "gid://shopify/Order/3", note_attributes: [] }); const count = await db.booking.count({ where: { shopDomain, orderId: "gid://shopify/Order/3" } }); expect(count).toBe(0); }); it("converts total_price to integer cents for the dashboard's revenue view", async () => { const location = await db.location.create({ data: { shopDomain, name: "Test Location", address: "", timezone: "America/Toronto" }, }); await createBookingFromOrder(shopDomain, { admin_graphql_api_id: "gid://shopify/Order/4", total_price: "49.99", note_attributes: [ { name: "dd_method", value: "PICKUP" }, { name: "dd_date", value: "2026-08-25" }, { name: "dd_start_min", value: "540" }, { name: "dd_end_min", value: "600" }, { name: "dd_location_id", value: location.id }, ], }); const booking = await db.booking.findUnique({ where: { orderId: "gid://shopify/Order/4" } }); expect(booking?.totalPriceCents).toBe(4999); }); it("leaves totalPriceCents unset when total_price is missing", async () => { const location = await db.location.create({ data: { shopDomain, name: "Test Location", address: "", timezone: "America/Toronto" }, }); await createBookingFromOrder(shopDomain, { admin_graphql_api_id: "gid://shopify/Order/5", note_attributes: [ { name: "dd_method", value: "PICKUP" }, { name: "dd_date", value: "2026-08-25" }, { name: "dd_start_min", value: "540" }, { name: "dd_end_min", value: "600" }, { name: "dd_location_id", value: location.id }, ], }); const booking = await db.booking.findUnique({ where: { orderId: "gid://shopify/Order/5" } }); expect(booking?.totalPriceCents).toBeNull(); }); });