// Boka Gasol247 — Prisma schema // SQLite for MVP. Migrating to Postgres later: change provider + DATABASE_URL. generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" url = env("DATABASE_URL") } // Singleton settings row. Always accessed with id = "singleton" so we never // have more than one row. Add new fields as feature flags grow. model Settings { id String @id @default("singleton") pickupEnabled Boolean @default(true) updatedAt DateTime @updatedAt } model Admin { id String @id @default(cuid()) email String @unique name String passwordHash String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Product { id String @id @default(cuid()) sku String @unique nameSv String nameEn String descriptionSv String descriptionEn String // Price in öre (SEK * 100) to avoid float issues. priceOre Int // VAT in basis points (e.g. 2500 = 25.00%). vatBp Int @default(2500) active Boolean @default(true) sortOrder Int @default(0) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt bookingItems BookingItem[] } model PickupSlot { id String @id @default(cuid()) // Human label fallback (e.g. "Måndag förmiddag"). labelSv String labelEn String startsAt DateTime endsAt DateTime capacity Int @default(50) active Boolean @default(true) bookings Booking[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } // BookingStatus values (string, since SQLite has no enums): // PENDING | CONFIRMED // DELIVERED_PARTIAL | DELIVERED (handout out, none returned) // RETURNED_PARTIAL | RETURNED (everything has come back) // INVOICED (billing done, terminal) // CANCELLED (terminal) // Derived statuses (DELIVERED*/RETURNED*) are normally auto-set from item // counters; INVOICED and CANCELLED are set explicitly by admin. model Booking { id String @id @default(cuid()) bookingNumber String @unique status String @default("CONFIRMED") // Contact contactName String email String phone String // Organization orgName String orgNumber String // Invoice address address String postalCode String city String country String @default("SE") // Pickup pickupSlotId String? pickupSlot PickupSlot? @relation(fields: [pickupSlotId], references: [id]) notes String? // Snapshots in öre at booking time subtotalOre Int vatOre Int totalOre Int locale String @default("sv") items BookingItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([createdAt]) @@index([status]) } model BookingItem { id String @id @default(cuid()) bookingId String booking Booking @relation(fields: [bookingId], references: [id], onDelete: Cascade) productId String product Product @relation(fields: [productId], references: [id]) // Snapshots so historical bookings don't break if a product changes sku String nameSv String nameEn String unitPriceOre Int vatBp Int quantity Int lineTotalOre Int // Fulfillment tracking — set by admin as cylinders go out and come back. // Invariants: 0 <= deliveredQuantity <= quantity // 0 <= returnedQuantity <= deliveredQuantity deliveredQuantity Int @default(0) returnedQuantity Int @default(0) @@index([bookingId]) }