**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.
