316 lines
13 KiB
Plaintext
Executable File
316 lines
13 KiB
Plaintext
Executable File
// Prisma schema for Estimate Assistant
|
||
|
||
generator client {
|
||
provider = "prisma-client-js"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// Справочники базовых цен (СБЦ)
|
||
model PriceBook {
|
||
id String @id @default(uuid())
|
||
code String @unique // SBC-GEODESY-2004, SBC-GEOLOGY-1999
|
||
name String // Полное название справочника
|
||
baseDate DateTime // Дата базовых цен (01.01.2001, 01.01.1991)
|
||
approvedBy String? // Кем утвержден
|
||
effectiveDate DateTime? // Дата введения в действие
|
||
isActive Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
tables PriceTable[]
|
||
items PriceItem[]
|
||
}
|
||
|
||
// Таблицы справочников
|
||
model PriceTable {
|
||
id String @id @default(uuid())
|
||
priceBookId String
|
||
tableNumber Int // Номер таблицы (8, 9, 13, и т.д.)
|
||
name String // Название таблицы
|
||
unit String // Единица измерения (1 пункт, 1 га, 1 км и т.д.)
|
||
notes Json? // Примечания к таблице
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
priceBook PriceBook @relation(fields: [priceBookId], references: [id], onDelete: Cascade)
|
||
items PriceItem[]
|
||
|
||
@@unique([priceBookId, tableNumber])
|
||
}
|
||
|
||
// Позиции справочников (расценки)
|
||
model PriceItem {
|
||
id String @id @default(uuid())
|
||
priceBookId String
|
||
priceTableId String
|
||
paragraph String // Номер параграфа (8-1, 9-4-1 и т.д.)
|
||
workType String // Тип работы / наименование
|
||
description String? // Дополнительное описание
|
||
|
||
// Цены (полевые/камеральные для разных категорий)
|
||
priceField1 Decimal? @db.Decimal(12, 2) // Полевые работы, категория 1
|
||
priceOffice1 Decimal? @db.Decimal(12, 2) // Камеральные работы, категория 1
|
||
priceField2 Decimal? @db.Decimal(12, 2) // Полевые работы, категория 2
|
||
priceOffice2 Decimal? @db.Decimal(12, 2) // Камеральные работы, категория 2
|
||
priceField3 Decimal? @db.Decimal(12, 2) // Полевые работы, категория 3
|
||
priceOffice3 Decimal? @db.Decimal(12, 2) // Камеральные работы, категория 3
|
||
priceSimple Decimal? @db.Decimal(12, 2) // Простая цена (без категорий)
|
||
|
||
// Дополнительные параметры
|
||
attributes Json? // Доп. атрибуты (масштаб, глубина, диаметр и т.д.)
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
priceBook PriceBook @relation(fields: [priceBookId], references: [id], onDelete: Cascade)
|
||
priceTable PriceTable @relation(fields: [priceTableId], references: [id], onDelete: Cascade)
|
||
estimateItems EstimateItem[]
|
||
|
||
@@index([paragraph])
|
||
@@index([workType])
|
||
}
|
||
|
||
// Коэффициенты
|
||
model Coefficient {
|
||
id String @id @default(uuid())
|
||
type String // regional, transport_internal, transport_external, seasonal, special
|
||
code String // Уникальный код коэффициента
|
||
name String // Название
|
||
value Decimal @db.Decimal(6, 4) // Значение коэффициента
|
||
description String? // Описание
|
||
conditions Json? // Условия применения
|
||
isActive Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@unique([type, code])
|
||
}
|
||
|
||
// Индексы инфляции (перевод в текущие цены)
|
||
model InflationIndex {
|
||
id String @id @default(uuid())
|
||
baseDate DateTime // Базовая дата цен
|
||
effectiveFrom DateTime // Дата начала действия индекса
|
||
effectiveTo DateTime? // Дата окончания (null = текущий)
|
||
indexValue Decimal @db.Decimal(10, 4) // Значение индекса
|
||
documentRef String? // Ссылка на документ (Письмо Минстроя и т.д.)
|
||
isActive Boolean @default(true)
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
}
|
||
|
||
// Пользователи
|
||
model User {
|
||
id String @id @default(uuid())
|
||
email String @unique
|
||
passwordHash String
|
||
name String?
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
estimates Estimate[]
|
||
chatSessions ChatSession[]
|
||
ownedShares EstimateShare[] @relation("ShareOwner")
|
||
receivedShares EstimateShare[] @relation("ShareReceiver")
|
||
shareNotes EstimateShareNote[]
|
||
}
|
||
|
||
// Направления изысканий
|
||
model SurveyDirection {
|
||
id String @id @default(uuid())
|
||
code String @unique // geodesy, geology, ecology, hydrology
|
||
name String // Инженерно-геодезические изыскания
|
||
shortName String // Геодезия
|
||
isActive Boolean @default(true)
|
||
|
||
estimates Estimate[]
|
||
}
|
||
|
||
// Сметы
|
||
model Estimate {
|
||
id String @id @default(uuid())
|
||
number String // Номер сметы
|
||
directionId String
|
||
ownerId String // Владелец сметы
|
||
objectName String // Название объекта
|
||
customer String // Заказчик
|
||
executor String // Исполнитель
|
||
|
||
// Итоговые значения
|
||
totalFieldWorks Decimal? @db.Decimal(14, 2) // Итого полевые работы
|
||
totalOfficeWorks Decimal? @db.Decimal(14, 2) // Итого камеральные работы
|
||
totalLaboratory Decimal? @db.Decimal(14, 2) // Итого лабораторные
|
||
subtotal Decimal? @db.Decimal(14, 2) // Итого по изысканиям
|
||
|
||
// Коэффициенты и пересчет
|
||
regionalCoef Decimal? @db.Decimal(6, 4) // Районный коэффициент
|
||
regionalCoefDocRef String? // Описание (С районным коэффициентом и т.д.)
|
||
inflationIndex Decimal? @db.Decimal(10, 4) // Индекс перевода в текущие цены
|
||
inflationDocRef String? // Ссылка на документ (Письмо Минстроя и т.д.)
|
||
companyCoef Decimal? @db.Decimal(6, 4) // Коэффициент компании (Газпром и т.д.)
|
||
companyCoefDocRef String? // Описание (Коэффициент ОАО «Газпром» №544 и т.д.)
|
||
executorCoef Decimal? @db.Decimal(6, 4) // Коэффициент исполнителя
|
||
executorCoefDocRef String? // Описание (Коэффициент ООО «ГеоВектор» и т.д.)
|
||
|
||
// Итоги
|
||
withVat Boolean @default(true) // Смета с НДС (true) или без НДС (false)
|
||
totalWithoutVat Decimal? @db.Decimal(14, 2) // Итого без НДС
|
||
vatRate Decimal? @db.Decimal(4, 2) // Ставка НДС (18, 20, 7)
|
||
vatAmount Decimal? @db.Decimal(14, 2) // Сумма НДС
|
||
totalWithVat Decimal? @db.Decimal(14, 2) // Всего с НДС
|
||
|
||
status String @default("draft") // draft, completed, approved
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
|
||
direction SurveyDirection @relation(fields: [directionId], references: [id])
|
||
items EstimateItem[]
|
||
totals EstimateTotal[]
|
||
shares EstimateShare[]
|
||
versions EstimateVersion[]
|
||
}
|
||
|
||
// История версий сметы (снимок при сохранении/пересчёте)
|
||
model EstimateVersion {
|
||
id String @id @default(uuid())
|
||
estimateId String
|
||
versionNumber Int // Порядковый номер версии по смете
|
||
snapshot Json // Полный снимок: estimate + items + totals
|
||
createdAt DateTime @default(now())
|
||
|
||
estimate Estimate @relation(fields: [estimateId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([estimateId])
|
||
@@index([estimateId, createdAt])
|
||
}
|
||
|
||
// Шаринг сметы с другим пользователем
|
||
model EstimateShare {
|
||
id String @id @default(uuid())
|
||
estimateId String
|
||
ownerId String // Кто поделился
|
||
sharedWithId String // С кем поделились
|
||
createdAt DateTime @default(now())
|
||
|
||
estimate Estimate @relation(fields: [estimateId], references: [id], onDelete: Cascade)
|
||
sharedWith User @relation("ShareReceiver", fields: [sharedWithId], references: [id], onDelete: Cascade)
|
||
owner User @relation("ShareOwner", fields: [ownerId], references: [id], onDelete: Cascade)
|
||
notes EstimateShareNote[]
|
||
|
||
@@unique([estimateId, sharedWithId])
|
||
@@index([sharedWithId])
|
||
}
|
||
|
||
// Заметки к шарингу сметы (кто что написал)
|
||
model EstimateShareNote {
|
||
id String @id @default(uuid())
|
||
shareId String
|
||
authorId String
|
||
content String @db.Text
|
||
createdAt DateTime @default(now())
|
||
|
||
share EstimateShare @relation(fields: [shareId], references: [id], onDelete: Cascade)
|
||
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([shareId])
|
||
}
|
||
|
||
// Позиции сметы
|
||
model EstimateItem {
|
||
id String @id @default(uuid())
|
||
estimateId String
|
||
orderNumber Int // Порядковый номер
|
||
sectionType String // field, office, laboratory, transport, other
|
||
priceItemId String? // Ссылка на позицию справочника
|
||
|
||
workName String // Наименование работы
|
||
justification String? // Обоснование (ссылка на СБЦ)
|
||
basePrice Decimal @db.Decimal(12, 2) // Базовая цена
|
||
quantity Decimal @db.Decimal(12, 4) // Объем
|
||
unit String? // Единица измерения
|
||
|
||
// Коэффициенты
|
||
coef1 Decimal? @db.Decimal(6, 4) // Коэффициент 1
|
||
coef1Desc String? // Описание коэффициента 1
|
||
coef2 Decimal? @db.Decimal(6, 4) // Коэффициент 2
|
||
coef2Desc String? // Описание коэффициента 2
|
||
coef3 Decimal? @db.Decimal(6, 4) // Коэффициент 3
|
||
coef3Desc String? // Описание коэффициента 3
|
||
|
||
totalPrice Decimal @db.Decimal(14, 2) // Итоговая стоимость
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
estimate Estimate @relation(fields: [estimateId], references: [id], onDelete: Cascade)
|
||
priceItem PriceItem? @relation(fields: [priceItemId], references: [id])
|
||
|
||
@@index([estimateId, orderNumber])
|
||
}
|
||
|
||
// Итоговая часть сметы (нижняя часть)
|
||
model EstimateTotal {
|
||
id String @id @default(uuid())
|
||
estimateId String
|
||
orderNumber Int // Порядок строки
|
||
label String // Название строки (Перевод в текущие цены, НДС и т.д.)
|
||
description String? // Дополнительное описание
|
||
baseValue Decimal? @db.Decimal(14, 2) // Базовое значение
|
||
coefficient Decimal? @db.Decimal(10, 4) // Коэффициент/процент
|
||
resultValue Decimal @db.Decimal(14, 2) // Результат
|
||
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
estimate Estimate @relation(fields: [estimateId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([estimateId, orderNumber])
|
||
}
|
||
|
||
// Настройки приложения
|
||
model Setting {
|
||
id String @id @default(uuid())
|
||
key String @unique
|
||
value String
|
||
type String @default("string") // string, number, boolean, json
|
||
category String // general, company, ai, display
|
||
label String? // Человекочитаемое название
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
}
|
||
|
||
// Сессии чата (у каждого пользователя свои контексты ИИ)
|
||
model ChatSession {
|
||
id String @id @default(uuid())
|
||
userId String // Владелец сессии
|
||
estimateId String? // Связанная смета (опционально)
|
||
status String @default("active") // active, completed
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
messages ChatMessage[]
|
||
|
||
@@index([userId])
|
||
@@index([userId, estimateId])
|
||
}
|
||
|
||
// Сообщения чата
|
||
model ChatMessage {
|
||
id String @id @default(uuid())
|
||
sessionId String
|
||
role String // user, assistant, system
|
||
content String
|
||
metadata Json? // Доп. данные (извлеченные сущности и т.д.)
|
||
createdAt DateTime @default(now())
|
||
|
||
session ChatSession @relation(fields: [sessionId], references: [id], onDelete: Cascade)
|
||
|
||
@@index([sessionId, createdAt])
|
||
}
|