136 lines
3.7 KiB
Plaintext
136 lines
3.7 KiB
Plaintext
// 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])
|
|
}
|