2260 lines
92 KiB
Plaintext
2260 lines
92 KiB
Plaintext
generator client {
|
||
provider = "prisma-client-js"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "postgresql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// ENUMS
|
||
// ══════════════════════════════════════════════════════════════════
|
||
|
||
// CDC §9.1 — 15 rôles métier
|
||
enum Role {
|
||
ADMIN // Louis-André — tous accès
|
||
DIRECTION_FIN // Максим — validation financière
|
||
DIRECTION_OPS // Никита — validation opérationnelle
|
||
COMMERCIAL // Васильева, Мартьянов
|
||
INGENIEUR_CHEF // Ежов Т.О. — сметы, КД
|
||
INGENIEUR_PTO // Данг Ле Хай — documentation technique
|
||
ADM_PRODUCTION // Лебедева — plan production
|
||
ACHETEUR // Иванов — achats
|
||
RESP_ENTREPOT // Наталья — réception, stocks
|
||
COMPTABLE // Банкина Т.А., Банкина Анна
|
||
MAITRE_PROD // Алидин — fabrication
|
||
MAITRE_ZAGOT // Блинов — fabrication
|
||
TECHNOLOGUE // Илья — laser
|
||
MAGASINIER // Ежов Олег — склад заготовок
|
||
USER // lecture seule
|
||
}
|
||
|
||
// CDC §5.1 — Cycle de vie commande (10 statuts + CANCELLED)
|
||
enum OrderStatus {
|
||
DRAFT // Brouillon
|
||
AWAITING_ESTIMATE // En attente смета
|
||
AWAITING_VALIDATION // En attente validation financière
|
||
VALIDATED // Validé (finances OK)
|
||
LAUNCHED // Lancé en production
|
||
IN_PRODUCTION // En production
|
||
QUALITY_CONTROL // En contrôle qualité
|
||
SHIPPED // Expédié
|
||
DELIVERED // Livré
|
||
ARCHIVED // Archivé
|
||
CANCELLED // Annulé
|
||
}
|
||
|
||
// CDC §5.2 — Type de commande
|
||
enum OrderType {
|
||
STANDARD
|
||
CUSTOM
|
||
}
|
||
|
||
// CDC §5.2 — Unité d'exécution (исполнитель)
|
||
enum ExecutionUnit {
|
||
MAIN_PRODUCTION // Основное производство
|
||
PREPARATION // Заготовительный участок
|
||
SEVER // Участок Север
|
||
TLT // ТЛТ
|
||
EXTERNAL // Внешний подрядчик
|
||
}
|
||
|
||
// CDC §5.3 — Motif révision
|
||
enum RevisionReason {
|
||
PROTOTYPE_REJECTED
|
||
CLIENT_REQUEST
|
||
TECHNICAL_ERROR
|
||
OTHER
|
||
}
|
||
|
||
// CDC §5.3 — Statut révision commande
|
||
enum RevisionStatus {
|
||
DRAFT
|
||
PENDING_FINANCIAL
|
||
PENDING_PRODUCTION
|
||
APPROVED
|
||
REJECTED
|
||
}
|
||
|
||
// CDC §4.1 — Catégorie demande de paiement
|
||
enum PaymentCategory {
|
||
DIRECT_PROJECT
|
||
PRODUCTION_SUPPLY
|
||
ADMINISTRATIVE
|
||
EXCEPTIONAL
|
||
}
|
||
|
||
// CDC §4.1 — Type de récurrence
|
||
enum RecurrenceType {
|
||
MONTHLY
|
||
ANNUAL
|
||
}
|
||
|
||
// CDC §4.1 — Statut approbation
|
||
enum ApprovalStatus {
|
||
PENDING
|
||
APPROVED
|
||
REJECTED
|
||
INFO_REQUESTED
|
||
ESCALATED
|
||
}
|
||
|
||
// CDC §4.1 — Niveau d'alerte budget
|
||
enum AlertLevel {
|
||
NONE
|
||
YELLOW
|
||
RED
|
||
}
|
||
|
||
// CDC §4.3 — Type de document
|
||
enum DocumentType {
|
||
CONTRACT
|
||
UPD
|
||
INVOICE
|
||
SMETA
|
||
SPECIFICATION
|
||
PASSPORT_ZAKAZA
|
||
DELIVERY_NOTE
|
||
OTHER
|
||
APPENDIX
|
||
}
|
||
|
||
// CDC §4.3 — Statut suivi document (contrat/УПД)
|
||
enum DocumentTrackingStatus {
|
||
SENT
|
||
REMINDER_1
|
||
REMINDER_2
|
||
REMINDER_3
|
||
ESCALATED
|
||
RECEIVED
|
||
CLOSED
|
||
}
|
||
|
||
// CDC §4.3 — Canal d'envoi document
|
||
enum DocumentChannel {
|
||
EDO
|
||
EMAIL
|
||
PAPER
|
||
}
|
||
|
||
// CDC §2 — Statut fournisseur
|
||
enum SupplierStatus {
|
||
ACTIVE
|
||
INACTIVE
|
||
DISPUTE
|
||
}
|
||
|
||
enum SupplierContractStatus {
|
||
DRAFT
|
||
SIGNED
|
||
EXPIRED
|
||
}
|
||
|
||
enum SupplierPaymentTrigger {
|
||
PREPAYMENT
|
||
ON_DELIVERY
|
||
POST_DELIVERY
|
||
CUSTOM_DATE
|
||
}
|
||
|
||
// CDC §4.4 — Type de contact fournisseur
|
||
enum SupplierContactType {
|
||
COMMERCIAL
|
||
ACCOUNTANT
|
||
}
|
||
|
||
// CDC §6.1 — Catégorie matériau
|
||
enum MaterialCategory {
|
||
LASER_FLAT
|
||
LASER_TUBE
|
||
TUBE_BENDING
|
||
ROD_BENDING
|
||
CNC_MILLING
|
||
GALVANIC
|
||
MACHINING_EXT
|
||
MESH_WELDING
|
||
SPRING_COILING
|
||
METAL
|
||
FASTENERS
|
||
COMPONENTS
|
||
PAINT
|
||
}
|
||
|
||
enum ReceptionStatus {
|
||
DRAFT
|
||
VERIFIED
|
||
ACCOUNTED
|
||
DISCREPANCY
|
||
CANCELLED
|
||
}
|
||
|
||
// SPEC 13A-1 — Type de ligne смета
|
||
enum SmetaLineType {
|
||
SERVICE
|
||
MATERIAL
|
||
LABOR
|
||
}
|
||
|
||
// CDC §6.1 — Statut besoin d'achat
|
||
enum PurchaseRequirementStatus {
|
||
DRAFT
|
||
CONFIRMED
|
||
IN_TENDER
|
||
ORDERED
|
||
RECEIVED
|
||
CANCELLED
|
||
}
|
||
|
||
// CDC §6.1 — Priorité besoin d'achat
|
||
enum PurchasePriority {
|
||
LOW
|
||
NORMAL
|
||
HIGH
|
||
URGENT
|
||
}
|
||
|
||
// CDC §6.1 — Statut tender
|
||
enum TenderStatus {
|
||
DRAFT
|
||
SENT
|
||
COMPARING
|
||
AWARDED
|
||
CLOSED
|
||
}
|
||
|
||
// CDC §6.1 — Statut commande fournisseur
|
||
enum PurchaseOrderStatus {
|
||
DRAFT
|
||
CONFIRMED
|
||
SENT
|
||
SHIPPED
|
||
RECEIVED
|
||
PARTIAL
|
||
CANCELLED
|
||
}
|
||
|
||
// CDC §7.2 — Statut entrée trésorerie
|
||
enum CashflowStatus {
|
||
PLANNED
|
||
CONFIRMED
|
||
PAID
|
||
CANCELLED
|
||
}
|
||
|
||
// CDC §4.2 — Statut validation смета
|
||
// CDC §7.2 — Type trésorerie
|
||
enum CashflowType {
|
||
INCOME
|
||
EXPENSE
|
||
}
|
||
|
||
// CDC §7.2 — Source entrée trésorerie
|
||
enum CashflowSource {
|
||
ERP
|
||
C1_IMPORT
|
||
MANUAL
|
||
}
|
||
|
||
// CDC §4.2 — Statut validation смета (workflow 2 validateurs)
|
||
enum EstimateStatus {
|
||
DRAFT
|
||
SUBMITTED
|
||
FINANCIAL_REVIEW
|
||
TECHNICAL_REVIEW
|
||
REVISION_REQUESTED
|
||
APPROVED
|
||
LOCKED
|
||
SUPERSEDED
|
||
}
|
||
|
||
// ACHATS-A — Statut lot d'achat
|
||
enum PurchaseLotStatus {
|
||
PLANNED
|
||
AWAITING_VALIDATION
|
||
VALIDATED
|
||
ORDERING
|
||
ORDERED
|
||
DELIVERED
|
||
CANCELLED
|
||
}
|
||
|
||
// CDC §5.2 révisé — Type de photo commande
|
||
enum PhotoType {
|
||
EXPEDITION
|
||
PRODUCT_FINISHED
|
||
PROTOTYPE
|
||
QUALITY_CHECK
|
||
OTHER
|
||
}
|
||
|
||
// CDC §5 — Priorité notification
|
||
enum NotificationPriority {
|
||
LOW
|
||
NORMAL
|
||
HIGH
|
||
URGENT
|
||
}
|
||
|
||
// Phase 1.5 — Direction document (client ou fournisseur)
|
||
enum DocumentDirection {
|
||
SUPPLIER
|
||
CLIENT
|
||
}
|
||
|
||
// CDC §7.2 révisé — Source relevé bancaire
|
||
enum BankStatementSource {
|
||
IMPORT_1C
|
||
MANUAL
|
||
}
|
||
|
||
// CDC §7.2 révisé — Statut vérification relevé
|
||
enum VerificationStatus {
|
||
PENDING
|
||
VERIFIED
|
||
ERROR
|
||
}
|
||
|
||
// CDC §6.1 révisé — Mode paiement ТЛТ
|
||
enum TltPaymentMode {
|
||
IMMEDIATE
|
||
DEFERRED
|
||
}
|
||
|
||
// SPEC 24F — Types de surcoûts revision smeta
|
||
enum AdditionalCostType {
|
||
WASTED_MATERIAL
|
||
CANCELLATION_FEE
|
||
URGENT_REORDER
|
||
PRICE_INCREASE
|
||
OTHER
|
||
}
|
||
|
||
// SPEC 24F — Statut validation surcoût
|
||
enum AdditionalCostStatus {
|
||
PENDING
|
||
AC_APPROVED
|
||
AC_REJECTED
|
||
}
|
||
|
||
// SPEC 24F — Statut approbation revision smeta
|
||
enum RevisionApprovalStatus {
|
||
REV_PENDING
|
||
PARTIALLY_APPROVED
|
||
REV_APPROVED
|
||
REV_REJECTED
|
||
}
|
||
|
||
// SPEC 24F — Type de diff entre lignes smeta
|
||
enum SmetaDiffType {
|
||
ADDED
|
||
REMOVED
|
||
QTY_CHANGED
|
||
PRICE_CHANGED
|
||
CATEGORY_CHANGED
|
||
UNIT_CHANGED
|
||
}
|
||
|
||
enum PaymentType {
|
||
PREPAYMENT_FULL
|
||
INSTALLMENT
|
||
POST_DELIVERY
|
||
}
|
||
|
||
enum InvoiceStatus {
|
||
PENDING_VALIDATION
|
||
APPROVED_AWAITING_PAYMENT
|
||
PARTIALLY_PAID
|
||
PAID
|
||
}
|
||
|
||
enum PaymentTrigger {
|
||
ORDER_DATE
|
||
INVOICE_DATE
|
||
SHIPMENT_DATE
|
||
PRODUCTION_READY
|
||
CUSTOM_DATE
|
||
}
|
||
|
||
enum ForecastStatus {
|
||
EXTRAPOLATED
|
||
CONFIRMED
|
||
MODIFIED
|
||
REALIZED
|
||
}
|
||
|
||
enum ForecastSourceType {
|
||
AUTO_GENERATED
|
||
MANUAL_ADD
|
||
RESIDUAL
|
||
BACKFILLED
|
||
}
|
||
|
||
enum ForecastTriggerPhase {
|
||
ORDER_CREATED
|
||
SMETA_LOCKED
|
||
PRODUCTION_LAUNCHED
|
||
SHIPMENT_SIGNED
|
||
MANUAL
|
||
}
|
||
|
||
enum ClientInstallmentStatus {
|
||
PENDING
|
||
PARTIALLY_PAID
|
||
PAID
|
||
CANCELLED
|
||
}
|
||
|
||
enum ClientInvoiceStatus {
|
||
DRAFT
|
||
ISSUED
|
||
CANCELLED
|
||
}
|
||
|
||
enum DeliveryLotStatus {
|
||
DRAFT
|
||
SHIPPED
|
||
SIGNED_BY_CLIENT
|
||
DELIVERED
|
||
CANCELLED
|
||
}
|
||
|
||
enum ContractStatus {
|
||
DRAFT
|
||
ACTIVE
|
||
EXPIRED
|
||
CANCELLED
|
||
}
|
||
|
||
enum PlannedDeliveryLotStatus {
|
||
PLANNED
|
||
PARTIALLY_SHIPPED
|
||
FULLY_SHIPPED
|
||
CANCELLED
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// MODELS
|
||
// ══════════════════════════════════════════════════════════════════
|
||
|
||
// CDC §9.1 — Utilisateurs avec rôles RBAC
|
||
model User {
|
||
id String @id @default(uuid())
|
||
email String @unique
|
||
password String
|
||
name String
|
||
nameRu String? @map("name_ru")
|
||
role Role @default(USER)
|
||
active Boolean @default(true)
|
||
phone String?
|
||
telegramId String? @map("telegram_id")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
ordersManaged Order[] @relation("OrderManager")
|
||
orderRevisions OrderRevision[] @relation("RevisionInitiator")
|
||
paymentRequests PaymentRequest[] @relation("PaymentRequester")
|
||
opsApprovals PaymentRequest[] @relation("OpsApprover")
|
||
finApprovals PaymentRequest[] @relation("FinApprover")
|
||
documentsResponsible Document[]
|
||
orderPhotos OrderPhoto[]
|
||
auditLogs AuditLog[]
|
||
smetasSubmitted Smeta[] @relation("SmetaSubmitter")
|
||
smetasValidated Smeta[] @relation("SmetaValidator")
|
||
estimateComments EstimateComment[] @relation("EstimateCommentAuthor")
|
||
notifications Notification[]
|
||
statusChanges OrderStatusHistory[] @relation("StatusChangeUser")
|
||
recurringPayments RecurringPayment[] @relation("RecurringPaymentCreator")
|
||
confirmedRequirements PurchaseRequirement[] @relation("RequirementConfirmer")
|
||
tendersCreated Tender[] @relation("TenderCreator")
|
||
purchaseOrdersCreated PurchaseOrder[] @relation("POCreator")
|
||
archivedRequirements PurchaseRequirement[] @relation("RequirementArchiver")
|
||
revisionAckRequirements PurchaseRequirement[] @relation("RequirementRevisionAck")
|
||
uploadedFiles DocumentFile[] @relation("UploadedFiles")
|
||
lineAwards TenderLineAward[] @relation("LineAwarder")
|
||
smetaRevisionsApproved SmetaRevision[] @relation("SmetaRevisionApprover")
|
||
smetaRevisionsCreated SmetaRevision[] @relation("SmetaRevisionCreator")
|
||
additionalCostsApproved AdditionalCost[] @relation("AdditionalCostApprover")
|
||
additionalCostsCreated AdditionalCost[] @relation("AdditionalCostCreator")
|
||
budgetFinValidations BudgetValidation[] @relation("BudgetFinValidator")
|
||
budgetTechValidations BudgetValidation[] @relation("BudgetTechValidator")
|
||
poInvoicesUploaded POInvoice[] @relation("POInvoiceUploadedBy")
|
||
prBudgetOverrides PurchaseRequirement[] @relation("PRBudgetOverride")
|
||
notificationPreferences UserNotificationPreference[]
|
||
fileTrackingConfigs FileTrackingConfig[]
|
||
forecastRebalanceLogs ForecastRebalanceLog[]
|
||
receptionsCreated PurchaseLineReception[] @relation("ReceptionCreator")
|
||
receptionsVerified PurchaseLineReception[] @relation("ReceptionVerifier")
|
||
receptionsAccounted PurchaseLineReception[] @relation("ReceptionAccountant")
|
||
orderCategoryNotes OrderCategoryNote[] @relation("OrderCategoryNoteCreator")
|
||
ordersAsConstructor Order[] @relation("OrderConstructor")
|
||
helpArticlesCreated HelpArticle[] @relation("HelpArticleCreatedBy")
|
||
|
||
@@index([role])
|
||
@@index([active])
|
||
@@map("users")
|
||
}
|
||
|
||
// CDC §4.4 — Base fournisseurs unifiée
|
||
model Supplier {
|
||
id Int @id @default(autoincrement())
|
||
companyName String @map("company_name")
|
||
inn String @unique
|
||
kpp String?
|
||
ogrn String?
|
||
legalAddress String? @map("legal_address")
|
||
contactName String? @map("contact_name")
|
||
contactPhone String? @map("contact_phone")
|
||
contactEmail String? @map("contact_email")
|
||
accountantName String? @map("accountant_name")
|
||
accountantPhone String? @map("accountant_phone")
|
||
accountantEmail String? @map("accountant_email")
|
||
productTags String[] @map("product_tags")
|
||
paymentDelayDays Int? @map("payment_delay_days")
|
||
deliveryDelayDays Int? @map("delivery_delay_days")
|
||
discountPercent Decimal? @map("discount_percent") @db.Decimal(5, 2)
|
||
notes String?
|
||
status SupplierStatus @default(ACTIVE)
|
||
isInternal Boolean @default(false) @map("is_internal")
|
||
isRegular Boolean @default(false) @map("is_regular")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
contacts SupplierContact[]
|
||
tagLinks SupplierTagLink[]
|
||
paymentRequests PaymentRequest[]
|
||
documents Document[] @relation("SupplierDocuments")
|
||
tenderOffers TenderOffer[]
|
||
purchaseOrders PurchaseOrder[]
|
||
cashflowEntries CashflowEntry[] @relation("SupplierCashflow")
|
||
recurringPayments RecurringPayment[]
|
||
hintedRequirements PurchaseRequirement[] @relation("SupplierHint")
|
||
preferredForPRs PurchaseRequirement[] @relation("PRPreferredSupplier")
|
||
tenderDispatches TenderDispatch[] @relation("TenderDispatches")
|
||
tenderLineAwards TenderLineAward[] @relation("TenderLineAwards")
|
||
deliveryNotes SupplierDeliveryNote[] @relation("SupplierDNs")
|
||
contracts SupplierContract[] @relation("SupplierContracts")
|
||
|
||
@@index([status])
|
||
@@index([inn])
|
||
@@index([deletedAt])
|
||
@@map("suppliers")
|
||
}
|
||
|
||
model SupplierContract {
|
||
id Int @id @default(autoincrement())
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation("SupplierContracts", fields: [supplierId], references: [id])
|
||
contractNumber String @map("contract_number")
|
||
contractDate DateTime @map("contract_date") @db.Date
|
||
startDate DateTime @map("start_date") @db.Date
|
||
endDate DateTime? @map("end_date") @db.Date
|
||
status SupplierContractStatus @default(DRAFT)
|
||
notes String?
|
||
documents Document[] @relation("SupplierContractDocuments")
|
||
terms SupplierContractPaymentTerm[]
|
||
purchaseOrders PurchaseOrder[]
|
||
signedAt DateTime? @map("signed_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([supplierId, contractNumber])
|
||
@@index([supplierId])
|
||
@@index([status])
|
||
@@map("supplier_contracts")
|
||
}
|
||
|
||
model SupplierContractPaymentTerm {
|
||
id Int @id @default(autoincrement())
|
||
contractId Int @map("contract_id")
|
||
contract SupplierContract @relation(fields: [contractId], references: [id], onDelete: Cascade)
|
||
percent Decimal @db.Decimal(5, 2)
|
||
trigger SupplierPaymentTrigger
|
||
offsetDays Int @default(0) @map("offset_days")
|
||
label String
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
|
||
@@index([contractId])
|
||
@@map("supplier_contract_payment_terms")
|
||
}
|
||
|
||
// CDC §4.4 — Contacts fournisseurs (opérationnels et comptables)
|
||
model SupplierContact {
|
||
id Int @id @default(autoincrement())
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation(fields: [supplierId], references: [id], onDelete: Cascade)
|
||
type SupplierContactType
|
||
name String
|
||
phone String?
|
||
email String?
|
||
position String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([supplierId])
|
||
@@map("supplier_contacts")
|
||
}
|
||
|
||
// CDC §4.4 — Tags fournisseurs (extensibles)
|
||
model SupplierTag {
|
||
id Int @id @default(autoincrement())
|
||
name String @unique
|
||
label String?
|
||
isIndirect Boolean @default(false) @map("is_indirect")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
// Relations
|
||
supplierLinks SupplierTagLink[]
|
||
|
||
@@map("supplier_tags")
|
||
}
|
||
|
||
// CDC §4.4 — Liaison fournisseur-tag (N-N)
|
||
model SupplierTagLink {
|
||
supplierId Int @map("supplier_id")
|
||
tagId Int @map("tag_id")
|
||
supplier Supplier @relation(fields: [supplierId], references: [id], onDelete: Cascade)
|
||
tag SupplierTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
||
|
||
@@id([supplierId, tagId])
|
||
@@map("supplier_tag_links")
|
||
}
|
||
|
||
// CDC — Client
|
||
model Client {
|
||
id Int @id @default(autoincrement())
|
||
companyName String @map("company_name")
|
||
inn String? @unique
|
||
kpp String?
|
||
abbreviation String? @unique
|
||
contactName String? @map("contact_name")
|
||
phone String?
|
||
email String?
|
||
address String?
|
||
isActive Boolean @default(true) @map("is_active")
|
||
notes String?
|
||
onecGuid String? @unique @map("onec_guid")
|
||
onecSyncedAt DateTime? @map("onec_synced_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
orders Order[]
|
||
documents Document[] @relation("ClientDocuments")
|
||
cashflowEntries CashflowEntry[] @relation("ClientCashflow")
|
||
contracts ClientContract[]
|
||
|
||
@@index([isActive])
|
||
@@map("clients")
|
||
}
|
||
|
||
// CDC §5.1-5.2 — Fiche de commande
|
||
model Order {
|
||
id Int @id @default(autoincrement())
|
||
orderCode String @unique @map("order_code")
|
||
clientId Int @map("client_id")
|
||
client Client @relation(fields: [clientId], references: [id])
|
||
managerId String? @map("manager_id")
|
||
manager User? @relation("OrderManager", fields: [managerId], references: [id])
|
||
status OrderStatus @default(DRAFT)
|
||
orderType OrderType @default(STANDARD) @map("order_type")
|
||
executionUnit ExecutionUnit @default(MAIN_PRODUCTION) @map("execution_unit")
|
||
productName String @map("product_name")
|
||
quantity Int @default(1)
|
||
dimensions String?
|
||
colorRal String? @map("color_ral")
|
||
massKg Decimal? @map("mass_kg") @db.Decimal(10, 4)
|
||
contractNumber String? @map("contract_number")
|
||
paymentTerms Json? @map("payment_terms")
|
||
kdFolderPath String? @map("kd_folder_path")
|
||
smetaFolderPath String? @map("smeta_folder_path")
|
||
specFolderPath String? @map("spec_folder_path")
|
||
launchDate DateTime? @map("launch_date")
|
||
deliveryDate DateTime? @map("delivery_date")
|
||
cancelReason String? @map("cancel_reason")
|
||
cancelledAt DateTime? @map("cancelled_at")
|
||
thumbnailPath String? @map("thumbnail_path")
|
||
notes String?
|
||
contractId Int? @map("contract_id")
|
||
contract ClientContract? @relation("OrderClientContract", fields: [contractId], references: [id])
|
||
constructorId String? @map("constructor_id")
|
||
constructor User? @relation("OrderConstructor", fields: [constructorId], references: [id])
|
||
planningComment String? @map("planning_comment") @db.VarChar(300)
|
||
productionStatusText String? @map("production_status_text") @db.VarChar(200)
|
||
executorText String? @map("executor_text") @db.VarChar(100)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
smetas Smeta[]
|
||
revisions OrderRevision[]
|
||
financialTracking FinancialTracking?
|
||
purchaseRequirements PurchaseRequirement[]
|
||
purchaseOrders PurchaseOrder[]
|
||
paymentRequests PaymentRequest[]
|
||
photos OrderPhoto[]
|
||
documents Document[] @relation("OrderDocuments")
|
||
cashflowEntries CashflowEntry[] @relation("OrderCashflow")
|
||
statusHistory OrderStatusHistory[]
|
||
smetaRevisions SmetaRevision[]
|
||
additionalCosts AdditionalCost[]
|
||
budgetValidation BudgetValidation?
|
||
clientInvoices ClientInvoice[]
|
||
plannedDeliveryLots PlannedDeliveryLot[]
|
||
deliveryLots DeliveryLot[]
|
||
clientInstallments ClientInstallment[]
|
||
forecastInstallments ForecastInstallment[]
|
||
categoryNotes OrderCategoryNote[]
|
||
|
||
productImagePath String? @map("product_image_path")
|
||
productImageMime String? @map("product_image_mime")
|
||
productImageHash String? @map("product_image_hash")
|
||
productImageSource String? @map("product_image_source")
|
||
|
||
@@index([status])
|
||
@@index([clientId])
|
||
@@index([managerId])
|
||
@@index([constructorId])
|
||
@@index([executionUnit])
|
||
@@index([createdAt])
|
||
@@map("orders")
|
||
}
|
||
|
||
// CDC §5.1 — Historique transitions de statut commande
|
||
model OrderStatusHistory {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
fromStatus OrderStatus @map("from_status")
|
||
toStatus OrderStatus @map("to_status")
|
||
changedById String @map("changed_by_id")
|
||
changedBy User @relation("StatusChangeUser", fields: [changedById], references: [id])
|
||
comment String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([orderId])
|
||
@@index([createdAt])
|
||
@@map("order_status_history")
|
||
}
|
||
|
||
// CDC §5.3 — Gestion des révisions
|
||
model OrderRevision {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
version Int
|
||
reason RevisionReason
|
||
description String?
|
||
status RevisionStatus @default(DRAFT)
|
||
// Deltas financiers
|
||
deltaServices Decimal @default(0) @map("delta_services") @db.Decimal(12, 2)
|
||
deltaMaterials Decimal @default(0) @map("delta_materials") @db.Decimal(12, 2)
|
||
deltaLabor Decimal @default(0) @map("delta_labor") @db.Decimal(12, 2)
|
||
deltaSellingPrice Decimal @default(0) @map("delta_selling_price") @db.Decimal(12, 2)
|
||
additionalPurchasesDesc String? @map("additional_purchases_desc")
|
||
delayImpactDays Int? @map("delay_impact_days")
|
||
drawingChanges String? @map("drawing_changes")
|
||
generatesNewPurchases Boolean @default(false) @map("generates_new_purchases")
|
||
// Initiateur
|
||
initiatorId String @map("initiator_id")
|
||
initiator User @relation("RevisionInitiator", fields: [initiatorId], references: [id])
|
||
// Approbation financière (DIRECTION_FIN)
|
||
finApproverId String? @map("fin_approver_id")
|
||
finApprovalComment String? @map("fin_approval_comment")
|
||
finApprovedAt DateTime? @map("fin_approved_at")
|
||
// Approbation production (DIRECTION_OPS)
|
||
opsApproverId String? @map("ops_approver_id")
|
||
opsApprovalComment String? @map("ops_approval_comment")
|
||
opsApprovedAt DateTime? @map("ops_approved_at")
|
||
// Rejet
|
||
rejectedById String? @map("rejected_by_id")
|
||
rejectionComment String? @map("rejection_comment")
|
||
rejectedAt DateTime? @map("rejected_at")
|
||
// Timestamps
|
||
submittedAt DateTime? @map("submitted_at")
|
||
approvedAt DateTime? @map("approved_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([orderId, version])
|
||
@@index([orderId])
|
||
@@index([status])
|
||
@@index([initiatorId])
|
||
@@map("order_revisions")
|
||
}
|
||
|
||
// CDC §4.2, §7.1 — Budget commande (смета) avec workflow validation
|
||
model Smeta {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
version Int @default(1)
|
||
status EstimateStatus @default(DRAFT)
|
||
filePath String? @map("file_path")
|
||
totalServices Decimal @default(0) @map("total_services") @db.Decimal(12, 2)
|
||
totalMaterials Decimal @default(0) @map("total_materials") @db.Decimal(12, 2)
|
||
totalLabor Decimal @default(0) @map("total_labor") @db.Decimal(12, 2)
|
||
supplyOverhead Decimal @default(0) @map("supply_overhead") @db.Decimal(12, 2)
|
||
margin Decimal @default(0) @db.Decimal(12, 2)
|
||
tradeSurcharge Decimal @default(0) @map("trade_surcharge") @db.Decimal(12, 2)
|
||
sellingPrice Decimal @default(0) @map("selling_price") @db.Decimal(12, 2)
|
||
isLocked Boolean @default(false) @map("is_locked")
|
||
submittedById String? @map("submitted_by_id")
|
||
submittedBy User? @relation("SmetaSubmitter", fields: [submittedById], references: [id])
|
||
submittedAt DateTime? @map("submitted_at")
|
||
validatedById String? @map("validated_by_id")
|
||
validatedBy User? @relation("SmetaValidator", fields: [validatedById], references: [id])
|
||
validatedAt DateTime? @map("validated_at")
|
||
lockedAt DateTime? @map("locked_at")
|
||
previousVersionId Int? @map("previous_version_id")
|
||
previousVersion Smeta? @relation("SmetaVersions", fields: [previousVersionId], references: [id])
|
||
nextVersions Smeta[] @relation("SmetaVersions")
|
||
deltaJson Json? @map("delta_json")
|
||
importSource String? @map("import_source") // 'EXCEL' | 'MANUAL' | null
|
||
importedAt DateTime? @map("imported_at")
|
||
importedFile String? @map("imported_file") // nom du fichier importé
|
||
manualEdits Json? @map("manual_edits") // log des éditions manuelles post-import
|
||
specData Json? @map("spec_data") // parsed spec lines from СПЕЦИФИКАЦИЯ (for PR generation at LAUNCH)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
comments EstimateComment[]
|
||
lines SmetaLine[]
|
||
revisionsAsOld SmetaRevision[] @relation("OldSmeta")
|
||
revisionsAsNew SmetaRevision[] @relation("NewSmeta")
|
||
|
||
@@unique([orderId, version])
|
||
@@index([orderId])
|
||
@@index([status])
|
||
@@map("smetas")
|
||
}
|
||
|
||
// CDC §4.2 — Commentaires de validation смета
|
||
model EstimateComment {
|
||
id Int @id @default(autoincrement())
|
||
smetaId Int @map("smeta_id")
|
||
smeta Smeta @relation(fields: [smetaId], references: [id], onDelete: Cascade)
|
||
authorId String @map("author_id")
|
||
author User @relation("EstimateCommentAuthor", fields: [authorId], references: [id])
|
||
content String
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([smetaId])
|
||
@@map("estimate_comments")
|
||
}
|
||
|
||
// SPEC 13A-1 — Lignes détaillées смета (import Excel)
|
||
model SmetaLine {
|
||
id Int @id @default(autoincrement())
|
||
smetaId Int @map("smeta_id")
|
||
smeta Smeta @relation(fields: [smetaId], references: [id], onDelete: Cascade)
|
||
lineType SmetaLineType @map("line_type")
|
||
lineCategory String? @map("line_category")
|
||
description String
|
||
unit String?
|
||
quantity Decimal? @db.Decimal(12, 4)
|
||
normHours Decimal? @map("norm_hours") @db.Decimal(12, 4)
|
||
unitPrice Decimal? @map("unit_price") @db.Decimal(12, 2)
|
||
totalPrice Decimal @default(0) @map("total_price") @db.Decimal(12, 2)
|
||
position Int @default(0)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([smetaId])
|
||
@@map("smeta_lines")
|
||
}
|
||
|
||
// CDC §4.1 — Demandes de paiement
|
||
model PaymentRequest {
|
||
id Int @id @default(autoincrement())
|
||
requestNumber String @unique @map("request_number")
|
||
requesterId String @map("requester_id")
|
||
requester User @relation("PaymentRequester", fields: [requesterId], references: [id])
|
||
supplierId Int? @map("supplier_id")
|
||
supplier Supplier? @relation(fields: [supplierId], references: [id])
|
||
orderId Int? @map("order_id")
|
||
order Order? @relation(fields: [orderId], references: [id])
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder? @relation("POPaymentRequests", fields: [purchaseOrderId], references: [id])
|
||
amount Decimal @db.Decimal(12, 2)
|
||
category PaymentCategory
|
||
expenseCodeId Int? @map("expense_code_id")
|
||
expenseCode ExpenseCode? @relation("PRExpenseCode", fields: [expenseCodeId], references: [id])
|
||
description String
|
||
invoiceFilePath String? @map("invoice_file_path")
|
||
status ApprovalStatus @default(PENDING)
|
||
opsApproverId String? @map("ops_approver_id")
|
||
opsApprover User? @relation("OpsApprover", fields: [opsApproverId], references: [id])
|
||
opsApprovedAt DateTime? @map("ops_approved_at")
|
||
finApproverId String? @map("fin_approver_id")
|
||
finApprover User? @relation("FinApprover", fields: [finApproverId], references: [id])
|
||
finApprovedAt DateTime? @map("fin_approved_at")
|
||
rejectionComment String? @map("rejection_comment")
|
||
budgetCheckResult String? @map("budget_check_result")
|
||
budgetOverrunPercent Decimal? @map("budget_overrun_percent") @db.Decimal(5, 2)
|
||
paidAt DateTime? @map("paid_at")
|
||
dueDate DateTime? @map("due_date")
|
||
isRecurring Boolean @default(false) @map("is_recurring")
|
||
recurrenceType RecurrenceType? @map("recurrence_type")
|
||
recurrenceEndDate DateTime? @map("recurrence_end_date")
|
||
parentRecurringId Int? @map("parent_recurring_id")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
poInvoice POInvoice?
|
||
installment POInstallment?
|
||
|
||
@@index([status])
|
||
@@index([category])
|
||
@@index([requesterId])
|
||
@@index([orderId])
|
||
@@index([purchaseOrderId])
|
||
@@index([createdAt])
|
||
@@index([isRecurring])
|
||
@@map("payment_requests")
|
||
}
|
||
|
||
// CDC §4.1.1 — Budgets mensuels
|
||
model MonthlyBudget {
|
||
id Int @id @default(autoincrement())
|
||
category PaymentCategory
|
||
expenseCodeId Int @map("expense_code_id")
|
||
expenseCode ExpenseCode @relation("MBExpenseCode", fields: [expenseCodeId], references: [id])
|
||
month Int
|
||
year Int
|
||
allocatedAmount Decimal @map("allocated_amount") @db.Decimal(12, 2)
|
||
consumedAmount Decimal @default(0) @map("consumed_amount") @db.Decimal(12, 2)
|
||
alertThreshold Decimal @default(70) @map("alert_threshold") @db.Decimal(5, 2)
|
||
budgetMode String @default("FIXED") @map("budget_mode")
|
||
productionVolumeBase Decimal? @map("production_volume_base") @db.Decimal(12, 2)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([category, expenseCodeId, month, year])
|
||
@@map("monthly_budgets")
|
||
}
|
||
|
||
// SPEC-39A — Codes budgétaires en base (remplace enum ExpenseCodeLegacy)
|
||
model ExpenseCode {
|
||
id Int @id @default(autoincrement())
|
||
code String @unique
|
||
labelRu String @map("label_ru")
|
||
groupCode String @map("group_code")
|
||
groupLabel String @map("group_label")
|
||
parentCategory PaymentCategory
|
||
scope String @default("INDIRECT_ADMIN")
|
||
isSystem Boolean @default(true) @map("is_system")
|
||
isActive Boolean @default(true) @map("is_active")
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
paymentRequests PaymentRequest[] @relation("PRExpenseCode")
|
||
monthlyBudgets MonthlyBudget[] @relation("MBExpenseCode")
|
||
recurringPayments RecurringPayment[] @relation("RPExpenseCode")
|
||
purchaseOrders PurchaseOrder[]
|
||
purchaseRequirements PurchaseRequirement[] @relation("RequirementExpenseCode")
|
||
cashflowEntries CashflowEntry[] @relation("CFExpenseCode")
|
||
smetaMappings SmetaBudgetMapping[] @relation("MappingExpenseCode")
|
||
|
||
@@index([groupCode])
|
||
@@index([parentCategory])
|
||
@@index([scope])
|
||
@@index([isActive])
|
||
@@map("expense_codes")
|
||
}
|
||
|
||
// SPEC-40D — Mapping des champs smeta vers les codes budg\u00e9taires (ventilation %)
|
||
model SmetaBudgetMapping {
|
||
id Int @id @default(autoincrement())
|
||
smetaField String @map("smeta_field")
|
||
expenseCodeId Int @map("expense_code_id")
|
||
expenseCode ExpenseCode @relation("MappingExpenseCode", fields: [expenseCodeId], references: [id])
|
||
percent Decimal @db.Decimal(5, 2)
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([smetaField, expenseCodeId])
|
||
@@index([smetaField])
|
||
@@map("smeta_budget_mappings")
|
||
}
|
||
|
||
// CDC §4.1 — Modèle de paiement récurrent (dépenses administratives)
|
||
model RecurringPayment {
|
||
id Int @id @default(autoincrement())
|
||
templateName String @map("template_name")
|
||
supplierId Int? @map("supplier_id")
|
||
supplier Supplier? @relation(fields: [supplierId], references: [id])
|
||
amount Decimal @db.Decimal(12, 2)
|
||
category PaymentCategory @default(ADMINISTRATIVE)
|
||
expenseCodeId Int @map("expense_code_id")
|
||
expenseCode ExpenseCode @relation("RPExpenseCode", fields: [expenseCodeId], references: [id])
|
||
recurrenceType RecurrenceType @map("recurrence_type")
|
||
dayOfMonth Int @default(1) @map("day_of_month")
|
||
nextGenerationDate DateTime @map("next_generation_date")
|
||
isActive Boolean @default(true) @map("is_active")
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("RecurringPaymentCreator", fields: [createdById], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([isActive])
|
||
@@index([nextGenerationDate])
|
||
@@map("recurring_payments")
|
||
}
|
||
|
||
// CDC §4.3 — Suivi documentaire
|
||
model Document {
|
||
id Int @id @default(autoincrement())
|
||
documentType DocumentType @map("document_type")
|
||
documentReference String? @map("document_reference")
|
||
title String
|
||
filePath String? @map("file_path")
|
||
orderId Int? @map("order_id")
|
||
order Order? @relation("OrderDocuments", fields: [orderId], references: [id])
|
||
supplierId Int? @map("supplier_id")
|
||
supplier Supplier? @relation("SupplierDocuments", fields: [supplierId], references: [id])
|
||
clientId Int? @map("client_id")
|
||
client Client? @relation("ClientDocuments", fields: [clientId], references: [id])
|
||
sentAt DateTime? @map("sent_at")
|
||
sentChannel DocumentChannel? @map("sent_channel")
|
||
returnExpectedAt DateTime? @map("return_expected_at")
|
||
returnActualAt DateTime? @map("return_actual_at")
|
||
responsibleId String? @map("responsible_id")
|
||
responsible User? @relation(fields: [responsibleId], references: [id])
|
||
trackingStatus DocumentTrackingStatus? @map("tracking_status")
|
||
nextReminderAt DateTime? @map("next_reminder_at")
|
||
escalatedAt DateTime? @map("escalated_at")
|
||
receivedAt DateTime? @map("received_at")
|
||
closedAt DateTime? @map("closed_at")
|
||
reminderCount Int @default(0) @map("reminder_count")
|
||
lastReminderAt DateTime? @map("last_reminder_at")
|
||
comment String?
|
||
direction DocumentDirection?
|
||
onecGuid String? @unique @map("onec_guid")
|
||
onecSyncedAt DateTime? @map("onec_synced_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Self-relation for APPENDIX documents
|
||
parentDocumentId Int? @map("parent_document_id")
|
||
parentDocument Document? @relation("DocumentParent", fields: [parentDocumentId], references: [id])
|
||
childDocuments Document[] @relation("DocumentParent")
|
||
|
||
// FK cashflow client
|
||
clientContractId Int? @map("client_contract_id")
|
||
clientContract ClientContract? @relation(fields: [clientContractId], references: [id])
|
||
deliveryLotId Int? @map("delivery_lot_id")
|
||
deliveryLot DeliveryLot? @relation(fields: [deliveryLotId], references: [id])
|
||
clientInvoiceId Int? @map("client_invoice_id")
|
||
clientInvoice ClientInvoice? @relation(fields: [clientInvoiceId], references: [id])
|
||
supplierDeliveryNoteId Int? @map("supplier_delivery_note_id")
|
||
supplierDeliveryNote SupplierDeliveryNote? @relation("SDNDocuments", fields: [supplierDeliveryNoteId], references: [id])
|
||
supplierContractId Int? @map("supplier_contract_id")
|
||
supplierContract SupplierContract? @relation("SupplierContractDocuments", fields: [supplierContractId], references: [id])
|
||
|
||
// Relations
|
||
notifications Notification[]
|
||
files DocumentFile[] @relation("DocumentFiles")
|
||
lastFileReminderAt DateTime? @map("last_file_reminder_at")
|
||
fileReminderCount Int @default(0) @map("file_reminder_count")
|
||
|
||
@@index([documentType])
|
||
@@index([orderId])
|
||
@@index([supplierId])
|
||
@@index([returnExpectedAt])
|
||
@@index([trackingStatus])
|
||
@@index([nextReminderAt])
|
||
@@index([direction])
|
||
@@index([parentDocumentId])
|
||
@@index([deletedAt])
|
||
@@index([clientContractId])
|
||
@@index([deliveryLotId])
|
||
@@index([clientInvoiceId])
|
||
@@index([supplierDeliveryNoteId])
|
||
@@index([supplierContractId])
|
||
@@index([lastFileReminderAt])
|
||
@@map("documents")
|
||
}
|
||
|
||
// CDC §13A — Fichiers attachés aux documents
|
||
model DocumentFile {
|
||
id Int @id @default(autoincrement())
|
||
documentId Int @map("document_id")
|
||
document Document @relation("DocumentFiles", fields: [documentId], references: [id])
|
||
|
||
originalName String @map("original_name")
|
||
storedPath String @map("stored_path")
|
||
mimeType String @map("mime_type")
|
||
fileSize Int @map("file_size")
|
||
|
||
version Int @default(1)
|
||
isLatest Boolean @default(true) @map("is_latest")
|
||
|
||
uploadedById String @map("uploaded_by_id")
|
||
uploadedBy User @relation("UploadedFiles", fields: [uploadedById], references: [id])
|
||
|
||
comment String?
|
||
checksum String?
|
||
|
||
deletedAt DateTime? @map("deleted_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([documentId])
|
||
@@index([documentId, isLatest])
|
||
@@index([uploadedById])
|
||
@@map("document_files")
|
||
}
|
||
|
||
// CDC §5 — Notifications centralisées
|
||
model Notification {
|
||
id Int @id @default(autoincrement())
|
||
documentId Int? @map("document_id")
|
||
document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||
recipientId String @map("recipient_id")
|
||
recipient User @relation(fields: [recipientId], references: [id])
|
||
type String // REMINDER_1, REMINDER_2, REMINDER_3, ESCALATION, RECEIVED, ALERT, TASK, INFO
|
||
message String
|
||
entityType String? @map("entity_type") // ORDER, PAYMENT_REQUEST, SMETA, DOCUMENT, PURCHASE_ORDER, FINANCIAL_ALERT, SYSTEM
|
||
entityId Int? @map("entity_id")
|
||
priority NotificationPriority @default(NORMAL)
|
||
actionRequired Boolean @default(false) @map("action_required")
|
||
actionUrl String? @map("action_url")
|
||
expiresAt DateTime? @map("expires_at")
|
||
readAt DateTime? @map("read_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([documentId])
|
||
@@index([recipientId])
|
||
@@index([readAt])
|
||
@@index([entityType, entityId])
|
||
@@index([actionRequired])
|
||
@@map("notifications")
|
||
}
|
||
|
||
// CDC §4.3 — Configuration délais relance (configurable)
|
||
model ReminderConfig {
|
||
id Int @id @default(autoincrement())
|
||
key String @unique // reminder_1_days, reminder_2_days, reminder_3_days
|
||
value Int // nombre de jours
|
||
label String? // description lisible
|
||
|
||
@@map("reminder_configs")
|
||
}
|
||
|
||
// CDC §6.1 étape 1 — Besoins d'achat
|
||
model PurchaseRequirement {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int? @map("order_id")
|
||
order Order? @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
materialCategory MaterialCategory @map("material_category")
|
||
description String
|
||
quantity Decimal @db.Decimal(12, 2)
|
||
originalQuantity Decimal? @map("original_quantity") @db.Decimal(12, 2)
|
||
unit String @default("шт")
|
||
estimatedPrice Decimal? @map("estimated_price") @db.Decimal(12, 2)
|
||
status PurchaseRequirementStatus @default(DRAFT)
|
||
priority PurchasePriority @default(NORMAL)
|
||
requiredByDate DateTime? @map("required_by_date")
|
||
sourceType String? @map("source_type")
|
||
sourceId Int? @map("source_id")
|
||
confirmedById String? @map("confirmed_by_id")
|
||
confirmedBy User? @relation("RequirementConfirmer", fields: [confirmedById], references: [id])
|
||
confirmedAt DateTime? @map("confirmed_at")
|
||
quantityPerUnit Decimal? @map("quantity_per_unit") @db.Decimal(12, 4)
|
||
sourceReference String? @map("source_reference")
|
||
budgetAmount Decimal? @map("budget_amount") @db.Decimal(12, 2)
|
||
notes String?
|
||
extraPurchaseReason String? @map("extra_purchase_reason")
|
||
supplierHintId Int? @map("supplier_hint_id")
|
||
supplierHint Supplier? @relation("SupplierHint", fields: [supplierHintId], references: [id])
|
||
tenderId Int? @map("tender_id")
|
||
tender Tender? @relation(fields: [tenderId], references: [id])
|
||
archived Boolean @default(false)
|
||
archivedAt DateTime? @map("archived_at")
|
||
archivedById String? @map("archived_by_id")
|
||
archivedBy User? @relation("RequirementArchiver", fields: [archivedById], references: [id])
|
||
deletedAt DateTime? @map("deleted_at")
|
||
inStock Boolean @default(false) @map("in_stock")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
// ACHATS-A — champs lotissement
|
||
totalQuantity Decimal? @map("total_quantity") @db.Decimal(10, 3)
|
||
selectedSupplierId Int? @map("selected_supplier_id")
|
||
negotiatedPrice Decimal? @map("negotiated_price") @db.Decimal(10, 2)
|
||
lots PurchaseLot[]
|
||
offerLines TenderOfferLine[]
|
||
lineAwards TenderLineAward[]
|
||
poLines PurchaseOrderLine[] @relation("POLineToPR")
|
||
|
||
// SPEC 29A — revision alert fields
|
||
revisionAlert Boolean @default(false) @map("revision_alert")
|
||
revisionNote String? @map("revision_note")
|
||
revisionAckBy String? @map("revision_ack_by")
|
||
revisionAckAt DateTime? @map("revision_ack_at")
|
||
revisionAckUser User? @relation("RequirementRevisionAck", fields: [revisionAckBy], references: [id])
|
||
|
||
// SPEC 39DE-v2 — PR indirects
|
||
isIndirect Boolean @default(false) @map("is_indirect")
|
||
expenseCodeId Int? @map("expense_code_id")
|
||
expenseCode ExpenseCode? @relation("RequirementExpenseCode", fields: [expenseCodeId], references: [id])
|
||
budgetPeriod String? @map("budget_period")
|
||
preferredSupplierId Int? @map("preferred_supplier_id")
|
||
preferredSupplier Supplier? @relation("PRPreferredSupplier", fields: [preferredSupplierId], references: [id])
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder? @relation("PRtoPO", fields: [purchaseOrderId], references: [id])
|
||
budgetOverrideBy String? @map("budget_override_by")
|
||
budgetOverrideByUser User? @relation("PRBudgetOverride", fields: [budgetOverrideBy], references: [id])
|
||
budgetOverrideAt DateTime? @map("budget_override_at")
|
||
|
||
@@index([orderId])
|
||
@@index([materialCategory])
|
||
@@index([status])
|
||
@@index([priority])
|
||
@@index([materialCategory, status])
|
||
@@index([archived])
|
||
@@index([isIndirect])
|
||
@@index([expenseCodeId])
|
||
@@index([revisionAlert])
|
||
@@map("purchase_requirements")
|
||
}
|
||
|
||
// ACHATS-A — Lotissement des besoins d'achat
|
||
model PurchaseLot {
|
||
id Int @id @default(autoincrement())
|
||
requirementId Int? @map("requirement_id")
|
||
requirement PurchaseRequirement? @relation(fields: [requirementId], references: [id], onDelete: Cascade)
|
||
lotNumber Int @map("lot_number")
|
||
quantity Decimal @db.Decimal(15, 2)
|
||
plannedDate DateTime? @map("planned_date")
|
||
paymentDate DateTime? @map("payment_date")
|
||
deliveryDate DateTime? @map("delivery_date")
|
||
deliveryDays Int? @map("delivery_days")
|
||
status PurchaseLotStatus @default(PLANNED)
|
||
validatedByFinId String? @map("validated_by_fin_id")
|
||
validatedByTechId String? @map("validated_by_tech_id")
|
||
validatedAt DateTime? @map("validated_at")
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder? @relation(fields: [purchaseOrderId], references: [id])
|
||
invoices POInvoice[]
|
||
lotLines PurchaseLotLine[]
|
||
receptions PurchaseLineReception[]
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([requirementId, lotNumber])
|
||
@@index([requirementId])
|
||
@@index([status])
|
||
@@index([purchaseOrderId])
|
||
@@map("purchase_lots")
|
||
}
|
||
|
||
model PurchaseLotLine {
|
||
id Int @id @default(autoincrement())
|
||
lotId Int @map("lot_id")
|
||
lot PurchaseLot @relation(fields: [lotId], references: [id], onDelete: Cascade)
|
||
poLineId Int @map("po_line_id")
|
||
poLine PurchaseOrderLine @relation(fields: [poLineId], references: [id], onDelete: Cascade)
|
||
quantity Decimal @db.Decimal(12, 2)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@unique([lotId, poLineId])
|
||
@@index([lotId])
|
||
@@index([poLineId])
|
||
@@map("purchase_lot_lines")
|
||
}
|
||
|
||
// CDC §6.1 étapes 2-5 — Mini-appel d'offres
|
||
model Tender {
|
||
id Int @id @default(autoincrement())
|
||
referenceCode String @unique @map("reference_code")
|
||
status TenderStatus @default(DRAFT)
|
||
description String?
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("TenderCreator", fields: [createdById], references: [id])
|
||
deadline DateTime?
|
||
awardedOfferId Int? @unique @map("awarded_offer_id")
|
||
awardedOffer TenderOffer? @relation("AwardedOffer", fields: [awardedOfferId], references: [id])
|
||
awardedAt DateTime? @map("awarded_at")
|
||
closedReason String? @map("closed_reason")
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
requirements PurchaseRequirement[]
|
||
offers TenderOffer[]
|
||
purchaseOrders PurchaseOrder[] @relation("TenderPurchaseOrders")
|
||
dispatches TenderDispatch[]
|
||
lineAwards TenderLineAward[]
|
||
|
||
@@index([status])
|
||
@@index([createdById])
|
||
@@map("tenders")
|
||
}
|
||
|
||
// CDC §6.1 étape 3-4 — Offres fournisseurs
|
||
model TenderOffer {
|
||
id Int @id @default(autoincrement())
|
||
tenderId Int @map("tender_id")
|
||
tender Tender @relation(fields: [tenderId], references: [id], onDelete: Cascade)
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation(fields: [supplierId], references: [id])
|
||
proposedPrice Decimal? @map("proposed_price") @db.Decimal(12, 2)
|
||
deliveryDays Int? @map("delivery_days")
|
||
conditions String?
|
||
receivedAt DateTime @default(now()) @map("received_at")
|
||
isSelected Boolean @default(false) @map("is_selected")
|
||
receivedVia String? @map("received_via")
|
||
validUntil DateTime? @map("valid_until")
|
||
notes String?
|
||
ranking Int?
|
||
attachmentPaths String[] @default([]) @map("attachment_paths")
|
||
|
||
// Relations
|
||
awardedTender Tender? @relation("AwardedOffer")
|
||
lines TenderOfferLine[]
|
||
lineAwards TenderLineAward[]
|
||
|
||
@@index([tenderId])
|
||
@@index([supplierId])
|
||
@@map("tender_offers")
|
||
}
|
||
|
||
// SPEC 20A — Détail ligne par ligne des offres fournisseurs
|
||
model TenderOfferLine {
|
||
id Int @id @default(autoincrement())
|
||
offerId Int @map("offer_id")
|
||
offer TenderOffer @relation(fields: [offerId], references: [id], onDelete: Cascade)
|
||
requirementId Int @map("requirement_id")
|
||
requirement PurchaseRequirement @relation(fields: [requirementId], references: [id])
|
||
unitPrice Decimal? @map("unit_price") @db.Decimal(12, 2)
|
||
quantity Decimal @db.Decimal(12, 2)
|
||
unit String @default("шт")
|
||
totalLinePrice Decimal? @map("total_line_price") @db.Decimal(12, 2)
|
||
available Boolean @default(true)
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([offerId])
|
||
@@index([requirementId])
|
||
@@map("tender_offer_lines")
|
||
}
|
||
|
||
// SPEC 20D — Attribution ligne par ligne des tenders
|
||
model TenderLineAward {
|
||
id Int @id @default(autoincrement())
|
||
tenderId Int @map("tender_id")
|
||
tender Tender @relation(fields: [tenderId], references: [id], onDelete: Cascade)
|
||
requirementId Int @map("requirement_id")
|
||
requirement PurchaseRequirement @relation(fields: [requirementId], references: [id])
|
||
offerId Int @map("offer_id")
|
||
offer TenderOffer @relation(fields: [offerId], references: [id])
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation("TenderLineAwards", fields: [supplierId], references: [id])
|
||
unitPrice Decimal @map("unit_price") @db.Decimal(12, 2)
|
||
quantity Decimal @db.Decimal(12, 2)
|
||
totalPrice Decimal @map("total_price") @db.Decimal(12, 2)
|
||
awardedById String @map("awarded_by_id")
|
||
awardedBy User @relation("LineAwarder", fields: [awardedById], references: [id])
|
||
awardedAt DateTime @default(now()) @map("awarded_at")
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder? @relation(fields: [purchaseOrderId], references: [id])
|
||
notes String?
|
||
|
||
@@unique([tenderId, requirementId])
|
||
@@index([tenderId])
|
||
@@index([offerId])
|
||
@@index([supplierId])
|
||
@@index([purchaseOrderId])
|
||
@@map("tender_line_awards")
|
||
}
|
||
|
||
// SPEC 19B — Suivi envois consultation fournisseurs
|
||
model TenderDispatch {
|
||
id Int @id @default(autoincrement())
|
||
tenderId Int @map("tender_id")
|
||
tender Tender @relation(fields: [tenderId], references: [id], onDelete: Cascade)
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation("TenderDispatches", fields: [supplierId], references: [id])
|
||
supplierEmail String @map("supplier_email")
|
||
sentAt DateTime @default(now()) @map("sent_at")
|
||
status String @default("SENT") // SENT, RESPONDED, NO_RESPONSE
|
||
respondedAt DateTime? @map("responded_at")
|
||
notes String?
|
||
requirementIds Json? @map("requirement_ids") // Array of PR ids this supplier covers
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([tenderId])
|
||
@@index([supplierId])
|
||
@@map("tender_dispatches")
|
||
}
|
||
|
||
// CDC §6.1 étapes 5-7 — Commande fournisseur
|
||
model PurchaseOrder {
|
||
id Int @id @default(autoincrement())
|
||
orderCode String @unique @map("order_code")
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation(fields: [supplierId], references: [id])
|
||
clientOrderId Int? @map("client_order_id")
|
||
clientOrder Order? @relation(fields: [clientOrderId], references: [id])
|
||
items Json
|
||
totalAmount Decimal @map("total_amount") @db.Decimal(12, 2)
|
||
qrCodePath String? @map("qr_code_path")
|
||
emailSentAt DateTime? @map("email_sent_at")
|
||
batchNumber Int? @map("batch_number")
|
||
totalBatches Int? @map("total_batches")
|
||
status PurchaseOrderStatus @default(DRAFT)
|
||
invoiceValidated Boolean @default(false) @map("invoice_validated")
|
||
isInternalTlt Boolean @default(false) @map("is_internal_tlt")
|
||
tltPaymentMode TltPaymentMode? @map("tlt_payment_mode")
|
||
drawingFilePaths String[] @map("drawing_file_paths")
|
||
tenderId Int? @map("tender_id")
|
||
tender Tender? @relation("TenderPurchaseOrders", fields: [tenderId], references: [id])
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("POCreator", fields: [createdById], references: [id])
|
||
expectedDeliveryDate DateTime? @map("expected_delivery_date")
|
||
actualDeliveryDate DateTime? @map("actual_delivery_date")
|
||
deliveryNotes String? @map("delivery_notes")
|
||
paymentStatus String? @map("payment_status")
|
||
paidAmount Decimal? @map("paid_amount") @db.Decimal(12, 2)
|
||
notes String?
|
||
archived Boolean @default(false)
|
||
archivedAt DateTime? @map("archived_at")
|
||
// SPEC-39A — classification budgétaire
|
||
isIndirect Boolean @default(false) @map("is_indirect")
|
||
expenseCodeId Int? @map("expense_code_id")
|
||
expenseCode ExpenseCode? @relation(fields: [expenseCodeId], references: [id])
|
||
budgetPeriod String? @map("budget_period")
|
||
budgetOverrideBy String? @map("budget_override_by")
|
||
budgetOverrideAt DateTime? @map("budget_override_at")
|
||
supplierContractId Int? @map("supplier_contract_id")
|
||
supplierContract SupplierContract? @relation(fields: [supplierContractId], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
// Relations
|
||
lines PurchaseOrderLine[]
|
||
lots PurchaseLot[]
|
||
tenderLineAwards TenderLineAward[]
|
||
invoices POInvoice[]
|
||
paymentSchedule POPaymentSchedule?
|
||
paymentRequests PaymentRequest[] @relation("POPaymentRequests")
|
||
sourcePurchaseRequirements PurchaseRequirement[] @relation("PRtoPO")
|
||
supplierDeliveryNotes SupplierDeliveryNote[] @relation("PODeliveryNotes")
|
||
|
||
@@index([status])
|
||
@@index([supplierId])
|
||
@@index([clientOrderId])
|
||
@@index([tenderId])
|
||
@@index([createdById])
|
||
@@index([expectedDeliveryDate])
|
||
@@index([archived])
|
||
@@index([expenseCodeId])
|
||
@@index([isIndirect])
|
||
@@index([supplierContractId])
|
||
@@map("purchase_orders")
|
||
}
|
||
|
||
model PurchaseOrderLine {
|
||
id Int @id @default(autoincrement())
|
||
purchaseOrderId Int @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
|
||
description String
|
||
material String
|
||
quantity Decimal @db.Decimal(12, 2)
|
||
unit String @default("шт")
|
||
estimatedPrice Decimal? @map("estimated_price") @db.Decimal(12, 2)
|
||
finalPrice Decimal? @map("final_price") @db.Decimal(12, 2)
|
||
sourceEstimateLineId Int? @map("source_estimate_line_id")
|
||
purchaseRequirementId Int? @map("purchase_requirement_id")
|
||
purchaseRequirement PurchaseRequirement? @relation("POLineToPR", fields: [purchaseRequirementId], references: [id])
|
||
consumedQuantity Decimal? @map("consumed_quantity") @db.Decimal(12, 2)
|
||
receivedQuantity Decimal @default(0) @map("received_quantity") @db.Decimal(12, 2)
|
||
receivedAt DateTime? @map("received_at")
|
||
lotLines PurchaseLotLine[]
|
||
receptions PurchaseLineReception[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([purchaseOrderId])
|
||
@@index([purchaseRequirementId])
|
||
@@map("purchase_order_lines")
|
||
}
|
||
|
||
// CDC §7.1 — Suivi coûts par commande
|
||
model FinancialTracking {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @unique @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
budgetServices Decimal @default(0) @map("budget_services") @db.Decimal(12, 2)
|
||
budgetMaterials Decimal @default(0) @map("budget_materials") @db.Decimal(12, 2)
|
||
budgetLabor Decimal @default(0) @map("budget_labor") @db.Decimal(12, 2)
|
||
budgetSupply Decimal @default(0) @map("budget_supply") @db.Decimal(12, 2)
|
||
committedServices Decimal @default(0) @map("committed_services") @db.Decimal(12, 2)
|
||
committedMaterials Decimal @default(0) @map("committed_materials") @db.Decimal(12, 2)
|
||
committedLabor Decimal @default(0) @map("committed_labor") @db.Decimal(12, 2)
|
||
committedSupply Decimal @default(0) @map("committed_supply") @db.Decimal(12, 2)
|
||
actualServices Decimal @default(0) @map("actual_services") @db.Decimal(12, 2)
|
||
actualMaterials Decimal @default(0) @map("actual_materials") @db.Decimal(12, 2)
|
||
actualLabor Decimal @default(0) @map("actual_labor") @db.Decimal(12, 2)
|
||
actualSupply Decimal @default(0) @map("actual_supply") @db.Decimal(12, 2)
|
||
alertLevel AlertLevel @default(NONE) @map("alert_level")
|
||
appliedRevisionIds Int[] @default([]) @map("applied_revision_ids")
|
||
lastRecalculatedAt DateTime? @map("last_recalculated_at")
|
||
notes String?
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@map("financial_trackings")
|
||
}
|
||
|
||
// CDC §7.2 — Trésorerie
|
||
model CashflowEntry {
|
||
id Int @id @default(autoincrement())
|
||
date DateTime
|
||
type CashflowType
|
||
category String
|
||
description String
|
||
amount Decimal @db.Decimal(14, 2)
|
||
orderId Int? @map("order_id")
|
||
order Order? @relation("OrderCashflow", fields: [orderId], references: [id])
|
||
supplierId Int? @map("supplier_id")
|
||
supplier Supplier? @relation("SupplierCashflow", fields: [supplierId], references: [id])
|
||
clientId Int? @map("client_id")
|
||
client Client? @relation("ClientCashflow", fields: [clientId], references: [id])
|
||
isActual Boolean @default(true) @map("is_actual")
|
||
source CashflowSource @default(ERP)
|
||
status CashflowStatus @default(PLANNED)
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
paymentRequestId Int? @map("payment_request_id")
|
||
recurringPaymentId Int? @map("recurring_payment_id")
|
||
bankAccountId String? @map("bank_account_id")
|
||
expenseCodeId Int? @map("expense_code_id")
|
||
expenseCode ExpenseCode? @relation("CFExpenseCode", fields: [expenseCodeId], references: [id])
|
||
notes String?
|
||
createdById String? @map("created_by_id")
|
||
onecGuid String? @unique @map("onec_guid")
|
||
onecSyncedAt DateTime? @map("onec_synced_at")
|
||
counterparty String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([date])
|
||
@@index([type])
|
||
@@index([orderId])
|
||
@@index([isActual])
|
||
@@index([status])
|
||
@@index([bankAccountId])
|
||
@@index([category])
|
||
@@map("cashflow_entries")
|
||
}
|
||
|
||
// CDC §7.2 — Saisie manuelle temporaire 1С (ДЗ, КЗ, avances)
|
||
model ManualEntry1C {
|
||
id Int @id @default(autoincrement())
|
||
type String // DZ, KZ, ADVANCE_RECEIVED
|
||
counterparty String
|
||
description String
|
||
amount Decimal @db.Decimal(14, 2)
|
||
dueDate DateTime? @map("due_date")
|
||
isActive Boolean @default(true) @map("is_active")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([type])
|
||
@@index([isActive])
|
||
@@map("manual_entries_1c")
|
||
}
|
||
|
||
// CDC §6.5 — Table de conversion aciers
|
||
model SteelReference {
|
||
id Int @id @default(autoincrement())
|
||
profileType String @map("profile_type")
|
||
section String
|
||
weightPerMeter Decimal @map("weight_per_meter") @db.Decimal(10, 4)
|
||
|
||
@@unique([profileType, section])
|
||
@@index([profileType])
|
||
@@map("steel_references")
|
||
}
|
||
|
||
// CDC §9 — Journal d'audit
|
||
model AuditLog {
|
||
id Int @id @default(autoincrement())
|
||
userId String? @map("user_id")
|
||
user User? @relation(fields: [userId], references: [id])
|
||
action String
|
||
entityType String @map("entity_type")
|
||
entityId String @map("entity_id")
|
||
details Json?
|
||
ipAddress String? @map("ip_address")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([userId])
|
||
@@index([entityType, entityId])
|
||
@@index([createdAt])
|
||
@@map("audit_logs")
|
||
}
|
||
|
||
// CDC §5.2 révisé — Фотофиксация commandes
|
||
model OrderPhoto {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
photoType PhotoType @map("photo_type")
|
||
filePath String @map("file_path")
|
||
fileSize Int @map("file_size")
|
||
mimeType String @map("mime_type")
|
||
description String?
|
||
takenById String? @map("taken_by_id")
|
||
takenBy User? @relation(fields: [takenById], references: [id])
|
||
isRequired Boolean @default(false) @map("is_required")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
takenAt DateTime @default(now()) @map("taken_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([orderId])
|
||
@@index([photoType])
|
||
@@map("order_photos")
|
||
}
|
||
|
||
// CDC §7.2 révisé — Банковские выписки
|
||
model BankStatement {
|
||
id Int @id @default(autoincrement())
|
||
statementDate DateTime @map("statement_date")
|
||
bankAccountNumber String @map("bank_account_number")
|
||
balanceStart Decimal @map("balance_start") @db.Decimal(14, 2)
|
||
balanceEnd Decimal @map("balance_end") @db.Decimal(14, 2)
|
||
sourceFilePath String? @map("source_file_path")
|
||
source BankStatementSource @default(IMPORT_1C)
|
||
verificationStatus VerificationStatus @default(PENDING) @map("verification_status")
|
||
errorNotes String? @map("error_notes")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([statementDate])
|
||
@@index([verificationStatus])
|
||
@@map("bank_statements")
|
||
}
|
||
|
||
// 1C OData sync log
|
||
model OnecSyncLog {
|
||
id Int @id @default(autoincrement())
|
||
entity String
|
||
status String @default("RUNNING")
|
||
startedAt DateTime @default(now()) @map("started_at")
|
||
completedAt DateTime? @map("completed_at")
|
||
created Int @default(0)
|
||
updated Int @default(0)
|
||
skipped Int @default(0)
|
||
errors Int @default(0)
|
||
errorDetails String? @map("error_details")
|
||
totalFetched Int @default(0) @map("total_fetched")
|
||
|
||
@@index([entity, startedAt])
|
||
@@map("onec_sync_log")
|
||
}
|
||
|
||
// 1C OData — bank accounts reference
|
||
model OnecBankAccount {
|
||
id Int @id @default(autoincrement())
|
||
onecGuid String @unique @map("onec_guid")
|
||
name String
|
||
shortName String @map("short_name")
|
||
number String?
|
||
|
||
@@map("onec_bank_accounts")
|
||
}
|
||
|
||
// Mapping MaterialCategory → SupplierTag names (configurable)
|
||
model CategoryTagMapping {
|
||
id Int @id @default(autoincrement())
|
||
category String @unique
|
||
tagNames String[] @map("tag_names")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@map("category_tag_mappings")
|
||
}
|
||
|
||
// 1C OData — cashflow categories (статьи ДДС)
|
||
model OnecCashflowCategory {
|
||
id Int @id @default(autoincrement())
|
||
onecGuid String @unique @map("onec_guid")
|
||
name String
|
||
erpCategory String? @map("erp_category")
|
||
|
||
@@map("onec_cashflow_categories")
|
||
}
|
||
|
||
// SPEC 24F — Revision smeta post-lancement
|
||
model SmetaRevision {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
oldSmetaId Int @map("old_smeta_id")
|
||
oldSmeta Smeta @relation("OldSmeta", fields: [oldSmetaId], references: [id])
|
||
newSmetaId Int @map("new_smeta_id")
|
||
newSmeta Smeta @relation("NewSmeta", fields: [newSmetaId], references: [id])
|
||
|
||
diffReport Json @map("diff_report")
|
||
status RevisionApprovalStatus @default(REV_PENDING)
|
||
decisions Json?
|
||
|
||
approvedById String? @map("approved_by_id")
|
||
approvedBy User? @relation("SmetaRevisionApprover", fields: [approvedById], references: [id])
|
||
approvedAt DateTime? @map("approved_at")
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("SmetaRevisionCreator", fields: [createdById], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
additionalCosts AdditionalCost[]
|
||
|
||
@@index([orderId])
|
||
@@index([oldSmetaId])
|
||
@@index([newSmetaId])
|
||
@@map("smeta_revisions")
|
||
}
|
||
|
||
// SPEC 24F — Surcoûts liés aux revisions smeta
|
||
model AdditionalCost {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
revisionId Int? @map("revision_id")
|
||
revision SmetaRevision? @relation(fields: [revisionId], references: [id])
|
||
|
||
type AdditionalCostType
|
||
description String
|
||
amount Decimal @db.Decimal(12, 2)
|
||
currency String @default("RUB")
|
||
|
||
relatedPRId Int? @map("related_pr_id")
|
||
relatedPOId Int? @map("related_po_id")
|
||
|
||
status AdditionalCostStatus @default(PENDING)
|
||
approvedById String? @map("approved_by_id")
|
||
approvedBy User? @relation("AdditionalCostApprover", fields: [approvedById], references: [id])
|
||
approvedAt DateTime? @map("approved_at")
|
||
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("AdditionalCostCreator", fields: [createdById], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([orderId])
|
||
@@index([revisionId])
|
||
@@map("additional_costs")
|
||
}
|
||
|
||
// SPEC 27C — Budget consolidé + double validation
|
||
model BudgetValidation {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @unique @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
totalEstimated Decimal @map("total_estimated") @db.Decimal(12, 2)
|
||
totalAwarded Decimal @map("total_awarded") @db.Decimal(12, 2)
|
||
totalPO Decimal @map("total_po") @db.Decimal(12, 2)
|
||
variance Decimal @db.Decimal(12, 2)
|
||
variancePercent Decimal @map("variance_percent") @db.Decimal(10, 2)
|
||
status BudgetValidationStatus @default(PENDING)
|
||
finValidatedBy String? @map("fin_validated_by")
|
||
finValidator User? @relation("BudgetFinValidator", fields: [finValidatedBy], references: [id])
|
||
finValidatedAt DateTime? @map("fin_validated_at")
|
||
finComment String? @map("fin_comment")
|
||
techValidatedBy String? @map("tech_validated_by")
|
||
techValidator User? @relation("BudgetTechValidator", fields: [techValidatedBy], references: [id])
|
||
techValidatedAt DateTime? @map("tech_validated_at")
|
||
techComment String? @map("tech_comment")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([status])
|
||
@@map("budget_validations")
|
||
}
|
||
|
||
enum BudgetValidationStatus {
|
||
PENDING
|
||
FIN_APPROVED
|
||
TECH_APPROVED
|
||
FULLY_APPROVED
|
||
REJECTED
|
||
}
|
||
|
||
// ─── POInvoice (facture fournisseur liée à un PO) ─────────────────
|
||
model POInvoice {
|
||
id Int @id @default(autoincrement())
|
||
purchaseOrderId Int @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
|
||
lotId Int? @map("lot_id")
|
||
lot PurchaseLot? @relation(fields: [lotId], references: [id])
|
||
invoiceNumber String? @map("invoice_number")
|
||
amount Decimal? @db.Decimal(12, 2)
|
||
status InvoiceStatus @default(PENDING_VALIDATION)
|
||
filePath String @map("file_path")
|
||
fileName String @map("file_name")
|
||
dueDate DateTime? @map("due_date")
|
||
paidAt DateTime? @map("paid_at")
|
||
paidAmount Decimal? @map("paid_amount") @db.Decimal(12, 2)
|
||
paymentRequestId Int? @unique @map("payment_request_id")
|
||
paymentRequest PaymentRequest? @relation(fields: [paymentRequestId], references: [id])
|
||
uploadedById String @map("uploaded_by_id")
|
||
uploadedBy User @relation("POInvoiceUploadedBy", fields: [uploadedById], references: [id])
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([purchaseOrderId])
|
||
@@index([lotId])
|
||
@@index([status])
|
||
@@map("po_invoices")
|
||
}
|
||
|
||
// ─── POPaymentSchedule (conditions de paiement d'un PO) ───────────
|
||
model POPaymentSchedule {
|
||
id Int @id @default(autoincrement())
|
||
purchaseOrderId Int @unique @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder @relation(fields: [purchaseOrderId], references: [id], onDelete: Cascade)
|
||
paymentType PaymentType @map("payment_type")
|
||
postDeliveryDays Int? @map("post_delivery_days")
|
||
postpayMode PostpayMode @default(SIMPLE) @map("postpay_mode")
|
||
source POPaymentScheduleSource @default(MANUAL)
|
||
sourceContractId Int? @map("source_contract_id")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
installments POInstallment[]
|
||
|
||
@@map("po_payment_schedules")
|
||
}
|
||
|
||
// ─── POInstallment (tranches de paiement) ─────────────────────────
|
||
model POInstallment {
|
||
id Int @id @default(autoincrement())
|
||
scheduleId Int @map("schedule_id")
|
||
schedule POPaymentSchedule @relation(fields: [scheduleId], references: [id], onDelete: Cascade)
|
||
percentage Decimal @db.Decimal(5, 2)
|
||
amount Decimal? @db.Decimal(12, 2)
|
||
dueDate DateTime? @map("due_date")
|
||
label String?
|
||
paidAt DateTime? @map("paid_at")
|
||
paidAmount Decimal? @map("paid_amount") @db.Decimal(12, 2)
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
isPostDelivery Boolean @default(false) @map("is_post_delivery")
|
||
paymentRequestId Int? @unique @map("payment_request_id")
|
||
paymentRequest PaymentRequest? @relation(fields: [paymentRequestId], references: [id])
|
||
|
||
@@index([scheduleId])
|
||
@@map("po_installments")
|
||
}
|
||
|
||
model UserNotificationPreference {
|
||
id Int @id @default(autoincrement())
|
||
userId String @map("user_id")
|
||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||
category String // PAYMENT_DUE, PR_APPROVE, PR_CONFIRM, TENDER_OFFER, SMETA_REVISION, PO_DELIVERY, LOT_ORDER_DUE
|
||
inApp Boolean @default(true) @map("in_app")
|
||
email Boolean @default(false)
|
||
telegram Boolean @default(false)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([userId, category])
|
||
@@map("user_notification_preferences")
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// CASHFLOW ENTRÉES CLIENTS (S42C)
|
||
// ══════════════════════════════════════════════════════════════════
|
||
|
||
model PaymentTemplate {
|
||
id Int @id @default(autoincrement())
|
||
name String
|
||
description String?
|
||
isActive Boolean @default(true)
|
||
terms PaymentTemplateTerm[]
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
|
||
@@map("payment_templates")
|
||
}
|
||
|
||
model PaymentTemplateTerm {
|
||
id Int @id @default(autoincrement())
|
||
templateId Int @map("template_id")
|
||
template PaymentTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||
percent Decimal @db.Decimal(5, 2)
|
||
trigger PaymentTrigger
|
||
offsetDays Int @default(0) @map("offset_days")
|
||
label String
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
|
||
@@map("payment_template_terms")
|
||
}
|
||
|
||
model ClientInvoice {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id])
|
||
invoiceNumber String @unique @map("invoice_number")
|
||
invoiceDate DateTime @map("invoice_date") @db.Date
|
||
amount Decimal @db.Decimal(14, 2)
|
||
status ClientInvoiceStatus @default(DRAFT)
|
||
notes String?
|
||
installments ClientInstallment[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
documents Document[]
|
||
|
||
@@index([orderId])
|
||
@@map("client_invoices")
|
||
}
|
||
|
||
model PlannedDeliveryLot {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id])
|
||
label String @db.VarChar(120)
|
||
plannedDate DateTime @map("planned_date") @db.Date
|
||
quantity Decimal @default(1) @db.Decimal(14, 4)
|
||
amountSnapshot Decimal? @map("amount_snapshot") @db.Decimal(14, 2)
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
status PlannedDeliveryLotStatus @default(PLANNED)
|
||
notes String?
|
||
deliveryLot DeliveryLot? @relation("PlannedToActual")
|
||
forecasts ForecastInstallment[] @relation("PlannedLotForecasts")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([orderId])
|
||
@@map("planned_delivery_lots")
|
||
}
|
||
|
||
model DeliveryLot {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id])
|
||
updNumber String @unique @map("upd_number")
|
||
updDate DateTime @map("upd_date") @db.Date
|
||
amount Decimal @db.Decimal(14, 2)
|
||
status DeliveryLotStatus @default(DRAFT)
|
||
notes String?
|
||
signedByClientAt DateTime? @map("signed_by_client_at")
|
||
plannedLotId Int? @unique @map("planned_lot_id")
|
||
plannedLot PlannedDeliveryLot? @relation("PlannedToActual", fields: [plannedLotId], references: [id], onDelete: SetNull)
|
||
installments ClientInstallment[] @relation("DeliveryLotInstallments")
|
||
documents Document[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([orderId])
|
||
@@map("delivery_lots")
|
||
}
|
||
|
||
model ClientInstallment {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id])
|
||
invoiceId Int? @map("invoice_id")
|
||
invoice ClientInvoice? @relation(fields: [invoiceId], references: [id])
|
||
shipmentId Int? @map("shipment_id")
|
||
shipment DeliveryLot? @relation("DeliveryLotInstallments", fields: [shipmentId], references: [id])
|
||
contractTermId Int? @map("contract_term_id")
|
||
contractTerm ContractPaymentTerm? @relation(fields: [contractTermId], references: [id], onDelete: SetNull)
|
||
forecastLink ForecastInstallment? @relation("ForecastLink")
|
||
amount Decimal @db.Decimal(14, 2)
|
||
dueDate DateTime @map("due_date") @db.Date
|
||
trigger PaymentTrigger
|
||
label String
|
||
status ClientInstallmentStatus @default(PENDING)
|
||
notes String?
|
||
payments ClientPaymentReceived[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([orderId])
|
||
@@index([invoiceId])
|
||
@@index([shipmentId])
|
||
@@index([contractTermId])
|
||
@@index([dueDate])
|
||
@@map("client_installments")
|
||
}
|
||
|
||
model ClientPaymentReceived {
|
||
id Int @id @default(autoincrement())
|
||
installmentId Int @map("installment_id")
|
||
installment ClientInstallment @relation(fields: [installmentId], references: [id])
|
||
amount Decimal @db.Decimal(14, 2)
|
||
receivedAt DateTime @map("received_at") @db.Date
|
||
bankReference String? @map("bank_reference")
|
||
onecId String? @map("onec_id")
|
||
notes String?
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([installmentId])
|
||
@@index([onecId])
|
||
@@map("client_payments_received")
|
||
}
|
||
|
||
model ForecastInstallment {
|
||
id Int @id @default(autoincrement())
|
||
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
|
||
contractTermId Int? @map("contract_term_id")
|
||
contractTerm ContractPaymentTerm? @relation(fields: [contractTermId], references: [id], onDelete: SetNull)
|
||
|
||
expectedDate DateTime @map("expected_date") @db.Date
|
||
expectedAmount Decimal @map("expected_amount") @db.Decimal(14, 2)
|
||
realizedAmount Decimal @default(0) @map("realized_amount") @db.Decimal(14, 2)
|
||
|
||
status ForecastStatus @default(EXTRAPOLATED)
|
||
sourceType ForecastSourceType @default(AUTO_GENERATED) @map("source_type")
|
||
triggerPhase ForecastTriggerPhase @default(ORDER_CREATED) @map("trigger_phase")
|
||
|
||
wasManuallyEdited Boolean @default(false) @map("was_manually_edited")
|
||
|
||
linkedInstallmentId Int? @unique @map("linked_installment_id")
|
||
linkedInstallment ClientInstallment? @relation("ForecastLink", fields: [linkedInstallmentId], references: [id], onDelete: SetNull)
|
||
|
||
parentForecastId Int? @map("parent_forecast_id")
|
||
parentForecast ForecastInstallment? @relation("ForecastResidualChain", fields: [parentForecastId], references: [id], onDelete: SetNull)
|
||
childForecasts ForecastInstallment[] @relation("ForecastResidualChain")
|
||
|
||
rebalancedFromLinkId Int? @map("rebalanced_from_link_id")
|
||
rebalancedFromLink ForecastInstallment? @relation("RebalanceChain", fields: [rebalancedFromLinkId], references: [id])
|
||
rebalancedTargets ForecastInstallment[] @relation("RebalanceChain")
|
||
rebalanceDelta Decimal? @map("rebalance_delta") @db.Decimal(14, 2)
|
||
|
||
rebalanceLogsAsTarget ForecastRebalanceLog[] @relation("RebalanceLogTarget")
|
||
rebalanceLogsAsSource ForecastRebalanceLog[] @relation("RebalanceLogSource")
|
||
|
||
plannedLotId Int? @map("planned_lot_id")
|
||
plannedLot PlannedDeliveryLot? @relation("PlannedLotForecasts", fields: [plannedLotId], references: [id], onDelete: SetNull)
|
||
|
||
label String?
|
||
notes String?
|
||
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([orderId])
|
||
@@index([expectedDate])
|
||
@@index([status])
|
||
@@index([rebalancedFromLinkId])
|
||
@@index([plannedLotId])
|
||
@@map("forecast_installments")
|
||
}
|
||
|
||
model ClientContract {
|
||
id Int @id @default(autoincrement())
|
||
clientId Int @map("client_id")
|
||
client Client @relation(fields: [clientId], references: [id])
|
||
contractNumber String @map("contract_number")
|
||
contractDate DateTime @map("contract_date") @db.Date
|
||
startDate DateTime @map("start_date") @db.Date
|
||
endDate DateTime? @map("end_date") @db.Date
|
||
status ContractStatus @default(DRAFT)
|
||
notes String?
|
||
terms ContractPaymentTerm[]
|
||
orders Order[] @relation("OrderClientContract")
|
||
documents Document[]
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([clientId, contractNumber])
|
||
@@index([clientId])
|
||
@@index([status])
|
||
@@map("client_contracts")
|
||
}
|
||
|
||
model ContractPaymentTerm {
|
||
id Int @id @default(autoincrement())
|
||
contractId Int @map("contract_id")
|
||
contract ClientContract @relation(fields: [contractId], references: [id], onDelete: Cascade)
|
||
percent Decimal @db.Decimal(5, 2)
|
||
trigger PaymentTrigger
|
||
offsetDays Int @default(0) @map("offset_days")
|
||
label String
|
||
sortOrder Int @default(0) @map("sort_order")
|
||
forecasts ForecastInstallment[]
|
||
installments ClientInstallment[]
|
||
|
||
@@index([contractId])
|
||
@@map("contract_payment_terms")
|
||
}
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// S42K — Configuration du tracking documents sans fichier
|
||
// ══════════════════════════════════════════════════════════════════
|
||
|
||
model FileTrackingConfig {
|
||
id String @id @default("singleton")
|
||
clientContractThresholdDays Int @default(15) @map("client_contract_threshold_days")
|
||
deliveryLotThresholdDays Int @default(10) @map("delivery_lot_threshold_days")
|
||
clientInvoiceThresholdDays Int @default(3) @map("client_invoice_threshold_days")
|
||
purchaseOrderThresholdDays Int @default(7) @map("purchase_order_threshold_days")
|
||
supplierContractThresholdDays Int @default(15) @map("supplier_contract_threshold_days")
|
||
escalationThresholdDays Int @default(30) @map("escalation_threshold_days")
|
||
reminderIntervalDays Int @default(7) @map("reminder_interval_days")
|
||
enabled Boolean @default(true)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
updatedById String? @map("updated_by_id")
|
||
updatedBy User? @relation(fields: [updatedById], references: [id])
|
||
|
||
@@map("file_tracking_configs")
|
||
}
|
||
|
||
model ForecastRebalanceLog {
|
||
id String @id @default(uuid())
|
||
targetId Int @map("target_id")
|
||
target ForecastInstallment @relation("RebalanceLogTarget", fields: [targetId], references: [id])
|
||
sourceId Int @map("source_id")
|
||
source ForecastInstallment @relation("RebalanceLogSource", fields: [sourceId], references: [id])
|
||
delta Decimal @db.Decimal(14, 2)
|
||
appliedAt DateTime @default(now()) @map("applied_at")
|
||
reversedAt DateTime? @map("reversed_at")
|
||
userId String @map("user_id")
|
||
user User @relation(fields: [userId], references: [id])
|
||
|
||
@@index([targetId, reversedAt])
|
||
@@index([sourceId, reversedAt])
|
||
@@map("forecast_rebalance_logs")
|
||
}
|
||
|
||
// S42-PLANNING-1 — Réceptions au niveau position PO
|
||
model PurchaseLineReception {
|
||
id Int @id @default(autoincrement())
|
||
poLineId Int @map("po_line_id")
|
||
poLine PurchaseOrderLine @relation(fields: [poLineId], references: [id], onDelete: Cascade)
|
||
lotId Int? @map("lot_id")
|
||
lot PurchaseLot? @relation(fields: [lotId], references: [id])
|
||
receivedQty Decimal @map("received_qty") @db.Decimal(12, 2)
|
||
receivedAt DateTime @map("received_at")
|
||
transportDocNum String? @map("transport_doc_num")
|
||
documentMissing Boolean @default(false) @map("document_missing")
|
||
qualityNotes String? @map("quality_notes")
|
||
status ReceptionStatus @default(DRAFT)
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("ReceptionCreator", fields: [createdById], references: [id])
|
||
verifiedById String? @map("verified_by_id")
|
||
verifiedBy User? @relation("ReceptionVerifier", fields: [verifiedById], references: [id])
|
||
verifiedAt DateTime? @map("verified_at")
|
||
accountedById String? @map("accounted_by_id")
|
||
accountedBy User? @relation("ReceptionAccountant", fields: [accountedById], references: [id])
|
||
accountedAt DateTime? @map("accounted_at")
|
||
discrepancyNotes String? @map("discrepancy_notes")
|
||
supplierDeliveryNoteId Int? @map("supplier_delivery_note_id")
|
||
supplierDeliveryNote SupplierDeliveryNote? @relation("SDNReceptions", fields: [supplierDeliveryNoteId], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@index([poLineId])
|
||
@@index([lotId])
|
||
@@index([status])
|
||
@@index([documentMissing])
|
||
@@index([supplierDeliveryNoteId])
|
||
@@map("purchase_line_receptions")
|
||
}
|
||
|
||
// S42-PLANNING-1 — Notes overlay Order × MaterialCategory
|
||
model OrderCategoryNote {
|
||
id Int @id @default(autoincrement())
|
||
orderId Int @map("order_id")
|
||
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
||
category MaterialCategory
|
||
note String @db.VarChar(200)
|
||
createdById String @map("created_by_id")
|
||
createdBy User @relation("OrderCategoryNoteCreator", fields: [createdById], references: [id])
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([orderId, category])
|
||
@@index([orderId])
|
||
@@map("order_category_notes")
|
||
}
|
||
|
||
enum HolidayType {
|
||
FIXED
|
||
WORKING_SATURDAY
|
||
}
|
||
|
||
model PublicHoliday {
|
||
id Int @id @default(autoincrement())
|
||
date DateTime @unique @db.Date
|
||
name String
|
||
holidayType HolidayType @default(FIXED) @map("holiday_type")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@map("public_holidays")
|
||
}
|
||
|
||
enum SupplierDeliveryNoteStatus {
|
||
DRAFT
|
||
SIGNED
|
||
CANCELLED
|
||
}
|
||
|
||
enum PostpayMode {
|
||
SIMPLE
|
||
PER_DELIVERY
|
||
}
|
||
|
||
enum POPaymentScheduleSource {
|
||
MANUAL
|
||
AUTO_FROM_CONTRACT
|
||
AUTO_FROM_TLT
|
||
}
|
||
|
||
model SupplierDeliveryNote {
|
||
id Int @id @default(autoincrement())
|
||
number String
|
||
signedDate DateTime @map("signed_date") @db.Date
|
||
supplierId Int @map("supplier_id")
|
||
supplier Supplier @relation("SupplierDNs", fields: [supplierId], references: [id])
|
||
purchaseOrderId Int? @map("purchase_order_id")
|
||
purchaseOrder PurchaseOrder? @relation("PODeliveryNotes", fields: [purchaseOrderId], references: [id])
|
||
status SupplierDeliveryNoteStatus @default(DRAFT)
|
||
notes String?
|
||
receptions PurchaseLineReception[] @relation("SDNReceptions")
|
||
documents Document[] @relation("SDNDocuments")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@unique([supplierId, number])
|
||
@@index([purchaseOrderId])
|
||
@@index([status])
|
||
@@map("supplier_delivery_notes")
|
||
}
|
||
|
||
// SPEC HELP-MODULE-P0 — Articles d'aide intégrés
|
||
enum HelpCategory {
|
||
GLOSSARY
|
||
WORKFLOW
|
||
FAQ
|
||
MODULE_REF
|
||
INTRO
|
||
}
|
||
|
||
model HelpArticle {
|
||
id Int @id @default(autoincrement())
|
||
slug String @unique
|
||
titleRu String @map("title_ru")
|
||
bodyMd String @db.Text @map("body_md")
|
||
category HelpCategory
|
||
tags String[] @default([])
|
||
isPublished Boolean @default(true) @map("is_published")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
createdById String? @map("created_by_id")
|
||
createdBy User? @relation("HelpArticleCreatedBy", fields: [createdById], references: [id])
|
||
|
||
@@index([category, isPublished])
|
||
@@index([isPublished])
|
||
@@map("help_articles")
|
||
}
|