316 lines
14 KiB
Plaintext
316 lines
14 KiB
Plaintext
|
|
// 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])
|
|||
|
|
}
|