// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema // Get a free hosted Postgres database in seconds: `npx create-db` generator client { provider = "prisma-client" output = "./generated/" } datasource db { provider = "postgresql" } /// Product category, mirrored from Hiboutik. Categories form a tree (parent / children). model Category { id String @id @default(uuid()) updatedAt DateTime @updatedAt /// Enabled in the Hiboutik POS (category_enabled) enabled Boolean @default(true) hiboutikId Int @unique name String /// Display order among its siblings (category_position) position Int @default(0) /// Displayed on the website (category_enabled_www) webEnabled Boolean @default(true) /// Null for a root category parent Category? @relation("CategoryTree", fields: [parentId], references: [id], onDelete: SetNull) parentId String? children Category[] @relation("CategoryTree") products Product[] @@map("categories") } /// Product brand, mirrored from Hiboutik. model Brand { id String @id @default(uuid()) updatedAt DateTime @updatedAt enabled Boolean @default(true) hiboutikId Int @unique name String products Product[] @@map("brands") } /// Product supplier, mirrored from Hiboutik. model Supplier { id String @id @default(uuid()) updatedAt DateTime @updatedAt enabled Boolean @default(true) hiboutikId Int @unique name String products Product[] @@map("suppliers") } /// Product mirrored from Hiboutik. What is actually sold is one of its versions (sizes). model Product { id String @id @default(uuid()) updatedAt DateTime @updatedAt /// Archived in Hiboutik (product_arch) archived Boolean @default(false) barcode String? description String /// Null when the product has no discount discountPrice Decimal? @db.Decimal(10, 2) /// Displayed on the website (product_display_www) enabled Boolean @default(true) /// Sum of the available stock of all its versions globalStock Int @default(0) hiboutikId Int @unique /// Last update in Hiboutik hiboutikUpdatedAt DateTime? name String price Decimal @db.Decimal(10, 2) brand Brand? @relation(fields: [brandId], references: [id], onDelete: SetNull) brandId String? category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull) categoryId String? supplier Supplier? @relation(fields: [supplierId], references: [id], onDelete: SetNull) supplierId String? versions ProductVersion[] @@map("products") } /// Sellable version of a product: one per Hiboutik size, or a single one (hiboutikSizeId 0) for a product without sizes. model ProductVersion { id String @id @default(uuid()) updatedAt DateTime @updatedAt /// Not unique: Hiboutik is the source of truth and may hold the same barcode on several products barcode String? /// Size-specific discount, null when none discountPrice Decimal? @db.Decimal(10, 2) /// Hiboutik size id, 0 for a product without sizes hiboutikSizeId Int /// Size-specific price, null to use the product price (copy of the product price for a product without sizes) price Decimal? @db.Decimal(10, 2) stock Int @default(0) /// Size name, or the product name for a product without sizes versionName String product Product @relation(fields: [productId], references: [id], onDelete: Cascade, onUpdate: Restrict) productId String orderLines OrderLine[] @@unique([productId, hiboutikSizeId]) @@index([barcode]) @@map("productVersions") } /// Customer mirrored from Hiboutik. model Customer { id String @id @default(uuid()) updatedAt DateTime @updatedAt dateOfBirth DateTime? /// Kept when removed in Hiboutik (an empty Hiboutik email does not erase it) email String? firstName String hiboutikId Int @unique /// Last update in Hiboutik hiboutikUpdatedAt DateTime? lastName String phone String? addresses CustomerAddress[] orders Order[] @@index([email]) @@map("customers") } /// Address of a customer, mirrored from Hiboutik. Its recipient (name, company, phone) can differ from the customer. model CustomerAddress { id String @id @default(uuid()) updatedAt DateTime @updatedAt address String city String company String? country String firstName String hiboutikId Int @unique isDefault Boolean @default(false) lastName String /// Free complement (building, floor, door code...) other String? phone String? state String? zipCode String customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) customerId String @@map("customer_addresses") } /// Where an order was placed. enum OrderSource { STORE // hiboutik WEB // site } /// Order placed in store (Hiboutik sale) or on the website. model Order { id String @id @default(uuid()) updatedAt DateTime @updatedAt createdAt DateTime @default(now()) /// Null for a website order not (yet) sent to Hiboutik hiboutikSaleId Int? @unique orderedAt DateTime source OrderSource status String total Decimal @db.Decimal(10, 2) /// Null for an anonymous sale or a deleted customer customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull) customerId String? lines OrderLine[] @@map("orders") } /// Line of an order. model OrderLine { id String @id @default(uuid()) updatedAt DateTime @updatedAt // Snapshot of the product at order time: the catalog can change or be deleted afterwards barcode String? hiboutikProductId Int hiboutikSizeId Int productName String quantity Int unitPrice Decimal @db.Decimal(10, 2) versionName String order Order @relation(fields: [orderId], references: [id], onDelete: Cascade) orderId String // Link to the current catalog, set to null when the version is deleted productVersion ProductVersion? @relation(fields: [productVersionId], references: [id], onDelete: SetNull) productVersionId String? @@map("order_lines") }