Files
shop-server/server/prisma/schema.prisma
T
Kirill f855568687 refactor: simplify order status model — remove DELIVERY_FEE_ADJUSTMENT and PAYMENT_VERIFICATION
- Add deliveryFeeLocked field to Order model
- Remove DELIVERY_FEE_ADJUSTMENT and PAYMENT_VERIFICATION statuses (11→8)
- 3 order paths: delivery+online (locked→unlocked→paid), pickup+online (unlocked→paid), pickup+on_pickup (direct to in_progress)
- Update checkout to use PENDING_PAYMENT + deliveryFeeLocked
- Update payment flow to stay in PENDING_PAYMENT until admin confirms
- Update admin UI to use deliveryFeeLocked instead of status check
- Update client payment UI with new deliveryFeeLocked logic
2026-05-15 21:55:14 +05:00

271 lines
7.6 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
/// Категория изделий (игрушки, сувениры и т.д.)
model Category {
id String @id @default(cuid())
name String
slug String @unique
sort Int @default(0)
products Product[]
}
model Product {
id String @id @default(cuid())
title String
slug String @unique
shortDescription String?
description String?
/// Количество на складе
quantity Int @default(0)
/// Материалы (список, например: ["хлопок","дерево"])
materials String @default("[]")
/// Цена в копейках (целое число, без дробной части)
priceCents Int
imageUrl String?
published Boolean @default(false)
category Category @relation(fields: [categoryId], references: [id], onDelete: Restrict)
categoryId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
images ProductImage[]
reviews Review[]
orderItems OrderItem[]
cartItems CartItem[]
}
model ProductImage {
id String @id @default(cuid())
url String
sort Int @default(0)
createdAt DateTime @default(now())
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
@@index([productId, sort])
}
/// Медиатека админки: зарегистрированные файлы /uploads/... (без обязательной привязки к товару).
model GalleryImage {
id String @id @default(cuid())
url String @unique
createdAt DateTime @default(now())
catalogSliderSlides CatalogSliderSlide[]
}
/// Слайды главной витрины (каталог): картинка из галереи + подпись.
model CatalogSliderSlide {
id String @id @default(cuid())
sortOrder Int
caption String @default("")
galleryImageId String
galleryImage GalleryImage @relation(fields: [galleryImageId], references: [id], onDelete: Cascade)
@@index([sortOrder])
}
model User {
id String @id @default(cuid())
email String @unique
name String?
phone String?
passwordHash String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
codes AuthCode[]
addresses ShippingAddress[]
cartItems CartItem[]
orders Order[]
reviews Review[]
orderMessageReadStates UserOrderMessageReadState[]
oauthAccounts OAuthAccount[]
}
/// Прочитанность чата по заказу (для сообщений от админа после lastReadAt)
model UserOrderMessageReadState {
id String @id @default(cuid())
lastReadAt DateTime @default("1970-01-01T00:00:00.000Z")
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
orderId String
@@unique([userId, orderId])
@@index([userId])
}
model CartItem {
id String @id @default(cuid())
qty Int
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
@@unique([userId, productId])
@@index([userId])
}
model Order {
id String @id @default(cuid())
/// Статус заказа (валидация переходов на уровне API)
status String @default("DRAFT")
deliveryFeeLocked Boolean @default(false)
/// 'delivery' | 'pickup'
deliveryType String @default("delivery")
/// RUSSIAN_POST | OZON_PVZ | YANDEX_PVZ | FIVE_POST при deliveryType=delivery
deliveryCarrier String?
/// 'online' | 'on_pickup' — способ расчёта для заказа
paymentMethod String @default("online")
itemsSubtotalCents Int @default(0)
deliveryFeeCents Int @default(0)
totalCents Int @default(0)
currency String @default("RUB")
addressSnapshotJson String?
comment String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
items OrderItem[]
messages OrderMessage[]
messageReadStates UserOrderMessageReadState[]
@@index([userId, createdAt])
@@index([status, updatedAt])
}
model OrderItem {
id String @id @default(cuid())
qty Int
titleSnapshot String
priceCentsSnapshot Int
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
orderId String
product Product @relation(fields: [productId], references: [id], onDelete: Restrict)
productId String
@@index([orderId])
}
model OrderMessage {
id String @id @default(cuid())
/// 'user' | 'admin'
authorType String
text String
/// URL вида /uploads/… (чек к оплате и т.п.)
attachmentUrl String?
createdAt DateTime @default(now())
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
orderId String
@@index([orderId, createdAt])
}
model Review {
id String @id @default(cuid())
rating Int
text String?
imageUrl String?
/// 'pending' | 'approved' | 'rejected'
status String @default("pending")
createdAt DateTime @default(now())
moderatedAt DateTime?
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
@@index([productId, status, createdAt])
@@index([status, createdAt])
@@unique([productId, userId])
}
model ShippingAddress {
id String @id @default(cuid())
label String?
recipientName String
recipientPhone String
addressLine String
comment String?
lat Float
lng Float
isDefault Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
@@index([userId, isDefault])
@@index([userId, updatedAt])
}
model OAuthAccount {
id String @id @default(cuid())
/// 'vk' | 'yandex'
provider String
providerUserId String
accessToken String?
refreshToken String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String
@@unique([provider, providerUserId])
@@index([userId])
}
model AuthCode {
id String @id @default(cuid())
email String
codeHash String
purpose String
expiresAt DateTime
usedAt DateTime?
createdAt DateTime @default(now())
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
@@index([email, purpose])
@@index([expiresAt])
}
model InfoPageBlock {
id String @id @default(cuid())
key String @unique
title String
body String
sort Int @default(0)
published Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([published, sort])
}