Files
sfera/prisma/schema.prisma

413 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"
url = env("DATABASE_URL")
}
// Модель пользователя
model User {
id String @id @default(cuid())
phone String @unique
avatar String? // URL аватара в S3
managerName String? // Имя управляющего
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Связь с организацией
organization Organization? @relation(fields: [organizationId], references: [id])
organizationId String?
// SMS коды для авторизации
smsCodes SmsCode[]
// Отправленные сообщения
sentMessages Message[] @relation("SentMessages")
@@map("users")
}
// Модель для SMS кодов
model SmsCode {
id String @id @default(cuid())
code String
phone String
expiresAt DateTime
isUsed Boolean @default(false)
attempts Int @default(0)
maxAttempts Int @default(3)
createdAt DateTime @default(now())
// Связь с пользователем
user User? @relation(fields: [userId], references: [id])
userId String?
@@map("sms_codes")
}
// Модель организации
model Organization {
id String @id @default(cuid())
inn String @unique
kpp String? // КПП
name String? // Краткое наименование
fullName String? // Полное наименование
ogrn String? // ОГРН организации
ogrnDate DateTime? // Дата выдачи ОГРН
type OrganizationType
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Адрес организации
address String? // Адрес одной строкой
addressFull String? // Полный адрес с индексом
// Статус организации
status String? // ACTIVE, LIQUIDATED и т.д.
actualityDate DateTime? // Дата последних изменений
registrationDate DateTime? // Дата регистрации
liquidationDate DateTime? // Дата ликвидации
// Руководитель
managementName String? // ФИО или наименование руководителя
managementPost String? // Должность руководителя
// ОПФ (Организационно-правовая форма)
opfCode String? // Код ОКОПФ
opfFull String? // Полное название ОПФ
opfShort String? // Краткое название ОПФ
// Коды статистики
okato String? // Код ОКАТО
oktmo String? // Код ОКТМО
okpo String? // Код ОКПО
okved String? // Основной код ОКВЭД
// Контакты
phones Json? // Массив телефонов
emails Json? // Массив email адресов
// Финансовые данные
employeeCount Int? // Численность сотрудников
revenue BigInt? // Выручка
taxSystem String? // Система налогообложения
// Полные данные из DaData (для полноты)
dadataData Json?
// Связи
users User[]
apiKeys ApiKey[]
// Связи контрагентов
sentRequests CounterpartyRequest[] @relation("SentRequests")
receivedRequests CounterpartyRequest[] @relation("ReceivedRequests")
organizationCounterparties Counterparty[] @relation("OrganizationCounterparties")
counterpartyOf Counterparty[] @relation("CounterpartyOf")
// Сообщения
sentMessages Message[] @relation("SentMessages")
receivedMessages Message[] @relation("ReceivedMessages")
// Услуги и расходники (только для фулфилмент центров)
services Service[]
supplies Supply[]
// Товары (только для оптовиков)
products Product[]
// Корзины
carts Cart[]
// Избранные товары
favorites Favorites[]
@@map("organizations")
}
// Модель для API ключей маркетплейсов
model ApiKey {
id String @id @default(cuid())
marketplace MarketplaceType
apiKey String
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Данные для валидации (например, информация о продавце)
validationData Json?
// Связь с организацией
organization Organization @relation(fields: [organizationId], references: [id])
organizationId String
@@unique([organizationId, marketplace])
@@map("api_keys")
}
// Тип организации
enum OrganizationType {
FULFILLMENT // Фулфилмент
SELLER // Селлер
LOGIST // Логистика
WHOLESALE // Оптовик
}
// Тип маркетплейса
enum MarketplaceType {
WILDBERRIES
OZON
}
// Модель для заявок на добавление в контрагенты
model CounterpartyRequest {
id String @id @default(cuid())
status CounterpartyRequestStatus @default(PENDING)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Кто отправил заявку
sender Organization @relation("SentRequests", fields: [senderId], references: [id])
senderId String
// Кому отправили заявку
receiver Organization @relation("ReceivedRequests", fields: [receiverId], references: [id])
receiverId String
// Комментарий к заявке
message String?
@@unique([senderId, receiverId])
@@map("counterparty_requests")
}
// Модель для связей контрагентов
model Counterparty {
id String @id @default(cuid())
createdAt DateTime @default(now())
// Основная организация
organization Organization @relation("OrganizationCounterparties", fields: [organizationId], references: [id])
organizationId String
// Контрагент
counterparty Organization @relation("CounterpartyOf", fields: [counterpartyId], references: [id])
counterpartyId String
@@unique([organizationId, counterpartyId])
@@map("counterparties")
}
// Статус заявки на добавление в контрагенты
enum CounterpartyRequestStatus {
PENDING // Ожидает ответа
ACCEPTED // Принята
REJECTED // Отклонена
CANCELLED // Отменена отправителем
}
// Модель сообщений в мессенджере
model Message {
id String @id @default(cuid())
content String? // Текст сообщения (nullable для медиа)
type MessageType @default(TEXT)
voiceUrl String? // URL голосового файла в S3
voiceDuration Int? // Длительность голосового сообщения в секундах
fileUrl String? // URL файла/изображения в S3
fileName String? // Оригинальное имя файла
fileSize Int? // Размер файла в байтах
fileType String? // MIME тип файла
isRead Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Отправитель
sender User @relation("SentMessages", fields: [senderId], references: [id])
senderId String
senderOrganization Organization @relation("SentMessages", fields: [senderOrganizationId], references: [id])
senderOrganizationId String
// Получатель
receiverOrganization Organization @relation("ReceivedMessages", fields: [receiverOrganizationId], references: [id])
receiverOrganizationId String
@@index([senderOrganizationId, receiverOrganizationId, createdAt])
@@index([receiverOrganizationId, isRead])
@@map("messages")
}
// Типы сообщений
enum MessageType {
TEXT
VOICE
IMAGE
FILE
}
// Модель услуг (для фулфилмент центров)
model Service {
id String @id @default(cuid())
name String
description String?
price Decimal @db.Decimal(10,2) // Цена за единицу
imageUrl String? // URL фотографии в S3
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Связь с организацией
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String
@@map("services")
}
// Модель расходников (для фулфилмент центров)
model Supply {
id String @id @default(cuid())
name String
description String?
price Decimal @db.Decimal(10,2) // Цена за единицу
quantity Int @default(0) // Количество в наличии
imageUrl String? // URL фотографии в S3
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Связь с организацией
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String
@@map("supplies")
}
// Модель категорий товаров
model Category {
id String @id @default(cuid())
name String @unique // Название категории
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Связь с товарами
products Product[]
@@map("categories")
}
// Модель товаров (для оптовиков)
model Product {
id String @id @default(cuid())
// Основные поля
name String // Название товара
article String // Артикул/номер записи
description String? // Описание
// Цена и количество
price Decimal @db.Decimal(12,2) // Цена за единицу
quantity Int @default(0) // Количество в наличии
// Основные характеристики
category Category? @relation(fields: [categoryId], references: [id])
categoryId String? // ID категории
brand String? // Бренд
// Дополнительные характеристики (необязательные)
color String? // Цвет
size String? // Размер
weight Decimal? @db.Decimal(8,3) // Вес в кг
dimensions String? // Габариты (ДxШxВ)
material String? // Материал
// Изображения (JSON массив URL-ов в S3)
images Json @default("[]") // Массив URL изображений
mainImage String? // URL главного изображения
// Статус товара
isActive Boolean @default(true) // Активен ли товар
// Временные метки
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Связь с организацией (только оптовики)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String
// Связь с элементами корзины
cartItems CartItem[]
// Избранные товары
favorites Favorites[]
// Уникальность артикула в рамках организации
@@unique([organizationId, article])
@@map("products")
}
// Модель корзины
model Cart {
id String @id @default(cuid())
// Связь с организацией (только покупатель может иметь корзину)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String @unique // У каждой организации может быть только одна корзина
// Элементы корзины
items CartItem[]
// Временные метки
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("carts")
}
// Модель элемента корзины
model CartItem {
id String @id @default(cuid())
// Связь с корзиной
cart Cart @relation(fields: [cartId], references: [id], onDelete: Cascade)
cartId String
// Связь с товаром
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
// Количество товара в корзине
quantity Int @default(1)
// Временные метки
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Уникальность: один товар может быть только один раз в корзине
@@unique([cartId, productId])
@@map("cart_items")
}
// Модель избранных товаров
model Favorites {
id String @id @default(cuid())
// Связь с организацией (пользователь может добавлять товары в избранное)
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
organizationId String
// Связь с товаром
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
productId String
// Временные метки
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Уникальность: один товар может быть только один раз в избранном у организации
@@unique([organizationId, productId])
@@map("favorites")
}