**Dành cho AI Agent & Lập trình** Dưới đây là **file Prisma Schema đầy đủ, thống nhất và chi tiết nhất** dựa trên tất cả các yêu cầu bạn đã nêu từ đầu đến giờ (bao gồm file Excel, logic chuyển nhượng, tình trạng hạ tầng nested, PaymentSchedule với template, dư/thiếu tiền, v.v.). prisma ``` // ============================================= // PRISMA SCHEMA - HỆ THỐNG QUẢN LÝ BẤT ĐỘNG SẢN // Phiên bản: 2.3 // Ngày: 18/04/2026 // Mục đích: Hoàn chỉnh, self-host, hỗ trợ nhiều loại sản phẩm, // lịch sử chuyển nhượng, phụ lục kế thừa, // tình trạng hạ tầng nested, và dòng tiền chi tiết. // ============================================= datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } // ============================================= // 1. PROJECT (Khu / Dự án) // ============================================= model Project { id String @id @default(uuid()) code String @unique // ví dụ: STH03 name String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt products Product[] templates PaymentTemplate[] } // ============================================= // 2. PRODUCT (Sản phẩm - Đất nền, Căn hộ...) // ============================================= model Product { id String @id @default(uuid()) projectId String productType ProductType // === TRƯỜNG CHUNG TỪ FILE sanpham.xlsx === code String @unique // Khu + Lô (STH03.01) area Decimal pricePerUnit Decimal totalPrice Decimal qsddValue Decimal foundationTempValue Decimal contractTempValue Decimal adjacentRoad String? frontageCount Int? maxFloors Int? buildingDensity Decimal? constructionStatus String? // === TÌNH TRẠNG HẠ TẦNG (NESTED JSONB) === infrastructureRawText String? // Giữ nguyên text gốc để backup infrastructureStatus Json // Cấu trúc nested (hỗ trợ child-of-child) // === TRẠNG THÁI SỔ ĐỎ === redBookStatus String @default("Chưa có dữ liệu") // === TRƯỜNG LINH HOẠT CHO SẢN PHẨM MỚI === customData Json // Block, tầng, hướng, sổ hồng riêng, giấy phép XD... createdAt DateTime @default(now()) updatedAt DateTime @updatedAt project Project @relation(fields: [projectId], references: [id]) contracts Contract[] settlements Settlement[] } // ============================================= // ENUM LOẠI SẢN PHẨM // ============================================= enum ProductType { LAND APARTMENT SHOPHOUSE OFFICE CONDOTEL VILLA // Thêm loại mới ở đây } // ============================================= // 3. CONTRACT & CHUYỂN NHƯỢNG (Giữ nguyên logic Excel) // ============================================= model Contract { id String @id @default(uuid()) productId String transferOrder Int // 0 = KH HIỆN TẠI, 1 = HĐ GỐC, 2+ = VBCN contractType String // HĐGV, HĐMB, VBCN contractNumber String signingDate DateTime totalValue Decimal paidAmount Decimal remainingAmount Decimal metadata Json? product Product @relation(fields: [productId], references: [id]) customers ContractCustomer[] appendices Appendix[] payments Payment[] schedule PaymentSchedule? fines PaymentFine[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Customer { id String @id @default(uuid()) cmndCccd String @unique fullName String phone String email String? address Json? dob DateTime? contracts ContractCustomer[] } model ContractCustomer { id String @id @default(uuid()) contractId String customerId String role String // "CHỦ SH 1", "CHỦ SH 2", "CHỦ SH 3" transferOrder Int contract Contract @relation(fields: [contractId], references: [id]) customer Customer @relation(fields: [customerId], references: [id]) } // ============================================= // 4. APPENDIX (Phụ lục) // ============================================= model Appendix { id String @id @default(uuid()) contractId String productId String type String applyFromOrder Int // Kế thừa từ CN # signingDate DateTime customData Json? contract Contract @relation(fields: [contractId], references: [id]) } // ============================================= // 5. SETTLEMENT (Quyết toán & Sổ đỏ) // ============================================= model Settlement { id String @id @default(uuid()) productId String type String // MÓNG, THÂN, CP THI CÔNG tempValue Decimal finalValue Decimal difference Decimal redBookStatus String issueDate DateTime? product Product @relation(fields: [productId], references: [id]) } // ============================================= // 6. PAYMENT MODULE - DÒNG TIỀN (THEO YÊU CẦU) // ============================================= model PaymentTemplate { id String @id @default(uuid()) projectId String name String // "Thanh toán chuẩn 30-30-40", "Trả một lần" isDefault Boolean @default(false) project Project @relation(fields: [projectId], references: [id]) items PaymentScheduleItem[] schedules PaymentSchedule[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PaymentScheduleItem { id String @id @default(uuid()) templateId String? scheduleId String? installmentNo Int amount Decimal? percentage Decimal? // Ưu tiên % nếu có // Hai cách tính ngày đến hạn daysAfterSigning Int? // Số ngày sau ngày ký hợp đồng dueDate DateTime? // Ngày chính xác type PaymentType template PaymentTemplate? @relation(fields: [templateId], references: [id]) schedule PaymentSchedule? @relation(fields: [scheduleId], references: [id]) payments Payment[] createdAt DateTime @default(now()) } model PaymentSchedule { id String @id @default(uuid()) contractId String templateId String // Template đã chọn khi tạo hợp đồng contract Contract @relation(fields: [contractId], references: [id]) template PaymentTemplate @relation(fields: [templateId], references: [id]) items PaymentScheduleItem[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Payment { id String @id @default(uuid()) contractId String scheduleItemId String? amount Decimal paidDate DateTime receiptNumber String? method String metadata Json? contract Contract @relation(fields: [contractId], references: [id]) scheduleItem PaymentScheduleItem? @relation(fields: [scheduleItemId], references: [id]) createdAt DateTime @default(now()) } model PaymentFine { id String @id @default(uuid()) contractId String amount Decimal reason String dueDate DateTime paidDate DateTime? contract Contract @relation(fields: [contractId], references: [id]) } // ============================================= // ENUMS // ============================================= enum PaymentType { QSDD MONG THAN CHI_PHI_TC CK PHAT OTHER } ``` --- **Hướng dẫn sử dụng cho AI Agent / Lập trình:** - **Model chính**: Product, Contract, PaymentTemplate, PaymentScheduleItem, PaymentSchedule, Payment. - **Logic tạo hợp đồng**: Khi tạo Contract → clone PaymentTemplate (mặc định hoặc do nhân viên chọn) thành PaymentSchedule + các PaymentScheduleItem. - **Dư/thiếu tiền**: Xử lý ở tầng application logic (khi tạo Payment). - **Tình trạng hạ tầng**: Sử dụng infrastructureStatus JSONB (nested). - **Dynamic fields**: Sử dụng customData JSONB.