// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" } model Scent { id Int @id @default(autoincrement()) name String @unique products Product[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Category { id Int @id @default(autoincrement()) name String @unique imageUrl String? products Product[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Product { id Int @id @default(autoincrement()) name String description String? details String? price Float? @default(0) categoryId Int category Category @relation(fields: [categoryId], references: [id]) scentId Int scent Scent @relation(fields: [scentId], references: [id]) variants ProductVariant[] images ProductImage[] reviews Review[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([scentId, categoryId]) } model ProductImage { id Int @id @default(autoincrement()) url String order Int @default(0) productId Int product Product @relation(fields: [productId], references: [id], onDelete: Cascade) } model ProductVariant { id Int @id @default(autoincrement()) size String price Float? @default(0) productId Int product Product @relation(fields: [productId], references: [id]) bomItems BomItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([productId, size]) } model User { id Int @id @default(autoincrement()) username String @unique password String role String @default("ADMIN") createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Customer { id Int @id @default(autoincrement()) lineUserId String @unique displayName String? pictureUrl String? email String? phone String? points Int @default(0) orders Order[] reviews Review[] addresses CustomerAddress[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model CustomerAddress { id Int @id @default(autoincrement()) customerId Int customer Customer @relation(fields: [customerId], references: [id], onDelete: Cascade) recipientName String phone String addressLine String // บ้านเลขที่ หมู่บ้าน ถนน ซอย subdistrict String // แขวง/ตำบล district String // เขต/อำเภอ province String // จังหวัด zipcode String // รหัสไปรษณีย์ isDefault Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Hero { id Int @id @default(autoincrement()) tagline String title String description String imageUrl String buttonText String @default("Explore Collection") buttonLink String @default("/shop") isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Coupon { id Int @id @default(autoincrement()) code String @unique type String // "PERCENTAGE", "FIXED_AMOUNT", "FREE_SHIPPING" value Float minPurchase Float @default(0) maxDiscount Float? usageLimit Int? usedCount Int @default(0) expiresAt DateTime? isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Promotion { id Int @id @default(autoincrement()) name String level Int type String value Float minPurchase Float @default(0) isActive Boolean @default(true) startDate DateTime? endDate DateTime? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model StoreSettings { id Int @id @default(1) shippingFee Float @default(35) bankName String @default("KASIKORNBANK (KBANK)") bankAccountName String @default("HomAroma Co., Ltd.") bankAccountNumber String @default("012-3-45678-9") pointsEarnRate Float @default(1.0) updatedAt DateTime @updatedAt } model Order { id Int @id @default(autoincrement()) customerName String customerEmail String customerPhone String shippingAddress String subtotal Float @default(0) promoLevel1Name String? promoLevel1Disc Float @default(0) promoLevel2Name String? promoLevel2Disc Float @default(0) couponCode String? discountAmount Float @default(0) pointsUsed Int @default(0) pointsDiscount Float @default(0) pointsEarned Int @default(0) shippingFee Float @default(35) totalAmount Float status String @default("PENDING_PAYMENT") paymentSlipUrl String? trackingNo String? customerId Int? customer Customer? @relation(fields: [customerId], references: [id]) items OrderItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model OrderItem { id Int @id @default(autoincrement()) orderId Int order Order @relation(fields: [orderId], references: [id], onDelete: Cascade) productId Int variantId Int? quantity Int priceAtPurchase Float productName String variantSize String? productImage String? } model Article { id Int @id @default(autoincrement()) slug String @unique title String coverImage String? content String isPublished Boolean @default(false) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model TiktokIncome { id String @id // Order/adjustment ID type String orderCreatedTime String? orderSettledTime String? currency String totalSettlementAmount Float totalRevenue Float totalFees Float rawData Json // Stores all other 50+ columns createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model TiktokProduct { id String @id // Product ID productName String status String gmv Float itemsSold Int orders Int rawData Json // Stores remaining tab/live/video metrics createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model TiktokProductSku { id String @id // SKU ID productId String skuName String status String gmv Float skuOrders Int itemsSold Int rawData Json createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model RawMaterial { id Int @id @default(autoincrement()) name String @unique unit String // e.g., 'kg', 'liter', 'piece' pricePerUnit Float bomItems BomItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model BomItem { id Int @id @default(autoincrement()) productVariantId Int productVariant ProductVariant @relation(fields: [productVariantId], references: [id], onDelete: Cascade) rawMaterialId Int rawMaterial RawMaterial @relation(fields: [rawMaterialId], references: [id], onDelete: Cascade) quantity Float createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([productVariantId, rawMaterialId]) } model ShopeeOrder { orderId String @id shop String @default("hom-aroma") status String buyerUsername String? orderCreatedAt String? paymentTime String? paymentMethod String? trackingNo String? totalAmount Float @default(0) buyerPaidAmount Float @default(0) shippingFee Float @default(0) commission Float @default(0) completedAt String? items ShopeeOrderItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model ShopeeOrderItem { id Int @id @default(autoincrement()) orderId String order ShopeeOrder @relation(fields: [orderId], references: [orderId], onDelete: Cascade) parentSku String? productName String skuRef String? variantName String? originalPrice Float @default(0) dealPrice Float @default(0) quantity Int @default(1) totalPayment Float @default(0) rawData Json } // ── TikTok Orders ────────────────────────────────────────────────────────────── model TiktokOrder { id Int @id @default(autoincrement()) orderId String @unique shop String @default("hom-aroma") status String // Order Status (Thai) subStatus String? // Order Substatus orderType String? // Normal / Pre-order cancelBy String? cancelReason String? fulfillmentType String? warehouseName String? trackingId String? deliveryOption String? shippingProvider String? buyerUsername String? paymentMethod String? // Financials (order-level) orderAmount Float @default(0) // Total paid by buyer refundAmount Float @default(0) shippingFee Float @default(0) // Shipping Fee After Discount originalShipping Float @default(0) taxes Float @default(0) // Geography province String? district String? country String? // Timestamps createdTime String? paidTime String? rtsTime String? shippedTime String? deliveredTime String? cancelledTime String? items TiktokOrderItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([shop]) @@index([status]) @@index([createdTime]) } model TiktokOrderItem { id Int @id @default(autoincrement()) orderId String order TiktokOrder @relation(fields: [orderId], references: [orderId], onDelete: Cascade) skuId String? sellerSku String? productName String variation String? quantity Int @default(1) skuQtyReturn Int @default(0) unitOriginalPrice Float @default(0) subtotalBeforeDiscount Float @default(0) platformDiscount Float @default(0) sellerDiscount Float @default(0) subtotalAfterDiscount Float @default(0) // Revenue ระดับ SKU productCategory String? weight Float @default(0) } // ── Lazada Orders ────────────────────────────────────────────────────────────── model LazadaOrder { id Int @id @default(autoincrement()) orderNumber String @unique shop String @default("hom-aroma") createTime String? updateTime String? deliveredDate String? customerName String? shippingCity String? shippingPostCode String? shippingRegion String? payMethod String? status String? // Based on items or first item trackingCode String? shippingProvider String? // Aggregate from items orderAmount Float @default(0) // sum(paidPrice) shippingFee Float @default(0) // sum(shippingFee) items LazadaOrderItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([shop]) @@index([status]) @@index([createTime]) } model LazadaOrderItem { id Int @id @default(autoincrement()) orderNumber String order LazadaOrder @relation(fields: [orderNumber], references: [orderNumber], onDelete: Cascade) orderItemId String @unique sellerSku String? lazadaSku String? itemName String variation String? unitPrice Float @default(0) paidPrice Float @default(0) sellerDiscountTotal Float @default(0) platformDiscountTotal Float @default(0) shippingFee Float @default(0) status String? } // ── Reviews ──────────────────────────────────────────────────────────────── model Review { id Int @id @default(autoincrement()) rating Int @default(5) comment String? productId Int product Product @relation(fields: [productId], references: [id], onDelete: Cascade) customerId Int? customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull) customerName String? isPublished Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([productId]) @@index([customerId]) } model Page { id Int @id @default(autoincrement()) slug String @unique // e.g., "home", "about-us" title String sections PageSection[] isPublished Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PageSection { id Int @id @default(autoincrement()) pageId Int page Page @relation(fields: [pageId], references: [id], onDelete: Cascade) type String // e.g., "HERO", "CATEGORIES", "PRODUCTS", "BANNER", "TEXT" order Int // Display order payload Json // Dynamic JSON payload isActive Boolean @default(true) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model NewsletterSubscription { id Int @id @default(autoincrement()) email String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt }