generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

// ========== 枚举 ==========

enum Plan {
  FREE
  PRO
  ENTERPRISE
}

enum Role {
  SUPER_ADMIN
  ADMIN
  HR
  VIEWER
}

enum EmployeeStatus {
  ACTIVE
  RESIGNED
  TERMINATED
}

enum FemaleWorkerType {
  CADRE     // 干部/管理岗
  WORKER    // 工人/操作岗
}

enum ContractType {
  FIXED
  UNFIXED
  UNSIGNED
  LABOR
  INTERNSHIP
  DISPATCH
  OUTSOURCING
  PARTTIME
}

enum SignMethod {
  PAPER
  ELECTRONIC
}

enum RiskType {
  CONTRACT
  SALARY
  TERMINATION
  MONTHLY
  ONBOARDING
  RETIREMENT
}

enum RiskLevel {
  HIGH
  MEDIUM
  LOW
}

enum PayrollBatchType {
  REGULAR      // 常规发薪
  TERMINATION  // 离职结算
  BONUS        // 年终奖/奖金
  SEVERANCE    // 补偿金按月发放（无社保，个税按政策处理）
}

enum PayrollBatchStatus {
  DRAFT     // 草稿（可编辑）
  ARCHIVED  // 归档（已发薪，锁定）
}

enum PayslipItemType {
  INPUT      // 手工输入项（计算依据）
  CALCULATED // 计算项（公式自动计算）
}

enum PayslipStatus {
  PENDING   // 待发布
  PUBLISHED // 已发布到员工端
}

enum RiskStatus {
  PENDING
  RESOLVED
  IGNORED
}

enum TerminationReason {
  NEGOTIATED
  FAULT
  NONFAULT
  LAYOFF
  EXPIRED
  RESIGNATION
}

enum RiskAssessment {
  SAFE
  WARNING
  DANGER
}

enum OnboardingStatus {
  PENDING
  APPROVED
  REJECTED
  CANCELLED
}

enum ContractConfirmStatus {
  UNCONFIRMED
  CONFIRMED
  EXPIRED
}

// ========== 核心表 ==========

model Organization {
  id           String   @id @default(cuid())
  name         String
  plan         Plan     @default(FREE)
  maxEmployees Int      @default(20)
  city         String?
  contactName  String?
  contactPhone String?
  payrollFrequency Int    @default(1)  // 每月发薪次数（1=一次一批）
  retirementReminderEnabled Boolean @default(false) // 退休提醒开关
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  users            User[]
  employees        Employee[]
  contracts        LaborContract[]
  overtimeRecords  OvertimeRecord[]
  terminations     TerminationRecord[]
  riskItems        RiskItem[]
  auditLogs        AuditLog[]
  payslips         Payslip[]
  payrollBatches   PayrollBatch[]
  payslipItems     PayslipItem[]
  salaryChangeRecords SalaryChangeRecord[]
  onboardingLinks  OnboardingLink[]
  confirmLinks     ContractConfirmLink[]
  aiConversations  AIConversation[]
  aiReviewRecords  AIReviewRecord[]
  socialInsuranceConfig SocialInsuranceConfig[]
  housingFundConfigs   HousingFundConfig[]
  socialInsRecords     EmployeeSocialInsRecord[]
  housingFundRecords   EmployeeHousingFundRecord[]
  departmentRecords    EmployeeDepartmentRecord[]
  notificationSetting  NotificationSetting?
  overtimeConfig       OvertimeConfig?
  notificationLogs     NotificationLog[]
  employeeAttachments  EmployeeAttachment[]
  disciplinaryRecords  DisciplinaryRecord[]
  attendanceRecords    AttendanceRecord[]
  trainingRecords      TrainingRecord[]
  performanceRecords   PerformanceRecord[]
  retirementPolicies   RetirementPolicy[]
  socialMonthlyProcesses SocialMonthlyProcess[]
  evidenceChains       EvidenceChain[]
  attendanceConfirmations AttendanceConfirmation[]
  policyDocuments      PolicyDocument[]
  policyReadRecords    PolicyReadRecord[]
  healthCheckReports   HealthCheckReport[]
  annualValueReports   AnnualValueReport[]
  specialDeductionRecords SpecialDeductionRecord[]
  shifts               Shift[]
  shiftAssignments     ShiftAssignment[]
  leaveRecords         LeaveRecord[]
  leaveRequests        LeaveRequest[]
  calendarEvents       CalendarEvent[]
  consultations        Consultation[]
  workProcesses        WorkProcess[]
  enterpriseTemplates  EnterpriseTemplate[]
  attendancePublishes  AttendancePublish[]
  specialStatuses      EmployeeSpecialStatus[]
  companyFiles         CompanyFile[]
  commercialInsPlans   CommercialInsurancePlan[]
  commercialInsEnrollments CommercialInsuranceEnrollment[]
  benefitPlans         EmployeeBenefitPlan[]
  benefitEnrollments   EmployeeBenefitEnrollment[]
  eSignRecords         ESignRecord[]
}

model User {
  id           String   @id @default(cuid())
  orgId        String?  // 平台管理员不绑定企业（null）
  org          Organization? @relation(fields: [orgId], references: [id], onDelete: Cascade)
  phone        String   @unique
  email        String?
  passwordHash String
  name         String
  role         Role     @default(ADMIN)
  disabled     Boolean  @default(false)
  createdAt    DateTime @default(now())
  lastLoginAt  DateTime?
}

// ========== 业务表 ==========

model Employee {
  id                String         @id @default(cuid())
  orgId             String
  org               Organization   @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name              String
  employeeNo        String?        // 工号
  department        String
  position          String?        // 岗位
  hireDate          DateTime
  monthlySalary     String         // AES-256 加密存储
  status            EmployeeStatus @default(ACTIVE)
  gender            String?
  phone             String?
  idCardNumber      String?        // AES-256 加密存储
  idCardHash        String?        // SHA-256 哈希，用于按身份证号查询匹配
  emergencyContact  String?
  emergencyPhone    String?
  address           String?
  bankAccount       String?        // AES-256 加密存储
  bankName          String?
  passwordHash      String?        // 员工端登录密码
  isPregnant        Boolean        @default(false)
  isInMedicalPeriod Boolean        @default(false)
  isWorkInjured     Boolean        @default(false)
  // 薪税扩展
  socialInsBase         Float?    // 社保缴费基数（便捷字段，由Record同步）
  housingFundBase       Float?    // 公积金缴费基数（便捷字段，由Record同步）
  socialInsStartMonth   String?   // 当前社保开始年月（便捷字段）
  socialInsEndMonth     String?   // 当前社保截止年月（便捷字段，null=在保）
  housingFundStartMonth String?   // 当前公积金开始年月（便捷字段）
  housingFundEndMonth   String?   // 当前公积金截止年月（便捷字段）
  specialDeduction  Float          @default(0)  // 专项附加扣除（子女教育、赡养老人等，员工portal端填报）
  city              String?        // 员工社保参保城市
  birthDate         DateTime?      // 出生日期（从身份证号提取）
  education         String?        // 学历（博士/硕士/本科/大专/高中/其他）
  femaleWorkerType  FemaleWorkerType? // 女性岗位类型（CADRE=干部/WORKER=工人，仅女性需要区分）
  retirementDaysLeft Int?          // 距退休天数（便捷字段，定期计算）
  createdBy         String
  createdAt         DateTime       @default(now())
  updatedAt         DateTime       @updatedAt

  contracts        LaborContract[]
  overtimeRecords  OvertimeRecord[]
  terminations     TerminationRecord[]
  riskItems        RiskItem[]
  payslips         Payslip[]
  salaryChanges    SalaryChangeRecord[]
  batchEntries     BatchEntry[]
  attachments      EmployeeAttachment[]
  disciplinaryRecords DisciplinaryRecord[]
  attendanceRecords   AttendanceRecord[]
  trainingRecords     TrainingRecord[]
  performanceRecords  PerformanceRecord[]
  socialInsRecords    EmployeeSocialInsRecord[]
  housingFundRecords  EmployeeHousingFundRecord[]
  departmentRecords   EmployeeDepartmentRecord[]
  aiReviewRecords     AIReviewRecord[]
  evidenceChains      EvidenceChain[]
  attendanceConfirmations AttendanceConfirmation[]
  policyReadRecords       PolicyReadRecord[]
  specialDeductionRecords SpecialDeductionRecord[]
  shiftAssignments        ShiftAssignment[]
  leaveRecords            LeaveRecord[]
  leaveRequests           LeaveRequest[]
  calendarEvents          CalendarEvent[]
  workProcesses           WorkProcess[]
  specialStatuses         EmployeeSpecialStatus[]
  commercialInsEnrollments CommercialInsuranceEnrollment[]
  benefitEnrollments      EmployeeBenefitEnrollment[]
  eSignRecords            ESignRecord[]

  @@unique([orgId, idCardHash])
}

model LaborContract {
  id                    String     @id @default(cuid())
  orgId                 String
  org                   Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId            String
  employee              Employee   @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  signDate              DateTime?
  startDate             DateTime
  endDate               DateTime?
  contractType          ContractType
  signMethod            SignMethod @default(PAPER)
  contractYears         Int        @default(3)
  probationMonths       Int        @default(0)
  probationSalary       Int        @default(0)
  renewalCount          Int        @default(0)
  attachmentName        String?
  attachmentUrl         String?
  electronicContractNo  String?
  electronicContractUrl String?
  createdBy             String
  createdAt             DateTime   @default(now())
  updatedAt             DateTime   @updatedAt

  confirmLinks ContractConfirmLink[]
}

model OvertimeRecord {
  id             String   @id @default(cuid())
  orgId          String
  org            Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId     String
  employee       Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  month          String   // YYYY-MM
  weekdayHours   Float    @default(0)
  weekendHours   Float    @default(0)
  holidayHours   Float    @default(0)
  weekdayPay     Float    @default(0)
  weekendPay     Float    @default(0)
  holidayPay     Float    @default(0)
  totalPay       Float    @default(0)
  batchId        String?  // 关联的发薪批次（加入后锁定，不可重复加入）
  createdAt      DateTime @default(now())

  @@unique([employeeId, month])
}

model TerminationRecord {
  id              String           @id @default(cuid())
  orgId           String
  org             Organization     @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee         @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  type            String           @default("TERMINATION") // TERMINATION=公司解聘, RESIGNATION=员工主动离职
  reason          TerminationReason
  terminationDate DateTime
  resignationReason String? // 主动离职原因（type=RESIGNATION时使用）
  compensation     Float           @default(0)
  socialInsEndMonth   String?     // 社保截止缴费年月 YYYY-MM
  housingFundEndMonth String?     // 公积金截止缴费年月 YYYY-MM
  riskLevel       RiskAssessment  @default(SAFE)
  checklist       Json
  remark          String?
  createdBy       String
  createdAt       DateTime         @default(now())
  updatedAt       DateTime         @updatedAt

  // 流程状态机
  status          String           @default("DRAFT") // DRAFT|PENDING_APPROVAL|APPROVED|EXECUTING|COMPLETED|REJECTED|CANCELLED
  currentStep     Int              @default(0)       // 当前完成到第几步
  // 补偿金分项明细 + 调整记录
  compensationBreakdown Json?      // { severance, noticePay, doublePay, other, adjustments: [{field, from, to, reason}] }
  // 合规检查覆盖记录
  checklistOverrides   Json?       // { key: { checked: bool, overrideReason: string } }
  // 工作交接清单
  handoverItems        Json?       // [{ key, label, done, remark }]
  // 审批信息
  approvedBy      String?
  approvedAt      DateTime?
  approvalComment String?
  updatedBy       String?

  @@index([orgId, status])
}

model RiskItem {
  id              String     @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId      String?
  employee        Employee?  @relation(fields: [employeeId], references: [id], onDelete: SetNull)
  type            RiskType
  level           RiskLevel
  status          RiskStatus @default(PENDING)
  title           String
  description     String
  actionUrl       String?
  // 风险量化：预估损失金额（元）
  estimatedLoss   Float?
  // 风险量化：损失区间 [最低, 最高]
  lossRange       Json?
  // 建议处理截止日期
  deadline        DateTime?
  resolvedAt      DateTime?
  resolvedBy      String?
  remark          String?
  createdAt       DateTime   @default(now())
  updatedAt       DateTime   @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
}

model AuditLog {
  id        String   @id @default(cuid())
  orgId     String
  org       Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  userId    String
  action    String
  entity    String
  entityId  String?
  detail    Json?
  ip        String?
  createdAt DateTime @default(now())

  @@index([orgId, createdAt])
}

// ========== 社保 & 通知 & 附件 ==========

model SocialInsuranceConfig {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  city            String   @default("北京")
  pensionOrg      Float    @default(16)    // 养老保险 企业比例 %
  pensionEmp      Float    @default(8)     // 养老保险 个人比例 %
  medicalOrg      Float    @default(9.8)   // 医疗保险 企业比例 %
  medicalEmp      Float    @default(2)     // 医疗保险 个人比例 %
  unemploymentOrg Float    @default(0.5)   // 失业保险 企业比例 %
  unemploymentEmp Float    @default(0.5)   // 失业保险 个人比例 %
  injuryOrg       Float    @default(0.2)   // 工伤保险 企业比例 %
  maternityOrg    Float    @default(0.8)   // 生育保险 企业比例 %
  baseMin         Float    @default(6326)  // 社保缴费基数下限（养老/失业/工伤）
  baseMax         Float    @default(33891) // 社保缴费基数上限（养老/失业/工伤）
  medicalBaseMin  Float    @default(0)     // 医疗/生育保险基数下限（0 时 fallback 到 baseMin）
  medicalBaseMax  Float    @default(0)     // 医疗/生育保险基数上限（0 时 fallback 到 baseMax）
  extraInsurances Json?    // 附加险种配置 JSON: [{ name, orgRate, empRate, baseType: 'pension'|'medical'|'fixed', fixedAmount }]
  effectiveFrom   String   // 生效月份 YYYY-MM
  effectiveTo     String?  // 失效月份 YYYY-MM（null=当前有效）
  isCurrent       Boolean  @default(true) // 是否当前生效版本
  adjustmentDone  Boolean  @default(false) // 是否已执行过社保基数调整
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([orgId, city, effectiveFrom])
  @@index([orgId, isCurrent])
}

model HousingFundConfig {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  city            String   @default("北京")
  accountType     String   @default("BASIC") // BASIC=基本公积金, SUPPLEMENTARY=补充公积金
  housingOrg      Float    @default(12)    // 公积金 企业比例 %
  housingEmp      Float    @default(12)    // 公积金 个人比例 %
  baseMin         Float    @default(6326)  // 公积金缴费基数下限
  baseMax         Float    @default(33891) // 公积金缴费基数上限
  effectiveFrom   String   // 生效月份 YYYY-MM
  effectiveTo     String?  // 失效月份 YYYY-MM（null=当前有效）
  isCurrent       Boolean  @default(true) // 是否当前生效版本
  adjustmentDone  Boolean  @default(false) // 是否已执行过公积金基数调整
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([orgId, city, accountType, effectiveFrom])
  @@index([orgId, isCurrent])
}

model NotificationSetting {
  id              String   @id @default(cuid())
  orgId           String   @unique
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  contractExpiry  Boolean  @default(true)
  expiryDays      Int      @default(30)
  contractUnsigned Boolean @default(true)
  overtimeAlert   Boolean  @default(true)
  payslipReady    Boolean  @default(true)
  // 月度事务提醒日（每月几号）
  payrollDay      Int      @default(10)   // 发薪日
  socialInsDay    Int      @default(15)   // 社保缴纳日
  housingFundDay  Int      @default(15)   // 公积金缴纳日
  taxDay          Int      @default(15)   // 个税申报日
  wechatWebhook   String?
  emailNotify     Boolean  @default(false)
  email           String?
  updatedAt       DateTime @updatedAt
}

model OvertimeConfig {
  id              String   @id @default(cuid())
  orgId           String   @unique
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  weekdayRate     Float    @default(1.5)  // 工作日加班倍率
  weekendRate     Float    @default(2.0)  // 休息日加班倍率
  holidayRate     Float    @default(3.0)  // 法定节假日加班倍率
  monthlyDays     Float    @default(21.75) // 月计薪天数
  dailyHours      Float    @default(8)    // 每日工时
  updatedAt       DateTime @updatedAt
}

model NotificationLog {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  type        String   // CONTRACT_EXPIRY / CONTRACT_UNSIGNED / OVERTIME / PAYSLIP
  title       String
  content     String
  channel     String   // WECHAT / EMAIL / IN_APP
  status      String   @default("SENT") // SENT / FAILED
  employeeId  String?
  createdAt   DateTime @default(now())

  @@index([orgId, createdAt])
}

model EmployeeAttachment {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId  String
  employee    Employee  @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  fileName    String
  fileType    String   // ID_CARD / BANK_CARD / CONTRACT_SCAN / EDUCATION / TERMINATION_DOC / RETIREMENT_DOC / INJURY_CERT / MEDICAL_CERT / PREGNANCY_CERT / DISCIPLINARY / OTHER
  fileUrl     String
  fileSize    Int      @default(0)
  // 关联违纪记录（可选）
  disciplinaryRecordId String?
  uploadedBy  String
  createdAt   DateTime @default(now())

  @@index([orgId, employeeId])
  @@index([disciplinaryRecordId])
}

// ========== 公司备用文件 ==========
model CompanyFile {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  fileName    String
  fileType    String   // BUSINESS_LICENSE=营业执照 / WORK_HOURS=工时备案 / HR_POLICY=制度文件 / LABOR_CONTRACT_TEMPLATE=合同模板 / OTHER=其他
  fileUrl     String
  fileSize    Int      @default(0)
  remark      String?  // 备注
  expiryDate  DateTime? // 有效期（如营业执照到期日）
  uploadedBy  String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, fileType])
}

// ========== 仲裁证据链 ==========

model DisciplinaryRecord {
  id             String   @id @default(cuid())
  orgId          String
  org            Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId     String
  employee       Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  violationDate  DateTime
  violationType  String   // LATE/ABSENT/INSUBORDINATION/MISCONDUCT/VIOLATE_POLICY/OTHER
  description    String
  severity       String   @default("WARNING") // WARNING/SERIOUS/SEVERE
  action         String   @default("ORAL_WARNING") // ORAL_WARNING/WRITTEN_WARNING/DEDUCTION/DEMOTION/TERMINATION
  actionDetail   String?
  employeeAck    Boolean  @default(false) // 员工是否签字确认
  ackDate        DateTime?
  ackMethod      String?  // SIGN/ELECTRONIC/REFUSED
  witness        String?  // 见证人
  attachmentUrl  String?
  createdBy      String
  createdAt      DateTime @default(now())
  updatedAt      DateTime @updatedAt

  @@index([orgId, employeeId])
}

model AttendanceRecord {
  id             String   @id @default(cuid())
  orgId          String
  org            Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId     String
  employee       Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  date           DateTime
  checkInTime    String?  // HH:mm
  checkOutTime   String?  // HH:mm
  status         String   @default("NORMAL") // NORMAL/LATE/EARLY_LEAVE/ABSENT/LEAVE/BUSINESS_TRIP
  lateMinutes    Int      @default(0)
  earlyMinutes   Int      @default(0)
  workHours      Float    @default(0)
  overtimeHours  Float    @default(0)
  remark         String?
  createdBy      String
  createdAt      DateTime @default(now())

  @@unique([employeeId, date])
  @@index([orgId, employeeId])
}

model TrainingRecord {
  id             String   @id @default(cuid())
  orgId          String
  org            Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId     String
  employee       Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  trainingDate   DateTime
  topic          String   // 培训主题/制度名称
  content        String?  // 培训内容摘要
  trainer        String?
  duration       Float    @default(0) // 培训时长（小时）
  ackStatus      String   @default("PENDING") // PENDING/SIGNED/REFUSED
  ackDate        DateTime?
  attachmentUrl  String?  // 签收单扫描件
  remark         String?
  createdBy      String
  createdAt      DateTime @default(now())

  @@index([orgId, employeeId])
}

model PerformanceRecord {
  id             String   @id @default(cuid())
  orgId          String
  org            Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId     String
  employee       Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  period         String   // 考核周期 YYYY-MM 或 YYYY-Q1
  score          Float    @default(0) // 考核得分
  grade          String   @default("B") // A/B/C/D
  result         String   @default("QUALIFIED") // EXCELLENT/QUALIFIED/NEED_IMPROVE/UNQUALIFIED
  summary        String?  // 考核评语
  improvementPlan String? // 改进计划（不胜任时）
  employeeAck    Boolean  @default(false)
  ackDate        DateTime?
  reviewer       String?
  createdBy      String
  createdAt      DateTime @default(now())

  @@unique([employeeId, period])
  @@index([orgId, employeeId])
}

// ========== 员工端表 ==========

model Payslip {
  id                 String   @id @default(cuid())
  orgId              String
  org                Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId         String
  employee           Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  month              String   // YYYY-MM
  // 薪酬构成
  baseSalary         Float    @default(0)
  overtimePay        Float    @default(0)
  weekdayOvertimePay Float    @default(0)
  weekendOvertimePay Float    @default(0)
  holidayOvertimePay Float    @default(0)
  allowance          Float    @default(0)
  deduction          Float    @default(0)
  bonus              Float    @default(0)       // 奖金/年终奖
  totalPay           Float    @default(0)       // 应发合计
  // 扣除项
  socialEmp          Float    @default(0)       // 个人社保
  housingEmp         Float    @default(0)       // 个人公积金
  tax                Float    @default(0)       // 个人所得税
  netPay             Float    @default(0)       // 实发工资 = totalPay - socialEmp - housingEmp - tax
  // 累计预扣法
  ytdIncome          Float    @default(0)       // 当年累计收入
  ytdTaxDeducted     Float    @default(0)       // 当年累计已扣税
  ytdSocialEmp       Float    @default(0)       // 当年累计个人社保
  ytdHousingEmp      Float    @default(0)       // 当年累计个人公积金
  // 状态
  status             PayslipStatus @default(PENDING)  // PENDING → PUBLISHED
  confirmedAt        DateTime?
  confirmedIp        String?
  publishedAt        DateTime?                    // 工资条发布到员工端的时间
  publishStatus      String?  // UNPUBLISHED/PUBLISHED/SCHEDULED
  scheduledAt        DateTime? // 定时发送时间
  viewedAt           DateTime? // 员工查看工资条的时间
  createdAt          DateTime @default(now())
  updatedAt          DateTime @updatedAt

  @@unique([employeeId, month])
  @@index([orgId, month])
  @@index([orgId, status])
}

model PayrollBatch {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  month           String   // YYYY-MM
  batchNo         Int      // 批次序号（1, 2, 3...）
  name            String   // 批次名称
  type            PayrollBatchType @default(REGULAR)
  status          PayrollBatchStatus @default(DRAFT)
  employeeCount   Int      @default(0)
  totalPay        Float    @default(0)
  totalNetPay     Float    @default(0)
  totalSocialOrg  Float    @default(0)
  totalSocialEmp  Float    @default(0)
  totalHousingOrg Float    @default(0)
  totalHousingEmp Float    @default(0)
  totalTax        Float    @default(0)
  remark          String?
  createdBy       String
  createdAt       DateTime @default(now())
  archivedAt      DateTime?
  updatedAt       DateTime @updatedAt

  entries         BatchEntry[]

  @@unique([orgId, month, batchNo])
  @@index([orgId, month])
  @@index([orgId, status])
}

model BatchEntry {
  id              String   @id @default(cuid())
  batchId         String
  batch           PayrollBatch @relation(fields: [batchId], references: [id], onDelete: Cascade)
  orgId           String
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  // 薪酬项（可编辑的输入项）
  baseSalary      Float    @default(0)
  overtimePay     Float    @default(0)
  allowance       Float    @default(0)
  deduction       Float    @default(0)
  bonus           Float    @default(0)
  // 细化薪资项
  positionSalary  Float    @default(0)  // 岗位工资
  performanceSalary Float  @default(0)  // 绩效工资
  senioritySalary Float    @default(0)  // 工龄工资
  transportAllowance Float @default(0)  // 交通补贴
  mealAllowance   Float    @default(0)  // 餐补
  housingAllowance Float   @default(0)  // 住房补贴
  communicationAllowance Float @default(0) // 通讯补贴
  otherDeduction  Float    @default(0)  // 其他扣款
  // 自动计算项
  socialEmp       Float    @default(0)
  socialOrg       Float    @default(0)
  housingEmp      Float    @default(0)
  housingOrg      Float    @default(0)
  tax             Float    @default(0)
  totalPay        Float    @default(0)  // 应发合计
  netPay          Float    @default(0)  // 实发工资
  // 风险提示
  riskWarnings    Json?
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([batchId, employeeId])
  @@index([orgId, employeeId])
}

model PayslipItem {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name            String   // 显示名称
  code            String   // 字段代码
  type            PayslipItemType @default(INPUT)
  formula         String?  // 计算公式（CALCULATED 类型），如 "baseSalary + overtimePay + allowance - deduction"
  order           Int      @default(0)
  isDefault       Boolean  @default(true)  // 系统预置项不可删除
  isEditable      Boolean  @default(true)
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([orgId, code])
}

model SalaryChangeRecord {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  oldSalary       Float
  newSalary       Float
  effectiveDate   DateTime  // 生效日期
  effectiveMonth  String   // 生效年月 YYYY-MM（从 effectiveDate 转换）
  endMonth        String?  // 失效年月 YYYY-MM（null=至今有效，被新版本覆盖时设置）
  changeType      String   @default("SALARY_CHANGE") // ONBOARDING=入职, REHIRE=重新入职, SALARY_CHANGE=调薪
  reason          String?
  createdBy       String
  createdAt       DateTime @default(now())

  @@index([orgId, employeeId])
  @@index([employeeId, effectiveMonth, endMonth])
}

model EmployeeSocialInsRecord {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee   @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  city         String    @default("北京")  // 参保城市
  startMonth   String   // 开始缴费年月 YYYY-MM
  endMonth     String?  // 截止缴费年月 YYYY-MM（null=至今有效）
  base         Float    // 缴费基数
  changeType   String   // ONBOARDING=入职, REHIRE=重新入职, ADJUST=调基, TERMINATION=离职/解聘
  changeRefId  String?  // 关联的 TerminationRecord ID（离职/解聘时）
  remark       String?
  createdBy    String
  createdAt    DateTime @default(now())

  @@index([orgId, employeeId])
  @@index([employeeId, startMonth, endMonth])
  @@index([orgId, city])
}

model EmployeeHousingFundRecord {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee   @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  city         String    @default("北京")  // 参保城市
  startMonth   String   // 开始缴费年月 YYYY-MM
  endMonth     String?  // 截止缴费年月 YYYY-MM（null=至今有效）
  base         Float    // 缴费基数
  changeType   String   // ONBOARDING=入职, REHIRE=重新入职, ADJUST=调基, TERMINATION=离职/解聘
  changeRefId  String?  // 关联的 TerminationRecord ID（离职/解聘时）
  remark       String?
  createdBy    String
  createdAt    DateTime @default(now())

  @@index([orgId, employeeId])
  @@index([employeeId, startMonth, endMonth])
}

/// 月度社保/公积金办理记录（标记某月已办理完成，保存快照）
model SocialMonthlyProcess {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  month        String   // 办理月份 YYYY-MM
  type         String   // SOCIAL=社保, HOUSING=公积金
  status       String   @default("COMPLETED") // COMPLETED=已办理
  snapshot     Json     // 办理时的数据快照（增减员+在保人员+缴费明细）
  processedBy  String
  processedAt  DateTime @default(now())
  createdBy    String
  createdAt    DateTime @default(now())

  @@unique([orgId, month, type])
  @@index([orgId, month])
}

model EmployeeDepartmentRecord {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee   @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  oldDepartment String  // 调整前部门
  newDepartment String  // 调整后部门
  effectiveMonth String // 生效年月 YYYY-MM
  endMonth     String?  // 失效年月 YYYY-MM（null=至今有效）
  reason       String?  // 调部门原因
  changeType   String   // ONBOARDING=入职, REHIRE=重新入职, TRANSFER=调部门
  createdBy    String
  createdAt    DateTime @default(now())

  @@index([orgId, employeeId])
  @@index([employeeId, effectiveMonth, endMonth])
}

model OnboardingLink {
  id        String           @id @default(cuid())
  orgId     String
  org       Organization     @relation(fields: [orgId], references: [id], onDelete: Cascade)
  token     String           @unique
  employeeName String?
  phone     String?
  status    OnboardingStatus @default(PENDING)
  formData  Json?
  expiresAt DateTime
  usedAt    DateTime?
  createdBy String
  createdAt DateTime         @default(now())
  updatedAt DateTime         @updatedAt

  @@index([orgId, status])
}

model ContractConfirmLink {
  id          String                 @id @default(cuid())
  orgId       String
  org         Organization           @relation(fields: [orgId], references: [id], onDelete: Cascade)
  contractId  String
  contract    LaborContract          @relation(fields: [contractId], references: [id], onDelete: Cascade)
  token       String                 @unique
  status      ContractConfirmStatus  @default(UNCONFIRMED)
  confirmedAt DateTime?
  confirmedIp String?
  expiresAt   DateTime
  createdBy   String
  createdAt   DateTime               @default(now())
  updatedAt   DateTime               @updatedAt

  @@index([orgId, status])
}

// ========== AI 会话 & 审查记录 ==========

model AIConversation {
  id        String   @id @default(cuid())
  orgId     String
  org       Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  userId    String
  title     String   @default("新对话")
  messages  Json     // [{ role, content }]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  @@index([orgId, userId])
}

model AIReviewRecord {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId  String?
  employee    Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
  type        String   // REVIEW=合同审查, CASE=案例匹配
  input       String   // 用户输入的合同文本或争议情形
  result      String   // AI 返回的审查/分析结果
  createdBy   String
  createdAt   DateTime @default(now())

  @@index([orgId, employeeId])
}

// ========== RAG 知识库 ==========

model RagKnowledge {
  id        String   @id
  title     String
  content   String
  source    String
  category  String
  embedding Unsupported("vector(1536)")?
  createdAt DateTime @default(now()) @map("created_at")

  @@index([category])
  @@map("rag_knowledge")
}

// ========== 退休政策版本管理 ==========

model RetirementPolicy {
  id            String   @id @default(cuid())
  orgId         String
  org           Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  version       Int      @default(1)
  content       String   // AI 返回的完整政策内容
  contentHash   String   // 内容 hash，用于判断内容是否变化
  status        String   @default("PENDING") // PENDING=待确认, CONFIRMED=已生效, SUPERSEDED=已被新版本替代
  maleRetireAge Float    @default(60)   // 男性退休年龄
  femaleRetireAge Float  @default(55)   // 女性退休年龄（干部55，工人50，由AI解析最新政策）
  femaleWorkerAge Float  @default(50)   // 女性工人退休年龄
  createdAt     DateTime @default(now())
  confirmedAt   DateTime?  // 用户确认时间

  @@index([orgId, createdAt])
}

// ========== 证据链管理 ==========

model EvidenceChain {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  category    String   // CONTRACT_SIGN / ONBOARD / PAYSLIP_CONFIRM / DISCIPLINARY / ATTENDANCE / TERMINATION
  refId       String?  // 关联记录 ID（合同ID/工资条ID等）
  employeeId  String?
  employee    Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
  events      Json     // [{ action, timestamp, ip, userAgent, smsCode?, location? }]
  hash        String   // 全链路 SHA-256 哈希（防篡改）
  createdBy   String
  createdAt   DateTime @default(now())

  @@index([orgId, category, refId])
  @@index([orgId, employeeId])
}

// ========== 考勤确认 ==========

model AttendanceConfirmation {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  month           String   // YYYY-MM
  workDays        Int      @default(0)
  weekdayHours    Float    @default(0)
  weekendHours    Float    @default(0)
  holidayHours    Float    @default(0)
  overtimePay     Float    @default(0)
  confirmedAt     DateTime?
  confirmedBy     String?
  confirmIp       String?
  status          String   @default("PENDING") // PENDING / CONFIRMED / DISPUTED
  disputeNote     String?  // 员工有异议时的说明
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([orgId, employeeId, month])
  @@index([orgId, month])
  @@index([orgId, status])
}

// ========== 规章制度民主程序 ==========

model PolicyDocument {
  id                String   @id @default(cuid())
  orgId             String
  org               Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  title             String
  content           String
  type              String   @default("RULES") // RULES=规章制度 / NOTICE=通知
  status            String   @default("DRAFT") // DRAFT / DISCUSSING / CONSULTING / PUBLISHED
  democracyProgress Json?    // { currentStep: 1-4, steps: [{ name, status, date, note }] }
  publishedAt       DateTime?
  createdBy         String
  createdAt         DateTime @default(now())
  updatedAt         DateTime @updatedAt
  readRecords       PolicyReadRecord[]

  @@index([orgId, status])
}

// ========== 规章制度阅读签收 ==========

model PolicyReadRecord {
  id          String   @id @default(cuid())
  policyId    String
  policy      PolicyDocument @relation(fields: [policyId], references: [id], onDelete: Cascade)
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId  String
  employee    Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  readAt      DateTime @default(now())
  ip          String?
  userAgent   String?

  @@unique([policyId, employeeId])
  @@index([orgId, employeeId])
}

// ========== 用工体检诊断报告 ==========

model HealthCheckReport {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  year        Int      // 诊断年度
  totalScore  Int      // 综合评分 0-100
  level       String   // safe / warning / danger
  dimensions  Json     // [{ key, name, score, findings: [], recommendations: [] }]
  summary     String   // 诊断总结
  createdBy   String
  createdAt   DateTime @default(now())

  @@index([orgId, year])
  @@index([orgId, createdAt])
}

// ========== 年度价值报告 ==========

model AnnualValueReport {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  year            Int      // 报告年度
  totalValue      Int      // 总价值（元）
  roi             Float    // ROI 百分比
  metrics         Json     // { risksResolved, lossAvoided, aiQueries, contractsReviewed, payrollProcessed, employeesManaged }
  timeline        Json     // [{ month, event, value }] 月度事件时间轴
  costSaved       Int      // 节约成本（元）
  timeSaved       Int      // 节约工时（小时）
  summary         String   // 年度总结
  createdBy       String
  createdAt       DateTime @default(now())

  @@index([orgId, year])
  @@index([orgId, createdAt])
}

// 专项附加扣除按月记录
model SpecialDeductionRecord {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId  String
  employee    Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  month       String   // YYYY-MM 月份
  amount      Float    @default(0) // 专项附加扣除总额
  children    Float    @default(0) // 子女教育
  elderly     Float    @default(0) // 赡养老人
  housing     Float    @default(0) // 住房贷款利息/住房租金
  education   Float    @default(0) // 继续教育
  infant      Float    @default(0) // 3岁以下婴幼儿照护
  remark      String?
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@unique([employeeId, month])
  @@index([orgId, month])
}

// ========== 班次管理 ==========

model Shift {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name         String   // 班次名称，如"早班"、"白班"、"夜班"
  startTime    String   // 上班时间 HH:mm
  endTime      String   // 下班时间 HH:mm
  flexibleMinutes Int   @default(0) // 弹性时长（分钟）
  restMinutes  Int      @default(0) // 休息时长（分钟）
  color        String   @default("#3b82f6") // 日历显示颜色
  createdBy    String
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt
  assignments  ShiftAssignment[]

  @@index([orgId])
}

// ========== 排班记录 ==========

model ShiftAssignment {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  shiftId      String
  shift        Shift    @relation(fields: [shiftId], references: [id], onDelete: Cascade)
  date         DateTime // 排班日期
  createdBy    String
  createdAt    DateTime @default(now())

  @@unique([employeeId, date])
  @@index([orgId, date])
  @@index([orgId, employeeId])
}

// ========== 休假记录（直接记录，无审批流程） ==========

model LeaveRecord {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  leaveType    String   // SICK=病假 / PERSONAL=事假 / ANNUAL=年假 / MATERNITY=产假 / OTHER=其他
  startDate    DateTime
  endDate      DateTime
  days         Float    // 请假天数
  reason       String?
  remark       String?
  createdBy    String
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  @@index([orgId, employeeId])
  @@index([orgId, startDate])
}

// ========== 休假审批流 ==========

model LeaveRequest {
  id           String   @id @default(cuid())
  orgId        String
  org          Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId   String
  employee     Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  leaveType    String   // SICK=病假 / PERSONAL=事假 / ANNUAL=年假 / MATERNITY=产假 / OTHER=其他
  startDate    DateTime
  endDate      DateTime
  days         Float    // 请假天数
  reason       String?
  attachment   String?  // 附件URL（如病假条）
  status       String   @default("PENDING") // PENDING=待审批 / APPROVED=已批准 / REJECTED=已驳回 / CANCELLED=已撤回
  approverId   String?  // 审批人ID
  approvedAt   DateTime?
  approveRemark String? // 审批意见
  createdBy    String
  createdAt    DateTime @default(now())
  updatedAt    DateTime @updatedAt

  @@index([orgId, employeeId])
  @@index([orgId, status])
  @@index([orgId, startDate])
}

// ========== 自定义日历事件 ==========

model CalendarEvent {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  title       String
  date        DateTime
  endDate     DateTime?
  type        String   @default("CUSTOM") // CUSTOM=自定义, MEETING=会议, TEAM_BUILDING=团建, TRAINING=培训, INTERVIEW=面试
  priority    String   @default("medium") // high/medium/low
  location    String?
  description String?
  employeeId  String?
  employee    Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, date])
  @@index([orgId, type])
}

// ========== 人工咨询服务 ==========

model Consultation {
  id            String   @id @default(cuid())
  orgId         String
  org           Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  type          String   // LEGAL=法律咨询, ARBITRATION=仲裁代理, COURT=出庭服务
  title         String
  description   String
  contactName   String
  contactPhone  String
  status        String   @default("PENDING") // PENDING=待处理, CONTACTED=已联系, COMPLETED=已完成, CANCELLED=已取消
  aiConversationId String? // 关联 AI 会话
  remark        String?
  createdBy     String
  createdAt     DateTime @default(now())
  updatedAt     DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
}

// ========== 用工办理工作流 ==========
model WorkProcess {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  type        String   // HIRE/ONBOARD/CUSTOM_CONTRACT/INFO_SUBMIT/CONFIRM/CHANGE/RENEW/SUSPEND/INCOME_CERT/TERMINATE/RESCIND/LEAVING_CERT/FLEXIBLE
  title       String
  employeeId  String?
  employee    Employee? @relation(fields: [employeeId], references: [id], onDelete: SetNull)
  status      String   @default("DRAFT") // DRAFT/PENDING_APPROVAL/APPROVED/REJECTED/EXECUTING/COMPLETED/CANCELLED
  formData    Json     // 表单数据 JSON
  documents   Json?    // 生成的文书列表 [{name, content, type}]
  approverId  String?
  approvedAt  DateTime?
  remark      String?
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
  @@index([orgId, createdBy])
}

// ========== 企业自建文本模板 ==========
model EnterpriseTemplate {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name        String
  category    String   // CONTRACT/RULES/NOTICE/AGREEMENT/OTHER
  description String?
  content     String   @db.Text
  variables   String[] // 变量名列表
  status      String   @default("ACTIVE") // ACTIVE/ARCHIVED
  createdBy   String
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt

  @@index([orgId, category])
}

// ========== 考勤发布记录 ==========
model AttendancePublish {
  id          String   @id @default(cuid())
  orgId       String
  org         Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  month       String   // YYYY-MM
  title       String   // 如"2026年7月考勤表"
  status      String   @default("PUBLISHED") // PUBLISHED/CANCELLED
  publishDate DateTime @default(now())
  createdBy   String
  createdAt   DateTime @default(now())

  @@unique([orgId, month])
  @@index([orgId, month])
}

// ========== 员工特殊状态台账（三期/工伤/医疗期等） ==========
model EmployeeSpecialStatus {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  type            String   // PREGNANCY(三期) | WORK_INJURY(工伤) | MEDICAL_PERIOD(医疗期) | OTHER
  status          String   @default("ACTIVE") // ACTIVE(进行中) | RESOLVED(已结束) | PENDING(待处理)

  // 通用时间节点
  startDate       DateTime?  // 开始日期
  endDate         DateTime?  // 预计结束日期
  actualEndDate   DateTime?  // 实际结束日期

  // 三期专用
  expectedDueDate      DateTime?  // 预产期
  maternityLeaveStart  DateTime?  // 产假开始
  maternityLeaveEnd    DateTime?  // 产假结束
  nursingEndDate       DateTime?  // 哺乳期截止

  // 工伤专用
  injuryDate           DateTime?  // 受伤日期
  injuryDescription    String?    // 伤情描述
  certificationDate    DateTime?  // 工伤认定日期
  certificationNo      String?    // 认定书编号
  disabilityLevel      Int?       // 伤残等级(1-10级)
  assessmentDate       DateTime?  // 鉴定日期

  // 医疗期专用
  medicalMonths        Int?       // 医疗期月数
  medicalPeriodEnd     DateTime?  // 医疗期截止日

  // 通用
  description          String?    // 备注
  attachments          Json?      // 附件列表 [{name, url}]
  timeline             Json?      // 操作时间线 [{time, action, by}]
  reminderDate         DateTime?  // 提醒日期
  createdBy            String
  createdAt            DateTime @default(now())
  updatedAt            DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
  @@index([employeeId])
}

// ========== 验收测试 ==========
model AcceptanceTest {
  id              String   @id @default(uuid())
  orgId           String
  verifierName    String   // 验收人姓名
  results         Json     // { "1.1": "pass", "1.2": "fail", ... }
  remarks         Json     // { "1.1": "备注内容", ... }
  conclusionName  String?  // 结论验收人
  conclusionDate  String?  // 结论日期
  conclusionResult String? // pass | conditional | fail — 系统自动计算
  conclusionIssues String? // 遗留问题（系统自动汇总）
  screenshots      Json?     // { "0-0": "data:image/png;base64,...", ... }
  signature1       String?   // 验收人签名 dataURL
  signature2       String?   // 项目经理签名 dataURL
  status          String   @default("DRAFT") // DRAFT | SUBMITTED
  submittedAt     DateTime?
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@unique([orgId, verifierName])
  @@index([orgId, status])
}

// ========== 商业保险 ==========
model CommercialInsurancePlan {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name            String
  type            String   // ACCIDENT | SUPPLEMENTARY_MEDICAL | EMPLOYER_LIABILITY | CRITICAL_ILLNESS | GROUP_LIFE | OTHER
  provider        String   // 保险公司
  policyNo        String?
  premium         Float    // 年保费
  coverageAmount  Float    // 保额
  effectiveFrom   String   // YYYY-MM-DD
  effectiveTo     String?  // null = 长期
  description     String?
  status          String   @default("ACTIVE") // ACTIVE | EXPIRED | CANCELLED
  enrollments     CommercialInsuranceEnrollment[]
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, type])
}

model CommercialInsuranceEnrollment {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  planId          String
  plan            CommercialInsurancePlan @relation(fields: [planId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  premium         Float    // 个人保费
  effectiveFrom   String   // YYYY-MM-DD
  effectiveTo     String?
  status          String   @default("ACTIVE") // ACTIVE | TERMINATED
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@index([orgId, planId])
  @@index([employeeId])
}

// ========== 员工福利 ==========
model EmployeeBenefitPlan {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  name            String
  category        String   // TRANSPORT | MEAL | HOUSING | COMMUNICATION | HEALTH_CHECK | HOLIDAY | BIRTHDAY | OTHER
  amount          Float    // 每月金额（或每次金额）
  frequency       String   @default("MONTHLY") // MONTHLY | QUARTERLY | YEARLY | ONE_TIME
  taxDeductible   Boolean  @default(false) // 是否税前扣除
  description     String?
  status          String   @default("ACTIVE")
  enrollments     EmployeeBenefitEnrollment[]
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@index([orgId, status])
  @@index([orgId, category])
}

model EmployeeBenefitEnrollment {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  planId          String
  plan            EmployeeBenefitPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  effectiveFrom   String   // YYYY-MM
  effectiveTo     String?  // null = 至今
  amount          Float?   // 覆盖默认金额（个别调整）
  status          String   @default("ACTIVE")
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@index([orgId, planId])
  @@index([employeeId])
}

// ========== 电子签署（易签宝） ==========
model ESignRecord {
  id              String   @id @default(cuid())
  orgId           String
  org             Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)
  contractId      String?  // 关联 LaborContract
  employeeId      String
  employee        Employee @relation(fields: [employeeId], references: [id], onDelete: Cascade)
  flowId          String?  // 易签宝流程ID
  documentTitle   String   // 文件标题
  documentContent String?  // 文件内容（HTML/PDF base64）
  status          String   @default("PENDING") // PENDING | SIGNING | COMPLETED | REJECTED | EXPIRED | CANCELLED
  signUrl         String?  // 签署链接
  signedPdfUrl    String?  // 签署完成后的PDF链接
  initiatedBy     String   // 发起人（HR用户ID）
  completedAt     DateTime?
  expiredAt       DateTime?
  callbackData    Json?    // 易签宝回调数据
  remark          String?
  createdBy       String
  createdAt       DateTime @default(now())
  updatedAt       DateTime @updatedAt

  @@index([orgId, status])
  @@index([employeeId])
  @@index([contractId])
}
