Files
fabric_trade_server/prisma/schema.prisma
T
mohmdsdgandCursor 345a4a4708 Add SMS OTP, harden auth, and fix order/checkout server bugs.
Ship 4-digit OTP with rate-limit attempts, Tehran-safe expiry/rass math, larger JSON body limit for check images, and safer order pricing/status guards. Include rebuilt dist for prebuilt deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-08 14:55:26 +03:30

422 lines
11 KiB
Plaintext

generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "debian-openssl-3.0.x", "linux-musl-openssl-3.0.x"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum SettlementType {
cash
check
}
enum CheckRegistrationMode {
full
brief
}
enum OrderStatus {
cart
awaiting_settlement
cash_in_progress
check_in_progress
submitted
awaiting_review
pricing
needs_correction
awaiting_settlement_fix
cash_invoice_issued
awaiting_cash_payment
cash_payment_submitted
awaiting_cash_confirmation
cash_confirmed
awaiting_check_review
check_needs_fix
check_rejected
checks_approved
final_approved
preparing
ready_to_ship
shipped
delivered
cancelled
rejected
expired
}
enum CheckStatus {
pending_review
approved
rejected
}
enum CashPaymentStatus {
pending_review
approved
rejected
expired
}
enum ShipmentStatus {
preparing
ready
shipped
delivered
}
enum CustomerType {
wholesale
retail
}
enum AdminRole {
admin
sales
finance
warehouse
}
enum NotificationTone {
info
warning
success
danger
}
model Company {
id String @id @default(cuid())
name String
slug String @unique
description String?
logoUrl String?
isActive Boolean @default(true)
displayOrder Int @default(0)
maxMeteragePerInvoice Int @default(5000)
cashInvoiceValidityHours Int @default(8)
cashInvoiceValidUntilHour Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bankAccounts BankAccount[]
catalogs Catalog[]
products Product[]
orders Order[]
customers Customer[]
}
model BankAccount {
id String @id @default(cuid())
companyId String
bankName String
accountHolder String
accountNumber String
cardNumber String
iban String
notes String?
isActive Boolean @default(true)
displayOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
cashReceipts CashPaymentReceipt[]
@@index([companyId])
}
model Catalog {
id String @id @default(cuid())
companyId String
name String
code String
description String?
displayOrder Int @default(0)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
products Product[]
@@unique([companyId, code])
@@index([companyId])
}
model Product {
id String @id @default(cuid())
companyId String
catalogId String
name String
code String
color String
description String?
minMeterage Float @default(30)
orderMultiplier Float @default(10)
basePrice Float?
stock Float?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
company Company @relation(fields: [companyId], references: [id], onDelete: Cascade)
catalog Catalog @relation(fields: [catalogId], references: [id], onDelete: Cascade)
cartItems CartItem[]
orderItems OrderItem[]
@@unique([companyId, code])
@@index([catalogId])
@@index([companyId])
}
model Customer {
id String @id @default(cuid())
firstName String
lastName String
phone String @unique
nationalId String?
customerType CustomerType @default(wholesale)
companyId String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
company Company? @relation(fields: [companyId], references: [id], onDelete: SetNull)
carts Cart[]
orders Order[]
@@index([companyId])
}
model AdminUser {
id String @id @default(cuid())
fullName String
phone String @unique
email String @unique
passwordHash String
role AdminRole @default(admin)
isActive Boolean @default(true)
lastLoginAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model OtpChallenge {
id String @id @default(cuid())
phone String
code String
firstName String?
lastName String?
isRegister Boolean @default(false)
attempts Int @default(0)
expiresAt DateTime
createdAt DateTime @default(now())
@@index([phone])
}
model Cart {
id String @id @default(cuid())
userId String
companyId String?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user Customer @relation(fields: [userId], references: [id], onDelete: Cascade)
items CartItem[]
@@index([userId])
}
model CartItem {
id String @id @default(cuid())
cartId String
productId String
catalogCode String
productName String
productCode String
color String
meterage Float
unitPrice Float?
notes String?
companyId String
companyName String
cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
product Product @relation(fields: [productId], references: [id], onDelete: Restrict)
@@unique([cartId, productId])
@@index([cartId])
}
model Order {
id String @id @default(cuid())
orderNumber String @unique
userId String
companyId String
companyName String
settlementType SettlementType
checkMode CheckRegistrationMode?
status OrderStatus @default(awaiting_review)
totalMeterage Float @default(0)
totalAmount Float?
shippingCost Float?
totalDiscount Float?
finalAmount Float?
notes String?
checkRassDays Int?
checkRassDate DateTime?
cashInvoiceExpiresAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user Customer @relation(fields: [userId], references: [id], onDelete: Restrict)
company Company @relation(fields: [companyId], references: [id], onDelete: Restrict)
items OrderItem[]
checks Check[]
cashReceipt CashPaymentReceipt?
shipment Shipment?
statusHistory OrderStatusHistory[]
@@index([userId])
@@index([companyId])
@@index([status])
@@index([createdAt])
}
model OrderItem {
id String @id @default(cuid())
orderId String
productId String?
catalogCode String
productName String
productCode String?
color String
requestedMeterage Float
confirmedMeterage Float?
unitPrice Float?
unitDiscount Float? @default(0)
lineTotal Float?
notes String?
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
product Product? @relation(fields: [productId], references: [id], onDelete: SetNull)
@@index([orderId])
}
model OrderStatusHistory {
id String @id @default(cuid())
orderId String
fromStatus OrderStatus?
toStatus OrderStatus
changedBy String
note String?
reason String?
changedAt DateTime @default(now())
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
@@index([orderId])
}
model Check {
id String @id @default(cuid())
orderId String
row Int
amount Float
dueDate DateTime
sayadId String?
checkNumber String?
ownerNationalId String?
ownerFirstName String?
ownerLastName String?
bankName String?
branchName String?
frontImage String?
backImage String?
notes String?
mode CheckRegistrationMode @default(full)
status CheckStatus @default(pending_review)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
@@index([orderId])
@@index([dueDate])
}
model CashPaymentReceipt {
id String @id @default(cuid())
orderId String @unique
amount Float
paidAmount Float?
transferDate DateTime?
transferTime String?
trackingNumber String?
destinationAccountId String?
receiptImage String?
notes String?
expiresAt DateTime?
status CashPaymentStatus @default(pending_review)
submittedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
destinationAccount BankAccount? @relation(fields: [destinationAccountId], references: [id], onDelete: SetNull)
}
model Shipment {
id String @id @default(cuid())
orderId String @unique
carrier String
trackingNumber String?
meterage Float
status ShipmentStatus @default(preparing)
shippedAt DateTime?
deliveredAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
}
model SystemSettings {
id String @id @default("default")
maxMeteragePerInvoice Int @default(5000)
cashInvoiceValidityHours Int @default(8)
defaultSettlementCheck Boolean @default(true)
defaultSettlementCash Boolean @default(true)
smsOrderRegistered Boolean @default(true)
smsPaymentReminder Boolean @default(true)
smsCheckReview Boolean @default(true)
smsShippingUpdate Boolean @default(true)
supportPhone String?
supportEmail String?
updatedAt DateTime @updatedAt
}
model AdminNotification {
id String @id @default(cuid())
title String
body String
tone NotificationTone? @default(info)
link String?
isRead Boolean @default(false)
sentAt DateTime @default(now())
}
model InternalMessage {
id String @id @default(cuid())
senderName String
subject String
preview String
isRead Boolean @default(false)
sentAt DateTime @default(now())
}