generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" } enum RoleCode { employee manager ceo finance finance_mgr administration hr system_admin admin } enum EmployeeStatus { active archived } enum DelegationGrantScope { reimbursement_submit all } enum ReimbursementStatus { draft reviewing approved paid rejected cancelled } enum LeaveRequestStatus { draft reviewing approved rejected cancelled } enum PurchaseRequestStatus { draft reviewing approved rejected cancelled } enum TravelRequestStatus { draft reviewing approved rejected } enum TravelTripType { domestic international } enum TravelSegmentRole { outbound return connection } enum TravelTransportType { flight train car bus other } enum TravelReconciliationBatchStatus { draft reconciled } enum TravelReconciliationItemKind { order orphan_transaction } enum TravelReconciliationMatchStatus { matched amount_mismatch currency_mismatch missing_transaction duplicate_charge orphan_transaction reversed_after_payment } enum TravelReconciliationResolutionStatus { pending confirmed } enum AssetCardStatus { in_stock in_use under_repair retired archived } enum AssetType { fixed_asset electronic_document electronic_system code_repository backup_media } enum AssetSensitivityLevel { public_candidate internal confidential strictly_confidential } enum InventoryCheckScopeType { all legal_entity cost_center location } enum InventoryCheckStatus { draft counting completed } enum InventoryCheckResult { matched missing extra damaged } enum LeaveDaySession { am pm } enum LeaveLedgerEntryType { grant reserve consume release adjust } enum InvoicePoolStatus { pending_ocr ocr_failed available bound archived } enum InvoiceArchivedReason { used_complete unused_timeout manual } enum OcrProvider { tencent mock } enum OcrType { vat train flight taxi general } enum DocumentResetPeriod { none daily monthly yearly } enum DocumentCategoryEntityType { reimbursement leave purchase_request travel_request travel_reconciliation_batch asset_card general } enum HolidayCalendarDayType { holiday workday adjusted_workday } enum WorkflowInstanceStatus { pending approved rejected cancelled terminated } enum WorkflowTaskStatus { pending completed rejected cancelled skipped } enum WorkflowTaskOutcome { approved rejected returned start transfer skipped } enum ApprovalTransferStatus { active cancelled } enum ExpenseCategory { travel rd production office business assets other } enum BudgetControlMode { warn block manual_review } enum RiskFlagStatus { open resolved dismissed } enum PaymentBatchStatus { draft reviewed executed failed cancelled } enum PaymentBatchEntityType { reimbursement travel_order loan_repayment } enum BudgetControlRuleEntityType { all reimbursement purchase_request travel_request } enum WorkspaceProfile { small_team_internal } enum WorkspaceOrgMode { single_company } enum WorkspacePrimaryEntryMode { password wecom } enum WorkspaceNotificationStrategy { in_app } enum WorkspaceDevicePriority { desktop } enum EmploymentLifecycleStatus { onboarding probation active offboarding inactive } enum EmployeeLifecycleEventType { onboard regularize transfer offboard } enum EmployeeChecklistScene { onboarding offboarding transfer } enum EmployeeChecklistTaskType { account_setup asset_issue policy_ack asset_return access_revoke expense_clearance handover_note } enum EmployeeChecklistTaskStatus { pending completed skipped } enum EmployeePresenceStatus { office remote out travel leave } enum EmployeePresenceTimeRange { full_day morning afternoon } enum EmployeePresenceSource { manual leave_sync admin_override } enum AttendanceCorrectionKind { missed_punch out overtime } enum AttendanceCorrectionStatus { reviewing approved rejected cancelled } enum EmployeeContractType { labor nda non_compete internship } enum EmployeeTrainingType { internal external online } enum EmployeeTrainingStatus { planned in_progress completed cancelled } enum SalaryItemType { earning deduction } enum PayslipStatus { draft issued } enum PerformanceReviewCycleType { monthly quarterly semi_annual annual } enum PerformanceReviewCycleStatus { draft active completed } enum PerformanceReviewDimensionType { work_quality work_efficiency teamwork initiative professional_skill } enum WeeklyReportStatus { draft submitted } enum TodoPriority { low normal high } enum TodoStatus { todo doing done cancelled } enum NotificationDeliveryStatus { pending success failed } enum TodoSource { manual weekly_report } enum ProjectStatus { draft active paused completed archived } enum ProjectRole { owner manager member observer } enum ProjectMilestoneStatus { pending in_progress done delayed cancelled } enum ProjectTaskStatus { todo doing blocked done cancelled } enum ProjectTaskPriority { low normal high urgent } enum ProjectRiskLevel { low medium high } enum ProjectDeliveryRecordType { kickoff onsite stage_acceptance final_acceptance handover } enum ProjectCommunicationChannel { wechat phone meeting wecom email onsite other } enum ProjectClosureChecklistStatus { pending done waived } enum ConfidentialityLevel { public internal confidential restricted } enum ContractRegistryType { purchase sales service framework other } enum DocumentStorageType { oa_link nas internal_share offline_archive } model Department { id String @id @default(uuid()) @db.Uuid name String parent_id String? @db.Uuid archived_at DateTime? archived_by String? @db.Uuid created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid parent Department? @relation("DepartmentToParent", fields: [parent_id], references: [id], onDelete: Restrict) children Department[] @relation("DepartmentToParent") employees Employee[] reimbursement_forms ReimbursementForm[] leave_requests LeaveRequest[] purchase_requests PurchaseRequest[] travel_requests TravelRequest[] attendance_corrections AttendanceCorrection[] workflow_instances WorkflowInstance[] budget_pools BudgetPool[] travel_orders TravelOrder[] card_authorizations CardAuthorization[] card_transactions CardTransaction[] @@index([parent_id]) @@map("departments") } model Employee { deleted_reimbursements ReimbursementForm[] @relation("ReimbursementDeletedBy") id String @id @default(uuid()) @db.Uuid employee_no String @unique @default(dbgenerated("generate_employee_number()")) name String phone String? @unique email String @unique department_id String @db.Uuid legal_entity_id String? @db.Uuid title String direct_manager_id String? @db.Uuid hire_date DateTime @db.Date status EmployeeStatus @default(active) employment_status EmploymentLifecycleStatus @default(active) probation_end_date DateTime? @db.Date last_working_date DateTime? @db.Date work_location String? emergency_contact_name String? emergency_contact_phone String? notes String? avatar_path String? notification_push_enabled Boolean @default(true) bank_account_encrypted String bank_name String bank_institution_id String? @db.Uuid id_number_encrypted String? password_hash String token_version Int @default(0) must_change_password Boolean @default(false) login_failed_count Int @default(0) login_failed_first_at DateTime? login_locked_until DateTime? email_login_code_failed_count Int @default(0) email_login_code_failed_first_at DateTime? email_login_code_locked_until DateTime? email_login_code_last_requested_at DateTime? password_reset_failed_count Int @default(0) password_reset_failed_first_at DateTime? password_reset_locked_until DateTime? password_reset_request_count Int @default(0) password_reset_request_first_at DateTime? password_reset_last_requested_at DateTime? archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid department Department @relation(fields: [department_id], references: [id], onDelete: Restrict) legal_entity LegalEntity? @relation(fields: [legal_entity_id], references: [id], onDelete: SetNull) bank_institution BankInstitution? @relation(fields: [bank_institution_id], references: [id], onDelete: SetNull) direct_manager Employee? @relation("EmployeeToManager", fields: [direct_manager_id], references: [id], onDelete: Restrict) subordinates Employee[] @relation("EmployeeToManager") roles EmployeeRole[] delegation_grants_as_principal DelegationGrant[] @relation("DelegationPrincipal") delegation_grants_as_delegate DelegationGrant[] @relation("DelegationDelegate") auth_sessions AuthSession[] audit_logs AuditLog[] @relation("AuditActor") notifications Notification[] submitted_reimbursements ReimbursementForm[] @relation("ReimbursementSubmitter") owned_reimbursements ReimbursementForm[] @relation("ReimbursementOwner") paid_reimbursements ReimbursementForm[] @relation("ReimbursementPaidBy") reimbursement_attachments_uploaded ReimbursementAttachment[] @relation("ReimbursementAttachmentUploader") payment_batch_receipts_uploaded PaymentBatchReceiptAttachment[] @relation("PaymentBatchReceiptAttachmentUploader") payment_batches_last_exported PaymentBatch[] @relation("PaymentOrderLastExportedBy") leave_requests LeaveRequest[] leave_ledgers LeaveLedger[] wecom_checkin_records WecomCheckinRecord[] wecom_checkin_daily_summaries WecomCheckinDailySummary[] wecom_checkin_monthly_summaries WecomCheckinMonthlySummary[] wecom_checkin_rule_snapshots WecomCheckinRuleSnapshot[] wecom_checkin_sync_runs WecomCheckinSyncRun[] @relation("WecomCheckinSyncRunTrigger") wecom_directory_sync_runs WecomDirectorySyncRun[] @relation("WecomDirectorySyncRunEmployee") triggered_wecom_directory_sync_runs WecomDirectorySyncRun[] @relation("WecomDirectorySyncRunTrigger") wecom_hr_master_sync_items WecomHrMasterSyncItem[] @relation("WecomHrMasterSyncItemEmployee") triggered_wecom_hr_master_sync_runs WecomHrMasterSyncRun[] @relation("WecomHrMasterSyncRunTrigger") wecom_approval_archives_applicant WecomApprovalArchive[] @relation("WecomApprovalArchiveApplicant") wecom_approval_participants WecomApprovalParticipant[] @relation("WecomApprovalParticipantEmployee") wecom_approval_actions_operator WecomApprovalAction[] @relation("WecomApprovalActionOperator") attendance_corrections AttendanceCorrection[] owned_cost_centers CostCenter[] @relation("CostCenterOwner") purchase_requests_applicant PurchaseRequest[] @relation("PurchaseRequestApplicant") travel_requests_applicant TravelRequest[] @relation("TravelRequestApplicant") travel_requests_submitted TravelRequest[] @relation("TravelRequestSubmitter") purchase_requests_submitted PurchaseRequest[] @relation("PurchaseRequestSubmitter") purchase_attachments_uploaded PurchaseAttachment[] @relation("PurchaseAttachmentUploader") purchase_order_archives PurchaseOrderArchive[] @relation("PurchaseOrderArchiveArchivedBy") assigned_asset_cards AssetCard[] @relation("AssetCardAssignee") owned_asset_cards AssetCard[] @relation("AssetCardOwner") kept_asset_cards AssetCard[] @relation("AssetCardKeeper") asset_assignments AssetAssignment[] asset_transfers_from AssetTransfer[] @relation("AssetTransferFromEmployee") asset_transfers_to AssetTransfer[] @relation("AssetTransferToEmployee") owned_invoices InvoicePool[] @relation("InvoiceOwner") uploaded_invoices InvoicePool[] @relation("InvoiceUploader") overridden_invoices InvoicePool[] @relation("InvoiceOverrideBy") requested_invoice_verifications InvoiceVerificationRecord[] @relation("InvoiceVerificationRequester") travel_orders TravelOrder[] @relation("TravelOrderEmployee") paid_travel_orders TravelOrder[] @relation("TravelOrderPaidBy") confirmed_travel_reconciliation_batches TravelReconciliationBatch[] @relation("TravelReconciliationBatchConfirmedBy") card_authorizations CardAuthorization[] card_transactions CardTransaction[] @relation("CardTransactionEmployee") freeze_suggested_card_transactions CardTransaction[] @relation("CardTransactionFreezeSuggestedBy") confirmed_travel_reconciliation_items TravelReconciliationItem[] @relation("TravelReconciliationItemConfirmedBy") workflow_instances_started WorkflowInstance[] @relation("WorkflowInstanceSubmitter") workflow_history_actions WorkflowHistory[] @relation("WorkflowHistoryActor") workflow_tasks_assigned WorkflowTask[] @relation("WorkflowTaskAssignee") workflow_tasks_completed WorkflowTask[] @relation("WorkflowTaskCompleter") approval_transfers_from ApprovalTransfer[] @relation("TransferFrom") approval_transfers_to ApprovalTransfer[] @relation("TransferTo") password_reset_codes PasswordResetCode[] email_login_codes EmailLoginCode[] lifecycle_events EmployeeLifecycleEvent[] checklist_tasks EmployeeChecklistTask[] portal_announcement_acknowledgements PortalAnnouncementAcknowledgement[] @relation("PortalAnnouncementAcknowledgementEmployee") portal_announcement_acknowledgement_actions PortalAnnouncementAcknowledgement[] @relation("PortalAnnouncementAcknowledgementActor") presence_records EmployeePresence[] attendance_records AttendanceRecord[] weekly_reports WeeklyReport[] todo_items_assigned TodoItem[] @relation("TodoAssignee") todo_items_created TodoItem[] @relation("TodoCreator") wecom_identity_binding WecomIdentityBinding? owned_projects Project[] @relation("ProjectOwner") managed_projects Project[] @relation("ProjectManager") project_memberships ProjectMember[] owned_project_milestones ProjectMilestone[] @relation("ProjectMilestoneOwner") assigned_project_tasks ProjectTask[] @relation("ProjectTaskAssignee") created_project_tasks ProjectTask[] @relation("ProjectTaskCreator") owned_project_risks ProjectRisk[] @relation("ProjectRiskOwner") owned_project_delivery_records ProjectDeliveryRecord[] @relation("ProjectDeliveryRecordOwner") created_project_communication_logs ProjectCommunicationLog[] @relation("ProjectCommunicationLogCreator") completed_project_closure_checklists ProjectClosureChecklistItem[] @relation("ProjectClosureChecklistItemCompleter") owned_contract_registries ContractRegistry[] @relation("ContractRegistryOwner") terminated_contract_registries ContractRegistry[] @relation("ContractRegistryTerminator") owned_confidential_document_refs ConfidentialDocumentRef[] @relation("ConfidentialDocumentRefOwner") contracts EmployeeContract[] trainings EmployeeTraining[] certificates EmployeeCertificate[] salary_profiles EmployeeSalary[] payslips Payslip[] performance_reviews_received PerformanceReview[] @relation("PerformanceReviewEmployee") performance_reviews_authored PerformanceReview[] @relation("PerformanceReviewReviewer") @@index([department_id]) @@index([legal_entity_id], map: "idx_employees_legal_entity") @@index([bank_institution_id], map: "idx_employees_bank_institution") @@index([direct_manager_id]) loan_lender_identities LoanLender[] loan_evidence_uploads LoanEvidence[] loan_receipt_attributions_proposed LoanReceiptAttribution[] @relation("LoanReceiptAttributionProposer") loan_receipt_attributions_reviewed LoanReceiptAttribution[] @relation("LoanReceiptAttributionReviewer") payment_order_exports_made PaymentOrderExport[] loan_bank_submissions_registered LoanBankSubmission[] loan_submission_attestations_proposed LoanBankSubmissionAttestation[] @relation("LoanSubmissionAttestationProposer") loan_submission_attestations_reviewed LoanBankSubmissionAttestation[] @relation("LoanSubmissionAttestationReviewer") loan_terminal_evidences_uploaded LoanBankTerminalEvidence[] loan_terminal_facts_proposed LoanBankTerminalFact[] @relation("LoanTerminalFactProposer") loan_terminal_facts_reviewed LoanBankTerminalFact[] @relation("LoanTerminalFactReviewer") @@map("employees") loan_recoveries_started LoanReleaseRecovery[] @relation("LoanReleaseStarter") loan_recoveries_submitted LoanReleaseRecovery[] @relation("LoanReleaseSubmitter") loan_recoveries_reviewed LoanReleaseRecovery[] @relation("LoanReleaseReviewer") loan_recoveries_consumed LoanReleaseRecovery[] @relation("LoanReleaseConsumer") loan_recovery_events LoanReleaseRecoveryEvent[] loan_not_submitted_proposals LoanNotSubmittedProposal[] loan_not_submitted_reviews LoanNotSubmittedReview[] loan_freezes_created LoanFreezeReason[] @relation("LoanFreezeCreator") loan_freezes_closed LoanFreezeReason[] @relation("LoanFreezeCloser") loan_bank_events_proposed LoanBankResultEvent[] @relation("LoanBankEventProposer") loan_bank_events_reviewed LoanBankResultEvent[] @relation("LoanBankEventReviewer") } model PasswordResetCode { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid code_hash String expires_at DateTime used_at DateTime? invalidated_at DateTime? attempts_count Int @default(0) created_at DateTime @default(now()) created_ip String? created_user_agent String? employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) @@index([employee_id, created_at]) @@index([employee_id, invalidated_at, created_at]) @@index([expires_at]) @@map("password_reset_codes") } model EmailLoginCode { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid code_hash String expires_at DateTime used_at DateTime? attempts_count Int @default(0) created_at DateTime @default(now()) created_ip String? created_user_agent String? employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) @@index([employee_id, created_at]) @@index([expires_at]) @@map("email_login_codes") } model EmployeeRole { employee_id String @db.Uuid role_code RoleCode created_at DateTime @default(now()) created_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) @@id([employee_id, role_code]) @@map("employee_roles") } model DelegationGrant { id String @id @default(uuid()) @db.Uuid principal_employee_id String @db.Uuid delegate_employee_id String @db.Uuid scope DelegationGrantScope valid_from DateTime @default(now()) valid_to DateTime? revoked_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid principal_employee Employee @relation("DelegationPrincipal", fields: [principal_employee_id], references: [id], onDelete: Restrict) delegate_employee Employee @relation("DelegationDelegate", fields: [delegate_employee_id], references: [id], onDelete: Restrict) @@index([principal_employee_id]) @@index([delegate_employee_id]) @@map("delegation_grants") } model AuthSession { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid refresh_token_hash String device_fingerprint String ip_address String user_agent String created_at DateTime @default(now()) last_seen_at DateTime @default(now()) expires_at DateTime revoked_at DateTime? employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([employee_id]) @@index([expires_at]) @@index([revoked_at]) @@map("auth_sessions") } model AuditLog { id String @id @default(uuid()) @db.Uuid request_id String actor_id String @db.Uuid action String target_type String target_id String? @db.Uuid ip_address String? user_agent String? extra Json created_at DateTime @default(now()) actor Employee @relation("AuditActor", fields: [actor_id], references: [id], onDelete: Restrict) @@index([request_id]) @@index([actor_id, created_at]) @@index([created_at, actor_id, action], map: "idx_audit_logs_query") @@index([target_type, created_at], map: "idx_audit_logs_target_type_created_at") @@map("audit_logs") } model Notification { id String @id @default(uuid()) @db.Uuid recipient_employee_id String @db.Uuid type String @db.VarChar(64) title String @db.VarChar(200) body String? target_type String? @db.VarChar(64) target_id String? @db.Uuid read_at DateTime? created_at DateTime @default(now()) recipient Employee @relation(fields: [recipient_employee_id], references: [id], onDelete: Cascade) deliveries NotificationDelivery[] @@index([recipient_employee_id, created_at]) @@index([recipient_employee_id, read_at, created_at], map: "idx_notifications_unread_query") @@map("notifications") } model NotificationDelivery { id String @id @default(uuid()) @db.Uuid notification_id String @db.Uuid channel_id String @db.Uuid status NotificationDeliveryStatus attempt_no Int result_code String? @db.VarChar(64) error_message String? response_body Json? attempted_at DateTime @default(now()) notification Notification @relation(fields: [notification_id], references: [id], onDelete: Cascade) channel NotificationChannel @relation(fields: [channel_id], references: [id], onDelete: Cascade) @@index([notification_id, attempted_at], map: "idx_notification_deliveries_notification_attempted") @@index([channel_id, attempted_at], map: "idx_notification_deliveries_channel_attempted") @@index([status, attempted_at], map: "idx_notification_deliveries_status_attempted") @@map("notification_deliveries") } model ExpenseType { id String @id @default(uuid()) @db.Uuid code String @unique name String description String? category ExpenseCategory sort_order Int account_code_default String? requires_invoice Boolean @default(true) is_system_default Boolean @default(false) enabled Boolean @default(true) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid standards ExpenseStandard[] reimbursement_items ReimbursementItem[] @@index([enabled, sort_order]) @@map("expense_types") } model ExpenseStandard { id String @id @default(uuid()) @db.Uuid expense_type_id String @db.Uuid name String @db.VarChar(100) max_amount Decimal @db.Decimal(14, 2) per_unit String @default("item") @db.VarChar(20) control_mode String @default("warn") @db.VarChar(16) scope_type String @default("global") @db.VarChar(32) scope_key String? @db.Uuid enabled Boolean @default(true) note String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid expense_type ExpenseType @relation(fields: [expense_type_id], references: [id], onDelete: Restrict) @@index([enabled, expense_type_id], map: "idx_expense_standards_enabled_type") @@map("expense_standards") } model ReimbursementTemplate { id String @id @default(uuid()) @db.Uuid name String @db.VarChar(100) description String? items Json @default("[]") sort_order Int @default(0) enabled Boolean @default(true) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@index([enabled, sort_order]) @@map("reimbursement_templates") } // Absent policy means legacy numbering. Migration never activates v2. model BusinessNumberPolicy { version Int @id effective_at DateTime enabled Boolean @default(false) updated_at DateTime @default(now()) @updatedAt updated_by String @db.Uuid reference String @@map("business_number_policies") } model BusinessNumberCounter { key String @id current_number BigInt @default(0) updated_at DateTime @default(now()) @updatedAt @@map("business_number_counters") } model DocumentSequence { document_type String @id prefix String date_format String separator String number_length Int @default(4) reset_period DocumentResetPeriod current_number Int @default(0) last_reset_date DateTime? updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@map("document_sequences") } model LegalEntity { id String @id @default(uuid()) @db.Uuid code String @unique name String short_name String? currency_code String @default("CNY") @db.VarChar(8) tax_no String? default_holiday_calendar_id String? @db.Uuid enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid default_holiday_calendar HolidayCalendar? @relation("LegalEntityDefaultHolidayCalendar", fields: [default_holiday_calendar_id], references: [id], onDelete: SetNull) cost_centers CostCenter[] employees Employee[] holiday_calendars HolidayCalendar[] @relation("HolidayCalendarLegalEntity") suppliers Supplier[] purchase_requests PurchaseRequest[] travel_requests TravelRequest[] travel_reconciliation_batches TravelReconciliationBatch[] card_authorizations CardAuthorization[] asset_cards AssetCard[] budget_pools BudgetPool[] @relation("BudgetPoolLegalEntity") payment_accounts PaymentAccount[] payment_batches PaymentBatch[] @@index([enabled, archived_at], map: "idx_legal_entities_status") @@index([default_holiday_calendar_id], map: "idx_legal_entities_default_calendar") loan_lenders LoanLender[] @@map("legal_entities") } model BankInstitution { id String @id @default(uuid()) @db.Uuid code String @unique @db.VarChar(16) name String @db.VarChar(100) enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employees Employee[] payment_accounts PaymentAccount[] @@index([enabled, archived_at], map: "idx_bank_institutions_status") loan_lenders LoanLender[] @@map("bank_institutions") } model PaymentAccount { id String @id @default(uuid()) @db.Uuid legal_entity_id String @db.Uuid bank_institution_id String @db.Uuid account_name String @db.VarChar(120) account_number_encrypted String enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) bank_institution BankInstitution @relation(fields: [bank_institution_id], references: [id], onDelete: Restrict) payment_batches PaymentBatch[] @@index([legal_entity_id, enabled, archived_at], map: "idx_payment_accounts_legal_entity_status") @@index([bank_institution_id], map: "idx_payment_accounts_bank_institution") @@map("payment_accounts") } model CostCenter { id String @id @default(uuid()) @db.Uuid legal_entity_id String @db.Uuid code String name String parent_id String? @db.Uuid owner_employee_id String? @db.Uuid enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) parent CostCenter? @relation("CostCenterToParent", fields: [parent_id], references: [id], onDelete: Restrict) children CostCenter[] @relation("CostCenterToParent") owner_employee Employee? @relation("CostCenterOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull) budget_pools BudgetPool[] @relation("BudgetPoolCostCenter") purchase_requests PurchaseRequest[] travel_requests TravelRequest[] travel_reconciliation_batches TravelReconciliationBatch[] card_authorizations CardAuthorization[] asset_cards AssetCard[] @@unique([legal_entity_id, code], map: "legal_entity_cost_center_code_ux") @@index([legal_entity_id, enabled, archived_at], map: "idx_cost_centers_legal_entity_status") @@index([parent_id], map: "idx_cost_centers_parent") @@index([owner_employee_id], map: "idx_cost_centers_owner") @@map("cost_centers") } model DocumentCategory { id String @id @default(uuid()) @db.Uuid code String @unique name String entity_type DocumentCategoryEntityType sequence_prefix String number_length Int @default(4) reset_period DocumentResetPeriod default_workflow_key String? enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid purchase_requests PurchaseRequest[] asset_categories AssetCategory[] @@index([entity_type, enabled, archived_at], map: "idx_document_categories_entity_status") @@map("document_categories") } model HolidayCalendar { id String @id @default(uuid()) @db.Uuid code String @unique name String timezone String @default("Asia/Shanghai") @db.VarChar(64) legal_entity_id String? @db.Uuid enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid legal_entity LegalEntity? @relation("HolidayCalendarLegalEntity", fields: [legal_entity_id], references: [id], onDelete: SetNull) days HolidayCalendarDay[] default_for_legal_entities LegalEntity[] @relation("LegalEntityDefaultHolidayCalendar") @@index([legal_entity_id, enabled, archived_at], map: "idx_holiday_calendars_legal_entity_status") @@map("holiday_calendars") } model HolidayCalendarDay { id String @id @default(uuid()) @db.Uuid calendar_id String @db.Uuid date DateTime @db.Date day_type HolidayCalendarDayType name String note String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid calendar HolidayCalendar @relation(fields: [calendar_id], references: [id], onDelete: Cascade) @@unique([calendar_id, date], map: "holiday_calendar_day_ux") @@index([calendar_id, date], map: "idx_holiday_calendar_days_calendar_date") @@map("holiday_calendar_days") } model Supplier { id String @id @default(uuid()) @db.Uuid code String @unique name String short_name String? tax_no String? contact_name String? contact_phone String? payment_terms String? legal_entity_id String? @db.Uuid enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid legal_entity LegalEntity? @relation(fields: [legal_entity_id], references: [id], onDelete: SetNull) purchase_requests PurchaseRequest[] @@index([legal_entity_id, enabled, archived_at], map: "idx_suppliers_legal_entity_status") @@index([name], map: "idx_suppliers_name") @@map("suppliers") } model PurchaseRequest { numbering_version Int @default(1) id String @id @default(uuid()) @db.Uuid request_no String? @unique applicant_id String @db.Uuid submitter_id String? @db.Uuid department_id String @db.Uuid legal_entity_id String? @db.Uuid cost_center_id String? @db.Uuid supplier_id String? @db.Uuid document_category_id String? @db.Uuid budget_pool_id String? @db.Uuid project_id String? @db.Uuid title String @default("") reason String? currency_code String @default("CNY") @db.VarChar(8) total_amount Decimal @default(0) @db.Decimal(14, 2) expected_delivery_date DateTime? @db.Date status PurchaseRequestStatus @default(draft) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid applicant Employee @relation("PurchaseRequestApplicant", fields: [applicant_id], references: [id], onDelete: Restrict) submitter Employee? @relation("PurchaseRequestSubmitter", fields: [submitter_id], references: [id], onDelete: SetNull) department Department @relation(fields: [department_id], references: [id], onDelete: Restrict) legal_entity LegalEntity? @relation(fields: [legal_entity_id], references: [id], onDelete: SetNull) cost_center CostCenter? @relation(fields: [cost_center_id], references: [id], onDelete: SetNull) supplier Supplier? @relation(fields: [supplier_id], references: [id], onDelete: SetNull) document_category DocumentCategory? @relation(fields: [document_category_id], references: [id], onDelete: SetNull) budget_pool BudgetPool? @relation(fields: [budget_pool_id], references: [id], onDelete: SetNull) project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) items PurchaseRequestItem[] attachments PurchaseAttachment[] order_archive PurchaseOrderArchive? asset_cards AssetCard[] workflow_instances WorkflowInstance[] @@index([applicant_id, status, updated_at], map: "idx_purchase_requests_applicant_status_updated") @@index([submitter_id], map: "idx_purchase_requests_submitter") @@index([department_id], map: "idx_purchase_requests_department") @@index([legal_entity_id], map: "idx_purchase_requests_legal_entity") @@index([cost_center_id], map: "idx_purchase_requests_cost_center") @@index([supplier_id], map: "idx_purchase_requests_supplier") @@index([document_category_id], map: "idx_purchase_requests_document_category") @@index([budget_pool_id], map: "idx_purchase_requests_budget_pool") @@index([project_id], map: "idx_purchase_requests_project") @@index([status], map: "idx_purchase_requests_status") @@map("purchase_requests") } model PurchaseRequestItem { id String @id @default(uuid()) @db.Uuid purchase_request_id String @db.Uuid description String specification String? quantity Decimal @db.Decimal(14, 2) unit_price Decimal @db.Decimal(14, 2) line_amount Decimal @db.Decimal(14, 2) is_asset_candidate Boolean @default(false) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid purchase_request PurchaseRequest @relation(fields: [purchase_request_id], references: [id], onDelete: Cascade) @@index([purchase_request_id], map: "idx_purchase_request_items_request") @@map("purchase_request_items") } model PurchaseAttachment { id String @id @default(uuid()) @db.Uuid purchase_request_id String @db.Uuid storage_path String original_name String mime_type String file_size Int file_sha256 String? uploaded_by String @db.Uuid created_at DateTime @default(now()) governance_status String @default("approved") @db.VarChar(32) sensitivity_level String @default("internal") @db.VarChar(32) attachment_type String @default("other") @db.VarChar(64) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? archived_by String? @db.Uuid archived_at DateTime? archive_note String? download_policy String @default("standard") @db.VarChar(32) purchase_request PurchaseRequest @relation(fields: [purchase_request_id], references: [id], onDelete: Cascade) uploader Employee @relation("PurchaseAttachmentUploader", fields: [uploaded_by], references: [id], onDelete: Restrict) @@index([purchase_request_id, created_at], map: "idx_purchase_attachments_request_created") @@index([uploaded_by], map: "idx_purchase_attachments_uploader") @@index([file_sha256], map: "idx_purchase_attachments_file_sha256") @@index([governance_status], map: "idx_purchase_attachments_governance_status") @@index([sensitivity_level], map: "idx_purchase_attachments_sensitivity_level") @@map("purchase_attachments") } model PurchaseOrderArchive { id String @id @default(uuid()) @db.Uuid purchase_request_id String @unique @db.Uuid po_no String contract_no String? archived_files Json? archived_at DateTime @default(now()) archived_by String @db.Uuid purchase_request PurchaseRequest @relation(fields: [purchase_request_id], references: [id], onDelete: Cascade) archived_by_employee Employee @relation("PurchaseOrderArchiveArchivedBy", fields: [archived_by], references: [id], onDelete: Restrict) @@index([archived_by], map: "idx_purchase_order_archives_archived_by") @@index([archived_at], map: "idx_purchase_order_archives_archived_at") @@map("purchase_order_archives") } model AssetCategory { id String @id @default(uuid()) @db.Uuid code String @unique name String document_category_id String? @db.Uuid enabled Boolean @default(true) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid document_category DocumentCategory? @relation(fields: [document_category_id], references: [id], onDelete: SetNull) asset_cards AssetCard[] @@index([enabled, archived_at], map: "idx_asset_categories_status") @@index([document_category_id], map: "idx_asset_categories_document_category") @@map("asset_categories") } model AssetCard { id String @id @default(uuid()) @db.Uuid asset_no String @unique name String asset_type AssetType @default(fixed_asset) sensitivity_level AssetSensitivityLevel @default(internal) category_id String @db.Uuid legal_entity_id String @db.Uuid cost_center_id String @db.Uuid purchase_request_id String? @db.Uuid serial_no String? location String? status AssetCardStatus @default(in_stock) assignee_employee_id String? @db.Uuid owner_employee_id String? @db.Uuid keeper_employee_id String? @db.Uuid archive_location String? external_ref String? source_hash String? verification_no String? @unique confidentiality_note String? metadata Json? last_verified_at DateTime? @db.Date expires_at DateTime? @db.Date activated_at DateTime? @db.Date retired_at DateTime? @db.Date created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid category AssetCategory @relation(fields: [category_id], references: [id], onDelete: Restrict) legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) cost_center CostCenter @relation(fields: [cost_center_id], references: [id], onDelete: Restrict) purchase_request PurchaseRequest? @relation(fields: [purchase_request_id], references: [id], onDelete: SetNull) assignee Employee? @relation("AssetCardAssignee", fields: [assignee_employee_id], references: [id], onDelete: SetNull) owner Employee? @relation("AssetCardOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull) keeper Employee? @relation("AssetCardKeeper", fields: [keeper_employee_id], references: [id], onDelete: SetNull) assignments AssetAssignment[] transfers AssetTransfer[] inventory_items InventoryCheckItem[] @@index([asset_type], map: "idx_asset_cards_asset_type") @@index([sensitivity_level], map: "idx_asset_cards_sensitivity") @@index([category_id], map: "idx_asset_cards_category") @@index([legal_entity_id], map: "idx_asset_cards_legal_entity") @@index([cost_center_id], map: "idx_asset_cards_cost_center") @@index([purchase_request_id], map: "idx_asset_cards_purchase_request") @@index([assignee_employee_id], map: "idx_asset_cards_assignee") @@index([owner_employee_id], map: "idx_asset_cards_owner") @@index([keeper_employee_id], map: "idx_asset_cards_keeper") @@index([source_hash], map: "idx_asset_cards_source_hash") @@index([last_verified_at], map: "idx_asset_cards_last_verified") @@index([status], map: "idx_asset_cards_status") @@map("asset_cards") } model AssetAssignment { id String @id @default(uuid()) @db.Uuid asset_id String @db.Uuid employee_id String @db.Uuid assigned_at DateTime @default(now()) returned_at DateTime? note String? asset AssetCard @relation(fields: [asset_id], references: [id], onDelete: Cascade) employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) @@index([asset_id, returned_at], map: "idx_asset_assignments_asset_open") @@index([employee_id, returned_at], map: "idx_asset_assignments_employee_open") @@map("asset_assignments") } model AssetTransfer { id String @id @default(uuid()) @db.Uuid asset_id String @db.Uuid from_employee_id String? @db.Uuid to_employee_id String? @db.Uuid from_location String? to_location String? transferred_at DateTime @default(now()) note String? asset AssetCard @relation(fields: [asset_id], references: [id], onDelete: Cascade) from_employee Employee? @relation("AssetTransferFromEmployee", fields: [from_employee_id], references: [id], onDelete: SetNull) to_employee Employee? @relation("AssetTransferToEmployee", fields: [to_employee_id], references: [id], onDelete: SetNull) @@index([asset_id, transferred_at], map: "idx_asset_transfers_asset_time") @@index([from_employee_id], map: "idx_asset_transfers_from_employee") @@index([to_employee_id], map: "idx_asset_transfers_to_employee") @@map("asset_transfers") } model InventoryCheck { id String @id @default(uuid()) @db.Uuid check_no String @unique scope_type InventoryCheckScopeType scope_ref_id String? @db.VarChar(200) status InventoryCheckStatus @default(draft) started_at DateTime? completed_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid items InventoryCheckItem[] @@index([status, created_at], map: "idx_inventory_checks_status_created") @@index([scope_type, scope_ref_id], map: "idx_inventory_checks_scope") @@map("inventory_checks") } model InventoryCheckItem { id String @id @default(uuid()) @db.Uuid inventory_check_id String @db.Uuid asset_id String @db.Uuid result InventoryCheckResult note String? inventory_check InventoryCheck @relation(fields: [inventory_check_id], references: [id], onDelete: Cascade) asset AssetCard @relation(fields: [asset_id], references: [id], onDelete: Restrict) @@unique([inventory_check_id, asset_id], map: "inventory_check_asset_ux") @@index([asset_id], map: "idx_inventory_check_items_asset") @@map("inventory_check_items") } model ReimbursementForm { deleted_at DateTime? deleted_by String? @db.Uuid deleted_by_employee Employee? @relation("ReimbursementDeletedBy", fields: [deleted_by], references: [id], onDelete: Restrict) id String @id @default(uuid()) @db.Uuid form_number String? @unique submitter_id String @db.Uuid owner_id String @db.Uuid department_id String @db.Uuid reimbursement_date DateTime @db.Date total_amount Decimal @default(0) @db.Decimal(14, 2) status ReimbursementStatus @default(draft) description String? payment_voucher_no String? @db.VarChar(50) payment_date DateTime? @db.Date payment_channel String? @db.VarChar(20) paid_at DateTime? paid_by String? @db.Uuid project_id String? @db.Uuid linked_travel_request_id String? @db.Uuid travel_purpose String? @db.VarChar(200) travel_location String? @db.VarChar(200) travel_start_date DateTime? @db.Date travel_end_date DateTime? @db.Date created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid submitter Employee @relation("ReimbursementSubmitter", fields: [submitter_id], references: [id], onDelete: Restrict) owner Employee @relation("ReimbursementOwner", fields: [owner_id], references: [id], onDelete: Restrict) paid_by_employee Employee? @relation("ReimbursementPaidBy", fields: [paid_by], references: [id], onDelete: SetNull) department Department @relation(fields: [department_id], references: [id], onDelete: Restrict) project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) travel_request TravelRequest? @relation(fields: [linked_travel_request_id], references: [id], onDelete: SetNull) items ReimbursementItem[] attachments ReimbursementAttachment[] invoice_pool_items InvoicePool[] workflow_instances WorkflowInstance[] approval_transfers ApprovalTransfer[] budget_ledger_entries BudgetLedgerEntry[] travel_orders TravelOrder[] @@index([owner_id]) @@index([submitter_id]) @@index([department_id]) @@index([paid_by]) @@index([project_id], map: "idx_reimbursement_forms_project") @@index([linked_travel_request_id], map: "idx_reimbursement_forms_linked_travel_request") @@index([status]) @@index([reimbursement_date]) @@index([owner_id, status, updated_at], map: "idx_reimbursement_owner_status_updated_at") @@index([deleted_at], map: "idx_reimbursement_forms_deleted_at") @@map("reimbursement_forms") } model ReimbursementItem { id String @id @default(uuid()) @db.Uuid reimbursement_id String @db.Uuid expense_type_id String? @db.Uuid expense_date DateTime @db.Date amount Decimal @db.Decimal(14, 2) description String asset_prior_approval_basis String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid reimbursement_form ReimbursementForm @relation(fields: [reimbursement_id], references: [id], onDelete: Cascade) expense_type ExpenseType? @relation(fields: [expense_type_id], references: [id], onDelete: Restrict) invoice_pool_items InvoicePool[] @@index([reimbursement_id]) @@index([expense_type_id]) @@index([expense_date]) @@map("reimbursement_items") } model ReimbursementAttachment { id String @id @default(uuid()) @db.Uuid reimbursement_id String @db.Uuid storage_path String original_name String mime_type String file_size Int file_sha256 String uploaded_by String @db.Uuid created_at DateTime @default(now()) governance_status String @default("approved") @db.VarChar(32) sensitivity_level String @default("internal") @db.VarChar(32) attachment_type String @default("supporting_material") @db.VarChar(64) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? archived_by String? @db.Uuid archived_at DateTime? archive_note String? download_policy String @default("standard") @db.VarChar(32) reimbursement_form ReimbursementForm @relation(fields: [reimbursement_id], references: [id], onDelete: Cascade) uploader Employee @relation("ReimbursementAttachmentUploader", fields: [uploaded_by], references: [id], onDelete: Restrict) @@index([reimbursement_id, created_at], map: "idx_reimbursement_attachments_form_created") @@index([uploaded_by], map: "idx_reimbursement_attachments_uploader") @@index([file_sha256], map: "idx_reimbursement_attachments_file_sha256") @@index([governance_status], map: "idx_reimbursement_attachments_governance_status") @@index([sensitivity_level], map: "idx_reimbursement_attachments_sensitivity_level") @@map("reimbursement_attachments") } model LeaveType { id String @id @default(uuid()) @db.Uuid code String @unique name String description String? enabled Boolean @default(true) requires_attachment Boolean @default(false) attachment_mime_types Json? sort_order Int @default(100) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid leave_policy LeavePolicy? leave_requests LeaveRequest[] leave_ledgers LeaveLedger[] @@index([enabled, sort_order], map: "idx_leave_types_enabled_sort_order") @@map("leave_types") } model LeavePolicy { id String @id @default(uuid()) @db.Uuid leave_type_id String @unique @db.Uuid annual_quota_days Decimal @db.Decimal(8, 1) enabled Boolean @default(true) description String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid leave_type LeaveType @relation(fields: [leave_type_id], references: [id], onDelete: Cascade) leave_ledgers LeaveLedger[] @@index([enabled], map: "idx_leave_policies_enabled") @@map("leave_policies") } model LeaveRequest { id String @id @default(uuid()) @db.Uuid owner_id String @db.Uuid department_id String @db.Uuid leave_type_id String @db.Uuid start_date DateTime @db.Date end_date DateTime @db.Date start_session LeaveDaySession @default(am) end_session LeaveDaySession @default(pm) requested_days Decimal @db.Decimal(8, 1) reason String? attachment_storage_path String? attachment_original_name String? attachment_mime_type String? status LeaveRequestStatus @default(draft) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid owner Employee @relation(fields: [owner_id], references: [id], onDelete: Restrict) department Department @relation(fields: [department_id], references: [id], onDelete: Restrict) leave_type LeaveType @relation(fields: [leave_type_id], references: [id], onDelete: Restrict) leave_ledgers LeaveLedger[] workflow_instances WorkflowInstance[] @@index([owner_id]) @@index([department_id]) @@index([leave_type_id]) @@index([status]) @@index([owner_id, status, updated_at], map: "idx_leave_owner_status_updated_at") @@index([owner_id, start_date, end_date], map: "idx_leave_owner_date_range") @@map("leave_requests") } model LeaveLedger { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid leave_type_id String @db.Uuid leave_policy_id String? @db.Uuid leave_request_id String? @db.Uuid entry_type LeaveLedgerEntryType days Decimal @db.Decimal(8, 1) period_start DateTime? @db.Date period_end DateTime? @db.Date note String? payload Json? created_at DateTime @default(now()) created_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) leave_type LeaveType @relation(fields: [leave_type_id], references: [id], onDelete: Restrict) leave_policy LeavePolicy? @relation(fields: [leave_policy_id], references: [id], onDelete: SetNull) leave_request LeaveRequest? @relation(fields: [leave_request_id], references: [id], onDelete: SetNull) @@index([employee_id, leave_type_id, created_at], map: "idx_leave_ledger_employee_type_created_at") @@index([leave_request_id]) @@index([period_start, period_end], map: "idx_leave_ledger_period") @@index([entry_type, employee_id], map: "idx_leave_ledger_entry_employee") @@map("leave_ledgers") } model OcrResult { id String @id @default(uuid()) @db.Uuid file_sha256 String ocr_provider OcrProvider @default(tencent) ocr_type OcrType result_json Json confidence Int? created_at DateTime @default(now()) invoice_pool_items InvoicePool[] @@unique([file_sha256, ocr_provider, ocr_type]) @@index([file_sha256]) @@map("ocr_results") } model InvoicePool { id String @id @default(uuid()) @db.Uuid owner_employee_id String @db.Uuid uploaded_by_employee_id String @db.Uuid storage_path String original_name String mime_type String file_size Int file_sha256 String status InvoicePoolStatus @default(pending_ocr) archived_reason InvoiceArchivedReason? archived_at DateTime? linked_reimbursement_id String? @db.Uuid linked_item_id String? @db.Uuid travel_order_id String? @db.Uuid remarks String? ocr_provider OcrProvider @default(tencent) ocr_type OcrType @default(general) ocr_result_id String? @db.Uuid ocr_attempts Int @default(0) ocr_last_requested_at DateTime? ocr_last_error String? ocr_completed_at DateTime? ocr_locked_at DateTime? ocr_lock_owner String? @db.VarChar(128) invoice_code String? invoice_number String? invoice_date DateTime? @db.Date seller_name String? buyer_name String? amount Decimal? @db.Decimal(14, 2) tax_amount Decimal? @db.Decimal(14, 2) total_amount Decimal? @db.Decimal(14, 2) is_duplicate_override Boolean @default(false) override_ref_form_number String? override_reason String? overridden_by String? @db.Uuid created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid owner_employee Employee @relation("InvoiceOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict) uploaded_by_employee Employee @relation("InvoiceUploader", fields: [uploaded_by_employee_id], references: [id], onDelete: Restrict) overridden_by_employee Employee? @relation("InvoiceOverrideBy", fields: [overridden_by], references: [id], onDelete: Restrict) ocr_result OcrResult? @relation(fields: [ocr_result_id], references: [id], onDelete: SetNull) linked_reimbursement ReimbursementForm? @relation(fields: [linked_reimbursement_id], references: [id], onDelete: SetNull) linked_item ReimbursementItem? @relation(fields: [linked_item_id], references: [id], onDelete: SetNull) travel_order TravelOrder? @relation(fields: [travel_order_id], references: [id], onDelete: SetNull) verification_records InvoiceVerificationRecord[] @@index([owner_employee_id]) @@index([uploaded_by_employee_id]) @@index([file_sha256]) @@index([invoice_code, invoice_number]) @@index([status]) @@index([status, ocr_locked_at, created_at], map: "idx_invoice_pool_ocr_queue") @@index([owner_employee_id, status, created_at], map: "idx_invoice_pool_owner_status_created_at") @@index([linked_reimbursement_id]) @@index([travel_order_id]) @@map("invoice_pool") } model InvoiceVerificationRecord { id String @id @default(uuid()) @db.Uuid invoice_id String @db.Uuid provider String @db.VarChar(32) status String @db.VarChar(16) request_payload Json? result_payload Json? result_code String? @db.VarChar(64) result_message String? error_code String? @db.VarChar(64) error_message String? duration_ms Int? requested_by String? @db.Uuid requested_at DateTime @default(now()) completed_at DateTime? retry_of_id String? @db.Uuid attempts Int @default(1) created_at DateTime @default(now()) updated_at DateTime @updatedAt invoice InvoicePool @relation(fields: [invoice_id], references: [id], onDelete: Cascade) requester Employee? @relation("InvoiceVerificationRequester", fields: [requested_by], references: [id], onDelete: SetNull) retry_of InvoiceVerificationRecord? @relation("InvoiceVerificationRetry", fields: [retry_of_id], references: [id], onDelete: SetNull) retries InvoiceVerificationRecord[] @relation("InvoiceVerificationRetry") @@index([invoice_id, created_at], map: "idx_invoice_verification_invoice_created_at") @@index([status, requested_at], map: "idx_invoice_verification_status_requested_at") @@index([requested_by]) @@map("invoice_verification_records") } model BudgetPool { id String @id @default(uuid()) @db.Uuid code String @unique name String department_id String? @db.Uuid legal_entity_id String? @db.Uuid cost_center_id String? @db.Uuid status String @default("active") @db.VarChar(16) period_start DateTime @db.Date period_end DateTime @db.Date allocated_amount Decimal @db.Decimal(14, 2) used_amount Decimal @default(0) @db.Decimal(14, 2) warning_threshold_percent Int @default(80) archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull) legal_entity LegalEntity? @relation("BudgetPoolLegalEntity", fields: [legal_entity_id], references: [id], onDelete: SetNull) cost_center CostCenter? @relation("BudgetPoolCostCenter", fields: [cost_center_id], references: [id], onDelete: SetNull) ledger_entries BudgetLedgerEntry[] purchase_requests PurchaseRequest[] travel_requests TravelRequest[] card_authorizations CardAuthorization[] @@index([department_id, status], map: "idx_budget_pools_department_status") @@index([legal_entity_id, cost_center_id, status], map: "idx_budget_pools_scope_status") @@index([status, period_start, period_end], map: "idx_budget_pools_period") @@map("budget_pools") } model BudgetLedgerEntry { id String @id @default(uuid()) @db.Uuid budget_pool_id String @db.Uuid reimbursement_id String? @db.Uuid entity_type String? @db.VarChar(32) entity_id String? @db.Uuid kind String @db.VarChar(32) amount Decimal @db.Decimal(14, 2) note String? created_at DateTime @default(now()) created_by String? @db.Uuid budget_pool BudgetPool @relation(fields: [budget_pool_id], references: [id], onDelete: Cascade) reimbursement_form ReimbursementForm? @relation(fields: [reimbursement_id], references: [id], onDelete: SetNull) @@index([budget_pool_id, created_at], map: "idx_budget_ledger_pool_created_at") @@index([reimbursement_id]) @@index([entity_type, entity_id], map: "idx_budget_ledger_entity") @@map("budget_ledger_entries") } model FeatureFlag { id String @id @default(uuid()) @db.Uuid flag_key String @unique @db.VarChar(64) override_mode String @default("force_off") @db.VarChar(16) rollout_type String @default("global") @db.VarChar(32) department_ids Json? note String? version Int @default(1) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@index([flag_key], map: "idx_feature_flags_key") @@map("feature_flags") } model BudgetControlRule { id String @id @default(uuid()) @db.Uuid name String entity_type BudgetControlRuleEntityType @default(all) department_id String? @db.Uuid legal_entity_id String? @db.Uuid cost_center_id String? @db.Uuid expense_type_id String? @db.Uuid control_mode BudgetControlMode priority Int @default(100) enabled Boolean @default(true) notes String? archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@index([entity_type, enabled, archived_at], map: "idx_budget_control_rules_entity_enabled") @@index([department_id, legal_entity_id, cost_center_id], map: "idx_budget_control_rules_scope") @@index([expense_type_id], map: "idx_budget_control_rules_expense_type") @@map("budget_control_rules") } model EntityRiskFlag { id String @id @default(uuid()) @db.Uuid entity_type String @db.VarChar(32) entity_id String @db.Uuid risk_code String @db.VarChar(64) level String @db.VarChar(16) title String detail String? source String @db.VarChar(32) status RiskFlagStatus @default(open) payload_json Json? created_at DateTime @default(now()) created_by String? @db.Uuid resolved_at DateTime? resolved_by String? @db.Uuid @@index([entity_type, entity_id, status], map: "idx_entity_risk_flags_entity_status") @@index([status, source, created_at], map: "idx_entity_risk_flags_status_source_created") @@map("entity_risk_flags") } model PaymentBatch { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? loan_repayment_id String? @db.Uuid loan_repayment LoanRepayment? @relation(fields: [loan_repayment_id], references: [id], onDelete: Restrict) id String @id @default(uuid()) @db.Uuid batch_no String @unique @db.VarChar(64) entity_type PaymentBatchEntityType name String status PaymentBatchStatus @default(draft) default_payment_date DateTime? @db.Date default_payment_channel String? @db.VarChar(20) voucher_prefix String? @db.VarChar(32) review_comment String? secondary_review_comment String? execution_summary_json Json? legal_entity_id String? @db.Uuid payment_account_id String? @db.Uuid payment_account_snapshot_json Json? payment_order_export_count Int @default(0) payment_order_last_exported_at DateTime? payment_order_last_exported_by String? @db.Uuid created_at DateTime @default(now()) created_by String? @db.Uuid reviewed_at DateTime? reviewed_by String? @db.Uuid secondary_reviewed_at DateTime? secondary_reviewed_by String? @db.Uuid executed_at DateTime? executed_by String? @db.Uuid cancelled_at DateTime? cancelled_by String? @db.Uuid cancelled_reason String? updated_at DateTime @updatedAt updated_by String? @db.Uuid items PaymentBatchItem[] receipt_attachments PaymentBatchReceiptAttachment[] legal_entity LegalEntity? @relation(fields: [legal_entity_id], references: [id], onDelete: SetNull) payment_account PaymentAccount? @relation(fields: [payment_account_id], references: [id], onDelete: SetNull) payment_order_last_exported_by_employee Employee? @relation("PaymentOrderLastExportedBy", fields: [payment_order_last_exported_by], references: [id], onDelete: SetNull) @@index([entity_type, status, created_at], map: "idx_payment_batches_entity_status_created") @@index([legal_entity_id], map: "idx_payment_batches_legal_entity") @@index([payment_account_id], map: "idx_payment_batches_payment_account") @@index([payment_order_last_exported_by], map: "idx_payment_batches_order_exported_by") loan_receipt_attributions LoanReceiptAttribution[] payment_order_exports PaymentOrderExport[] loan_legacy_export_summary LoanLegacyExportSummary? loan_bank_submissions LoanBankSubmission[] loan_bank_submission_attestations LoanBankSubmissionAttestation[] loan_terminal_evidences LoanBankTerminalEvidence[] loan_terminal_facts LoanBankTerminalFact[] loan_failure_evidence_uses LoanFailureEvidenceUse[] @@map("payment_batches") loan_release_recoveries LoanReleaseRecovery[] loan_freeze_reasons LoanFreezeReason[] loan_bank_result_events LoanBankResultEvent[] loan_not_submitted_proposals LoanNotSubmittedProposal[] loan_material_revision LoanReleaseMaterialRevision? } model PaymentBatchItem { id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid entity_id String @db.Uuid entity_code String entity_title String amount Decimal @db.Decimal(14, 2) currency_code String @default("CNY") @db.VarChar(8) payment_voucher_no_override String? @db.VarChar(50) payment_date_override DateTime? @db.Date payment_channel_override String? @db.VarChar(20) status String @default("pending") @db.VarChar(16) failure_code String? @db.VarChar(64) failure_message String? snapshot_json Json created_at DateTime @default(now()) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Cascade) @@index([payment_batch_id, status], map: "idx_payment_batch_items_batch_status") receipt_matches PaymentReceiptMatch[] receipt_claim PaymentReceiptClaim? @@index([entity_id], map: "idx_payment_batch_items_entity_id") @@map("payment_batch_items") } model PaymentBatchReceiptAttachment { id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid storage_path String original_name String mime_type String file_size Int file_sha256 String uploaded_by String @db.Uuid created_at DateTime @default(now()) governance_status String @default("approved") @db.VarChar(32) sensitivity_level String @default("confidential") @db.VarChar(32) attachment_type String @default("receipt") @db.VarChar(64) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? archived_by String? @db.Uuid archived_at DateTime? archive_note String? download_policy String @default("reason_required") @db.VarChar(32) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Cascade) uploader Employee @relation("PaymentBatchReceiptAttachmentUploader", fields: [uploaded_by], references: [id], onDelete: Restrict) verifications PaymentReceiptVerification[] manual_proposals PaymentReceiptManualProposal[] receipt_ocr_version Int @default(0) receipt_ocr_state String @default("legacy") @db.VarChar(32) receipt_ocr_started_at DateTime? loan_terminal_facts LoanBankTerminalFact[] @@index([payment_batch_id, created_at], map: "idx_payment_batch_receipts_batch_created") @@index([uploaded_by], map: "idx_payment_batch_receipts_uploader") @@index([file_sha256], map: "idx_payment_batch_receipts_file_sha256") @@index([governance_status], map: "idx_payment_batch_receipts_governance_status") @@index([sensitivity_level], map: "idx_payment_batch_receipts_sensitivity_level") @@map("payment_batch_receipt_attachments") } model PaymentReceiptVerification { id String @id @default(uuid()) @db.Uuid attachment_id String @db.Uuid source_sha256 String @db.VarChar(64) source_version Int status String @db.VarChar(32) pages_expected Int pages_processed Int normalized_encrypted String created_at DateTime @default(now()) attachment PaymentBatchReceiptAttachment @relation(fields: [attachment_id], references: [id], onDelete: Restrict) matches PaymentReceiptMatch[] claims PaymentReceiptClaim[] manual_proposals PaymentReceiptManualProposal[] loan_terminal_facts LoanBankTerminalFact[] @@index([attachment_id, created_at]) @@map("payment_receipt_verifications") } model PaymentReceiptManualProposal { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid attachment_id String @db.Uuid original_verification_id String @db.Uuid source_sha256 String @db.VarChar(64) source_version Int status String @db.VarChar(32) proposed_by String @db.Uuid reviewed_by String? @db.Uuid payload_encrypted String review_note_encrypted String? created_at DateTime @default(now()) reviewed_at DateTime? attachment PaymentBatchReceiptAttachment @relation(fields: [attachment_id], references: [id], onDelete: Restrict) original_verification PaymentReceiptVerification @relation(fields: [original_verification_id], references: [id], onDelete: Restrict) claims PaymentReceiptClaim[] @@unique([attachment_id, source_version]) @@map("payment_receipt_manual_proposals") } model PaymentReceiptMatch { id String @id @default(uuid()) @db.Uuid verification_id String @db.Uuid item_id String @db.Uuid page_number Int fingerprint String @db.VarChar(64) key_id String @db.VarChar(64) verification PaymentReceiptVerification @relation(fields: [verification_id], references: [id], onDelete: Restrict) item PaymentBatchItem @relation(fields: [item_id], references: [id], onDelete: Restrict) @@unique([verification_id, page_number]) @@unique([verification_id, item_id]) @@index([item_id]) @@map("payment_receipt_matches") } model PaymentReceiptClaim { fingerprint String @id @db.VarChar(64) key_id String @db.VarChar(64) item_id String @unique @db.Uuid verification_id String @db.Uuid manual_proposal_id String? @db.Uuid created_at DateTime @default(now()) item PaymentBatchItem @relation(fields: [item_id], references: [id], onDelete: Restrict) verification PaymentReceiptVerification @relation(fields: [verification_id], references: [id], onDelete: Restrict) manual_proposal PaymentReceiptManualProposal? @relation(fields: [manual_proposal_id], references: [id], onDelete: Restrict) aliases PaymentReceiptTransactionAlias[] @@map("payment_receipt_claims") } model PaymentReceiptTransactionAlias { fingerprint String @id @db.VarChar(64) key_id String @db.VarChar(64) claim_fingerprint String @db.VarChar(64) created_at DateTime @default(now()) claim PaymentReceiptClaim @relation(fields: [claim_fingerprint], references: [fingerprint], onDelete: Restrict) @@index([claim_fingerprint]) @@map("payment_receipt_transaction_aliases") } model PortalAnnouncement { id String @id @default(uuid()) @db.Uuid title String summary String link_url String? starts_at DateTime? ends_at DateTime? enabled Boolean @default(true) priority Int @default(100) category String @default("general") requires_acknowledgement Boolean @default(false) acknowledgement_statement String? acknowledgement_due_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid acknowledgements PortalAnnouncementAcknowledgement[] @@index([enabled, priority, starts_at, ends_at], map: "idx_portal_announcements_enabled_priority") @@map("portal_announcements") } model PortalAnnouncementAcknowledgement { id String @id @default(uuid()) @db.Uuid announcement_id String @db.Uuid employee_id String @db.Uuid acknowledged_at DateTime @default(now()) statement_snapshot String title_snapshot String summary_snapshot String actor_id String @db.Uuid created_at DateTime @default(now()) announcement PortalAnnouncement @relation(fields: [announcement_id], references: [id], onDelete: Cascade) employee Employee @relation("PortalAnnouncementAcknowledgementEmployee", fields: [employee_id], references: [id], onDelete: Restrict) actor Employee @relation("PortalAnnouncementAcknowledgementActor", fields: [actor_id], references: [id], onDelete: Restrict) @@unique([announcement_id, employee_id]) @@index([employee_id, acknowledged_at]) @@index([announcement_id, acknowledged_at]) @@map("portal_announcement_acknowledgements") } model WorkspaceSetting { id String @id @default(uuid()) @db.Uuid profile WorkspaceProfile @default(small_team_internal) org_mode WorkspaceOrgMode @default(single_company) primary_entry_mode WorkspacePrimaryEntryMode @default(password) notification_strategy WorkspaceNotificationStrategy @default(in_app) device_priority WorkspaceDevicePriority @default(desktop) module_visibility_json Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@map("workspace_settings") } model EmployeeLifecycleEvent { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid event_type EmployeeLifecycleEventType effective_date DateTime @db.Date payload_json Json? created_at DateTime @default(now()) created_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([employee_id, effective_date], map: "idx_employee_lifecycle_events_employee_date") @@index([event_type, created_at], map: "idx_employee_lifecycle_events_type_created") @@map("employee_lifecycle_events") } model EmployeeChecklistTask { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid scene EmployeeChecklistScene task_type EmployeeChecklistTaskType title String status EmployeeChecklistTaskStatus @default(pending) due_date DateTime? @db.Date completed_at DateTime? completed_by String? @db.Uuid payload_json Json? created_at DateTime @default(now()) employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([employee_id, scene, status], map: "idx_employee_checklist_tasks_employee_scene_status") @@index([scene, due_date], map: "idx_employee_checklist_tasks_scene_due") @@map("employee_checklist_tasks") } model EmployeePresence { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid date DateTime @db.Date status EmployeePresenceStatus time_range EmployeePresenceTimeRange @default(full_day) note String? source EmployeePresenceSource @default(manual) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([employee_id, date], map: "employee_presence_employee_date_ux") @@index([date, status], map: "idx_employee_presence_date_status") @@map("employee_presence") } model AttendanceRecord { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid work_date DateTime @db.Date clock_in_at DateTime? clock_out_at DateTime? work_minutes Int? is_late Boolean @default(false) late_minutes Int @default(0) is_early_leave Boolean @default(false) early_minutes Int @default(0) note String? source String @default("web") @db.VarChar(16) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([employee_id, work_date], map: "attendance_records_employee_date_ux") @@index([work_date], map: "idx_attendance_records_work_date") @@map("attendance_records") } model AttendancePolicy { id String @id @default(uuid()) @db.Uuid work_start_time String @default("09:00") @db.VarChar(5) work_end_time String @default("18:00") @db.VarChar(5) lunch_start_time String @default("12:00") @db.VarChar(5) lunch_end_time String @default("13:00") @db.VarChar(5) late_tolerance_minutes Int @default(0) enabled Boolean @default(true) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@map("attendance_policies") } model WecomCheckinSyncRun { id String @id @default(uuid()) @db.Uuid start_date DateTime @db.Date end_date DateTime @db.Date status String @default("running") @db.VarChar(24) employee_count Int @default(0) record_count Int @default(0) error_code String? @db.VarChar(80) error_message String? triggered_by String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt trigger Employee? @relation("WecomCheckinSyncRunTrigger", fields: [triggered_by], references: [id], onDelete: SetNull) records WecomCheckinRecord[] @@index([status, created_at], map: "idx_wecom_checkin_sync_runs_status_created") @@index([start_date, end_date], map: "idx_wecom_checkin_sync_runs_range") @@index([triggered_by], map: "idx_wecom_checkin_sync_runs_triggered_by") @@map("wecom_checkin_sync_runs") } model WecomCheckinRecord { id String @id @default(uuid()) @db.Uuid sync_run_id String @db.Uuid employee_id String @db.Uuid external_user_id String @db.VarChar(128) checkin_time DateTime checkin_date DateTime @db.Date checkin_type String @db.VarChar(40) exception_type String? @db.VarChar(80) source_type String? @db.VarChar(40) result String? @db.VarChar(80) raw_hash String @db.VarChar(64) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt sync_run WecomCheckinSyncRun @relation(fields: [sync_run_id], references: [id], onDelete: Cascade) employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([external_user_id, checkin_time, checkin_type], map: "wecom_checkin_records_user_time_type_ux") @@index([employee_id, checkin_date], map: "idx_wecom_checkin_records_employee_date") @@index([sync_run_id], map: "idx_wecom_checkin_records_sync_run") @@map("wecom_checkin_records") } model WecomCheckinDailySummary { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid external_user_id_prefix String? @db.VarChar(32) checkin_date DateTime @db.Date record_count Int @default(0) first_checkin_at DateTime? last_checkin_at DateTime? exception_count Int @default(0) abnormal_count Int @default(0) checkin_type_summary Json? result_summary Json? source_type_summary Json? raw_hash_digest String? @db.VarChar(64) source_record_count Int @default(0) last_sync_run_id String? @db.Uuid archived_at DateTime @default(now()) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([employee_id, checkin_date], map: "wecom_checkin_daily_summaries_emp_date_ux") @@index([checkin_date], map: "idx_wecom_checkin_daily_summaries_date") @@index([last_sync_run_id], map: "idx_wecom_checkin_daily_summaries_run") @@map("wecom_checkin_daily_summaries") } model WecomCheckinMonthlySummary { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid month String @db.VarChar(7) start_date DateTime @db.Date end_date DateTime @db.Date summary_day_count Int @default(0) checkin_day_count Int @default(0) exception_day_count Int @default(0) abnormal_record_count Int @default(0) missing_day_candidate_count Int @default(0) first_checkin_at DateTime? last_checkin_at DateTime? result_summary Json? raw_hash_digest String? @db.VarChar(64) archived_at DateTime @default(now()) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([employee_id, month], map: "wecom_checkin_monthly_summaries_emp_month_ux") @@index([month], map: "idx_wecom_checkin_monthly_summaries_month") @@map("wecom_checkin_monthly_summaries") } model WecomCheckinRuleSnapshot { id String @id @default(uuid()) @db.Uuid employee_id String? @db.Uuid external_user_id_prefix String? @db.VarChar(32) snapshot_date DateTime @db.Date rule_hash String @db.VarChar(64) rule_summary Json? source_endpoint String @default("/cgi-bin/checkin/getcheckinoption") @db.VarChar(120) archived_at DateTime @default(now()) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt employee Employee? @relation(fields: [employee_id], references: [id], onDelete: SetNull) @@unique([employee_id, snapshot_date, rule_hash], map: "wecom_checkin_rule_snapshots_emp_date_hash_ux") @@index([snapshot_date], map: "idx_wecom_checkin_rule_snapshots_date") @@index([rule_hash], map: "idx_wecom_checkin_rule_snapshots_hash") @@map("wecom_checkin_rule_snapshots") } model WecomDirectorySyncRun { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid external_user_id String? @db.VarChar(128) operation String @db.VarChar(32) status String @default("running") @db.VarChar(24) attempts Int @default(1) error_code String? @db.VarChar(80) error_message String? response_summary Json? triggered_by String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt employee Employee @relation("WecomDirectorySyncRunEmployee", fields: [employee_id], references: [id], onDelete: Cascade) trigger Employee? @relation("WecomDirectorySyncRunTrigger", fields: [triggered_by], references: [id], onDelete: SetNull) @@index([employee_id, created_at], map: "idx_wecom_directory_sync_runs_employee_created") @@index([status, created_at], map: "idx_wecom_directory_sync_runs_status_created") @@index([operation, created_at], map: "idx_wecom_directory_sync_runs_operation_created") @@index([triggered_by], map: "idx_wecom_directory_sync_runs_triggered_by") @@map("wecom_directory_sync_runs") } model AttendanceCorrection { id String @id @default(uuid()) @db.Uuid owner_id String @db.Uuid department_id String? @db.Uuid kind AttendanceCorrectionKind status AttendanceCorrectionStatus @default(reviewing) work_date DateTime @db.Date start_at DateTime? end_at DateTime? missed_punch_at DateTime? reason String location_summary String? compensation_policy String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid owner Employee @relation(fields: [owner_id], references: [id], onDelete: Cascade) department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull) workflow_instances WorkflowInstance[] @@index([owner_id, work_date], map: "idx_attendance_corrections_owner_date") @@index([department_id, status], map: "idx_attendance_corrections_department_status") @@index([status, updated_at], map: "idx_attendance_corrections_status_updated") @@map("attendance_corrections") } model WeeklyReport { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid week_start DateTime @db.Date status WeeklyReportStatus @default(draft) highlights_text String @default("") blockers_text String @default("") next_week_text String @default("") needs_help Boolean @default(false) submitted_at DateTime? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) project_links ProjectLinkOnWeeklyReport[] @@unique([employee_id, week_start], map: "weekly_reports_employee_week_start_ux") @@index([week_start, status], map: "idx_weekly_reports_week_status") @@map("weekly_reports") } model TodoItem { id String @id @default(uuid()) @db.Uuid title String description String? assignee_employee_id String @db.Uuid created_by String @db.Uuid due_date DateTime? @db.Date priority TodoPriority @default(normal) status TodoStatus @default(todo) source TodoSource @default(manual) project_id String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt completed_at DateTime? assignee Employee @relation("TodoAssignee", fields: [assignee_employee_id], references: [id], onDelete: Restrict) creator Employee @relation("TodoCreator", fields: [created_by], references: [id], onDelete: Restrict) project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) @@index([assignee_employee_id, status, due_date], map: "idx_todo_items_assignee_status_due") @@index([project_id, status], map: "idx_todo_items_project_status") @@index([created_by, created_at], map: "idx_todo_items_creator_created") @@map("todo_items") } model WecomIdentityBinding { id String @id @default(uuid()) @db.Uuid employee_id String @unique @db.Uuid external_user_id String @unique @db.VarChar(128) external_open_user_id String? @db.VarChar(128) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([external_user_id], map: "idx_wecom_identity_bindings_external_user") @@map("wecom_identity_bindings") } model WecomHrMasterSyncRun { id String @id @default(uuid()) @db.Uuid mode String @db.VarChar(16) status String @default("running") @db.VarChar(24) token_source Json? requested_userids Json? limit Int? summary Json? error_code String? @db.VarChar(80) error_message String? triggered_by String? @db.Uuid started_at DateTime @default(now()) finished_at DateTime? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt trigger Employee? @relation("WecomHrMasterSyncRunTrigger", fields: [triggered_by], references: [id], onDelete: SetNull) items WecomHrMasterSyncItem[] @@index([status, created_at], map: "idx_wecom_hr_master_sync_runs_status_created") @@index([mode, created_at], map: "idx_wecom_hr_master_sync_runs_mode_created") @@index([triggered_by], map: "idx_wecom_hr_master_sync_runs_triggered_by") @@map("wecom_hr_master_sync_runs") } model WecomHrMasterSyncItem { id String @id @default(uuid()) @db.Uuid run_id String @db.Uuid employee_id String? @db.Uuid external_user_id_masked String @db.VarChar(80) action String @db.VarChar(32) status String @db.VarChar(24) error_code String? @db.VarChar(80) error_message String? retry_count Int @default(0) field_changes Json? source_summary Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt run WecomHrMasterSyncRun @relation(fields: [run_id], references: [id], onDelete: Cascade) employee Employee? @relation("WecomHrMasterSyncItemEmployee", fields: [employee_id], references: [id], onDelete: SetNull) @@index([run_id, status], map: "idx_wecom_hr_master_sync_items_run_status") @@index([employee_id, created_at], map: "idx_wecom_hr_master_sync_items_employee_created") @@index([action, status], map: "idx_wecom_hr_master_sync_items_action_status") @@map("wecom_hr_master_sync_items") } model WecomApprovalArchive { id String @id @default(uuid()) @db.Uuid corp_id_hash String @db.VarChar(64) sp_no String @db.VarChar(160) template_id String? @db.VarChar(160) template_type String @default("unknown") @db.VarChar(40) sp_name String? @db.VarChar(160) normalized_status String @default("unknown") @db.VarChar(32) wecom_status String? @db.VarChar(40) applicant_employee_id String? @db.Uuid applicant_external_user_id String? @db.VarChar(128) submitted_at DateTime? applied_at DateTime? completed_at DateTime? status_observed_at DateTime? last_callback_at DateTime? last_compensation_at DateTime? last_source String? @db.VarChar(40) last_detail_digest String? @db.VarChar(64) readability_status String? @db.VarChar(40) single_tap_approve_risk Boolean @default(false) template_adjustment_required Boolean @default(false) external_config_status String? @db.VarChar(40) source_summary Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt applicant Employee? @relation("WecomApprovalArchiveApplicant", fields: [applicant_employee_id], references: [id], onDelete: SetNull) participants WecomApprovalParticipant[] actions WecomApprovalAction[] field_summaries WecomApprovalFieldSummary[] attachment_summaries WecomApprovalAttachmentSummary[] callback_events WecomApprovalCallbackEvent[] compensation_items WecomApprovalCompensationItem[] reconcile_findings WecomApprovalReconcileFinding[] @@unique([corp_id_hash, sp_no], map: "wecom_approval_archives_corp_sp_no_ux") @@index([applicant_employee_id, status_observed_at], map: "idx_wecom_approval_arch_applicant_status_at") @@index([template_type, normalized_status], map: "idx_wecom_approval_arch_type_status") @@index([last_source], map: "idx_wecom_approval_arch_last_source") @@map("wecom_approval_archives") } model WecomApprovalParticipant { id String @id @default(uuid()) @db.Uuid archive_id String @db.Uuid role String @db.VarChar(32) node_index Int @default(0) external_user_id String @db.VarChar(128) employee_id String? @db.Uuid is_current Boolean @default(false) mapping_status String @default("unknown") @db.VarChar(32) display_summary String? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive @relation(fields: [archive_id], references: [id], onDelete: Cascade) employee Employee? @relation("WecomApprovalParticipantEmployee", fields: [employee_id], references: [id], onDelete: SetNull) @@unique([archive_id, role, node_index, external_user_id], map: "wecom_approval_participants_node_user_ux") @@index([employee_id, role], map: "idx_wecom_approval_part_employee_role") @@index([external_user_id], map: "idx_wecom_approval_part_external_user") @@map("wecom_approval_participants") } model WecomApprovalAction { id String @id @default(uuid()) @db.Uuid archive_id String @db.Uuid action_type String @db.VarChar(40) operator_external_user_id String? @db.VarChar(128) operator_employee_id String? @db.Uuid action_time DateTime? node_index Int @default(0) comment_summary String? source String @db.VarChar(40) idempotency_key String @db.VarChar(96) evidence_digest String? @db.VarChar(64) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive @relation(fields: [archive_id], references: [id], onDelete: Cascade) operator Employee? @relation("WecomApprovalActionOperator", fields: [operator_employee_id], references: [id], onDelete: SetNull) @@unique([archive_id, idempotency_key], map: "wecom_approval_actions_archive_key_ux") @@index([operator_employee_id, action_time], map: "idx_wecom_approval_actions_operator_time") @@index([action_type, action_time], map: "idx_wecom_approval_actions_type_time") @@map("wecom_approval_actions") } model WecomApprovalFieldSummary { id String @id @default(uuid()) @db.Uuid archive_id String @db.Uuid field_key String @db.VarChar(120) field_index Int @default(0) field_name String? @db.VarChar(160) field_type String? @db.VarChar(80) normalized_value String? value_preview String? sensitive_level String @default("normal") @db.VarChar(32) display_allowed Boolean @default(false) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive @relation(fields: [archive_id], references: [id], onDelete: Cascade) @@unique([archive_id, field_key, field_index], map: "wecom_approval_fields_archive_key_ux") @@index([field_key], map: "idx_wecom_approval_fields_key") @@map("wecom_approval_field_summaries") } model WecomApprovalAttachmentSummary { id String @id @default(uuid()) @db.Uuid archive_id String @db.Uuid attachment_index Int @default(0) attachment_type String? @db.VarChar(80) external_ref_summary String? downloaded Boolean @default(false) sensitive_level String @default("restricted") @db.VarChar(32) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive @relation(fields: [archive_id], references: [id], onDelete: Cascade) @@index([archive_id, attachment_index], map: "idx_wecom_approval_attach_archive_idx") @@map("wecom_approval_attachment_summaries") } model WecomApprovalCallbackEvent { id String @id @default(uuid()) @db.Uuid archive_id String? @db.Uuid corp_id_hash String @db.VarChar(64) sp_no String @db.VarChar(160) template_id String? @db.VarChar(160) event_type String @db.VarChar(80) callback_kind String @db.VarChar(80) approval_type String @default("unknown") @db.VarChar(40) normalized_status String @default("unknown") @db.VarChar(32) wecom_status String? @db.VarChar(40) received_at DateTime @default(now()) event_time DateTime? apply_time DateTime? processing_status String @default("accepted") @db.VarChar(40) processing_error_code String? @db.VarChar(80) processing_error_message String? retry_count Int @default(0) idempotency_key String @unique @db.VarChar(96) event_digest String @db.VarChar(64) source_summary Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive? @relation(fields: [archive_id], references: [id], onDelete: SetNull) @@index([sp_no], map: "idx_wecom_approval_callbacks_sp_no") @@index([archive_id, received_at], map: "idx_wecom_approval_callbacks_archive_at") @@index([processing_status, received_at], map: "idx_wecom_approval_callbacks_status_at") @@map("wecom_approval_callback_events") } model WecomApprovalCompensationRun { id String @id @default(uuid()) @db.Uuid run_key String? @db.VarChar(64) mode String @default("live_read") @db.VarChar(32) status String @default("running") @db.VarChar(32) start_time DateTime end_time DateTime template_filter Json? cursor_summary String? page_size Int @default(100) page_count Int @default(0) item_count Int @default(0) detail_count Int @default(0) finding_count Int @default(0) error_code String? @db.VarChar(80) error_message String? started_at DateTime @default(now()) finished_at DateTime? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt items WecomApprovalCompensationItem[] findings WecomApprovalReconcileFinding[] @@index([run_key], map: "idx_wecom_approval_comp_runs_key") @@index([status, started_at], map: "idx_wecom_approval_comp_runs_status") @@index([start_time, end_time], map: "idx_wecom_approval_comp_runs_window") @@map("wecom_approval_compensation_runs") } model WecomApprovalCompensationItem { id String @id @default(uuid()) @db.Uuid run_id String @db.Uuid archive_id String? @db.Uuid sp_no String @db.VarChar(160) template_id String? @db.VarChar(160) template_type String @default("unknown") @db.VarChar(40) normalized_status String @default("unknown") @db.VarChar(32) detail_status String @default("pending") @db.VarChar(40) detail_digest String? @db.VarChar(64) error_code String? @db.VarChar(80) error_message String? source_summary Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt run WecomApprovalCompensationRun @relation(fields: [run_id], references: [id], onDelete: Cascade) archive WecomApprovalArchive? @relation(fields: [archive_id], references: [id], onDelete: SetNull) @@unique([run_id, sp_no], map: "wecom_approval_comp_items_run_sp_no_ux") @@index([archive_id], map: "idx_wecom_approval_comp_items_archive") @@index([detail_status], map: "idx_wecom_approval_comp_items_status") @@map("wecom_approval_compensation_items") } model WecomApprovalReconcileFinding { id String @id @default(uuid()) @db.Uuid archive_id String? @db.Uuid run_id String? @db.Uuid finding_type String @db.VarChar(80) status String @default("open") @db.VarChar(32) severity String @default("info") @db.VarChar(32) evidence_digest String @db.VarChar(64) source String @db.VarChar(40) description String? detected_at DateTime @default(now()) resolved_at DateTime? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt archive WecomApprovalArchive? @relation(fields: [archive_id], references: [id], onDelete: SetNull) run WecomApprovalCompensationRun? @relation(fields: [run_id], references: [id], onDelete: SetNull) @@unique([archive_id, finding_type, evidence_digest], map: "wecom_approval_findings_archive_digest_ux") @@unique([run_id, finding_type, evidence_digest], map: "wecom_approval_findings_run_digest_ux") @@index([status, detected_at], map: "idx_wecom_approval_findings_status_at") @@index([run_id], map: "idx_wecom_approval_findings_run") @@map("wecom_approval_reconcile_findings") } model Project { id String @id @default(uuid()) @db.Uuid project_no String @unique name String client_name String client_alias String? owner_employee_id String @db.Uuid manager_employee_id String? @db.Uuid status ProjectStatus @default(draft) starts_at DateTime? @db.Date target_end_at DateTime? @db.Date actual_end_at DateTime? @db.Date summary String? is_confidential Boolean @default(false) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt owner Employee @relation("ProjectOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict) manager Employee? @relation("ProjectManager", fields: [manager_employee_id], references: [id], onDelete: SetNull) members ProjectMember[] milestones ProjectMilestone[] tasks ProjectTask[] risks ProjectRisk[] reimbursements ReimbursementForm[] purchase_requests PurchaseRequest[] travel_requests TravelRequest[] todo_items TodoItem[] weekly_reports ProjectLinkOnWeeklyReport[] communication_logs ProjectCommunicationLog[] closure_checklist_items ProjectClosureChecklistItem[] contracts ContractRegistry[] deliveries ProjectDeliveryRecord[] document_refs ConfidentialDocumentRef[] @@index([owner_employee_id, status], map: "idx_projects_owner_status") @@index([manager_employee_id, status], map: "idx_projects_manager_status") @@index([status, target_end_at], map: "idx_projects_status_target_end") @@index([client_name, name], map: "idx_projects_client_name") @@map("projects") } model ProjectMember { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid employee_id String @db.Uuid role ProjectRole @default(member) joined_at DateTime @default(now()) left_at DateTime? project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) @@unique([project_id, employee_id], map: "project_members_project_employee_ux") @@index([employee_id, left_at], map: "idx_project_members_employee_open") @@map("project_members") } model ProjectMilestone { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid title String description String? status ProjectMilestoneStatus @default(pending) due_date DateTime? @db.Date completed_at DateTime? owner_employee_id String? @db.Uuid sort_order Int @default(100) created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) owner Employee? @relation("ProjectMilestoneOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull) @@index([project_id, sort_order], map: "idx_project_milestones_project_sort") @@index([owner_employee_id, due_date], map: "idx_project_milestones_owner_due") @@map("project_milestones") } model ProjectTask { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid title String description String? status ProjectTaskStatus @default(todo) priority ProjectTaskPriority @default(normal) assignee_employee_id String? @db.Uuid due_date DateTime? @db.Date blocked_reason String? created_by String @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) assignee Employee? @relation("ProjectTaskAssignee", fields: [assignee_employee_id], references: [id], onDelete: SetNull) creator Employee @relation("ProjectTaskCreator", fields: [created_by], references: [id], onDelete: Restrict) @@index([project_id, status, priority], map: "idx_project_tasks_project_status_priority") @@index([assignee_employee_id, status], map: "idx_project_tasks_assignee_status") @@map("project_tasks") } model ProjectRisk { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid title String detail String level ProjectRiskLevel @default(medium) status String @default("open") @db.VarChar(32) owner_employee_id String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) owner Employee? @relation("ProjectRiskOwner", fields: [owner_employee_id], references: [id], onDelete: SetNull) @@index([project_id, status, level], map: "idx_project_risks_project_status_level") @@index([owner_employee_id, status], map: "idx_project_risks_owner_status") @@map("project_risks") } model ProjectLinkOnWeeklyReport { id String @id @default(uuid()) @db.Uuid weekly_report_id String @db.Uuid project_id String @db.Uuid progress_text String @default("") risk_text String @default("") next_step_text String @default("") created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt weekly_report WeeklyReport @relation(fields: [weekly_report_id], references: [id], onDelete: Cascade) project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) @@unique([weekly_report_id, project_id], map: "weekly_report_project_links_report_project_ux") @@index([project_id, updated_at], map: "idx_weekly_report_project_links_project_updated") @@map("weekly_report_project_links") } model ProjectCommunicationLog { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid happened_at DateTime channel ProjectCommunicationChannel external_contact_name String? external_org_name String? summary String next_action String? next_follow_up_date DateTime? @db.Date created_by String @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) creator Employee @relation("ProjectCommunicationLogCreator", fields: [created_by], references: [id], onDelete: Restrict) @@index([project_id, happened_at], map: "idx_project_communication_logs_project_happened") @@index([project_id, next_follow_up_date], map: "idx_project_communication_logs_followup") @@index([created_by, created_at], map: "idx_project_communication_logs_creator_created") @@map("project_communication_logs") } model ProjectClosureChecklistItem { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid item_key String @db.VarChar(64) title String status ProjectClosureChecklistStatus @default(pending) note String? sort_order Int @default(100) completed_at DateTime? completed_by String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) completer Employee? @relation("ProjectClosureChecklistItemCompleter", fields: [completed_by], references: [id], onDelete: SetNull) @@unique([project_id, item_key], map: "project_closure_checklists_project_key_ux") @@index([project_id, status, sort_order], map: "idx_project_closure_checklists_project_status") @@index([completed_by, completed_at], map: "idx_project_closure_checklists_completed") @@map("project_closure_checklist_items") } model ContractRegistry { id String @id @default(uuid()) @db.Uuid contract_no String @unique project_id String? @db.Uuid contract_type ContractRegistryType @default(other) counterparty_name String summary String amount Decimal? @db.Decimal(14, 2) currency String @default("CNY") @db.VarChar(8) signed_date DateTime? @db.Date effective_date DateTime? @db.Date expiry_date DateTime? @db.Date confidentiality_level ConfidentialityLevel @default(internal) archive_location String offline_archive_no String? owner_employee_id String @db.Uuid status String @default("active") @db.VarChar(32) terminated_at DateTime? terminated_reason String? @db.VarChar(1000) terminated_by String? @db.Uuid created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) owner Employee @relation("ContractRegistryOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict) terminator Employee? @relation("ContractRegistryTerminator", fields: [terminated_by], references: [id], onDelete: Restrict) document_refs ConfidentialDocumentRef[] @@index([project_id, status], map: "idx_contract_registry_project_status") @@index([status, expiry_date], map: "idx_contract_registry_status_expiry") @@index([contract_type, status], map: "idx_contract_registry_type_status") @@index([owner_employee_id, created_at], map: "idx_contract_registry_owner_created") @@index([terminated_by, terminated_at], map: "idx_contract_registry_terminator_terminated") @@map("contract_registry") } model EmployeeContract { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid contract_no String contract_type EmployeeContractType start_date DateTime @db.Date end_date DateTime @db.Date terminated_date DateTime? @db.Date attachment_path String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@unique([employee_id, contract_no], map: "employee_contracts_employee_contract_no_ux") @@index([employee_id, start_date], map: "idx_employee_contracts_employee_start") @@index([employee_id, end_date], map: "idx_employee_contracts_employee_end") @@map("employee_contracts") } model EmployeeTraining { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid name String training_type EmployeeTrainingType start_date DateTime @db.Date end_date DateTime? @db.Date status EmployeeTrainingStatus notes String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([employee_id, start_date], map: "idx_employee_trainings_employee_start") @@index([employee_id, status], map: "idx_employee_trainings_employee_status") @@map("employee_trainings") } model EmployeeCertificate { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid name String issuer String obtained_date DateTime @db.Date expiry_date DateTime? @db.Date certificate_no String? attachment_path String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) @@index([employee_id, obtained_date], map: "idx_employee_certificates_employee_obtained") @@index([employee_id, expiry_date], map: "idx_employee_certificates_employee_expiry") @@map("employee_certificates") } model SalaryItem { id String @id @default(uuid()) @db.Uuid name String @unique item_type SalaryItemType sort_order Int enabled Boolean @default(true) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee_salaries EmployeeSalary[] payslip_items PayslipItem[] @@index([enabled, sort_order], map: "idx_salary_items_enabled_sort") @@map("salary_items") } model EmployeeSalary { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid salary_item_id String @db.Uuid monthly_amount Decimal @db.Decimal(12, 2) effective_date DateTime @db.Date created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) salary_item SalaryItem @relation(fields: [salary_item_id], references: [id], onDelete: Restrict) @@unique([employee_id, salary_item_id, effective_date], map: "employee_salaries_employee_item_effective_ux") @@index([employee_id, effective_date], map: "idx_employee_salaries_employee_effective") @@index([salary_item_id], map: "idx_employee_salaries_salary_item") @@map("employee_salaries") } model Payslip { id String @id @default(uuid()) @db.Uuid employee_id String @db.Uuid pay_month DateTime @db.Date status PayslipStatus @default(draft) gross_amount Decimal @default(0) @db.Decimal(12, 2) deduction_amount Decimal @default(0) @db.Decimal(12, 2) net_amount Decimal @default(0) @db.Decimal(12, 2) issued_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Cascade) items PayslipItem[] @@unique([employee_id, pay_month], map: "payslips_employee_month_ux") @@index([pay_month, status], map: "idx_payslips_month_status") @@index([employee_id, pay_month], map: "idx_payslips_employee_month") @@map("payslips") } model PayslipItem { id String @id @default(uuid()) @db.Uuid payslip_id String @db.Uuid salary_item_id String @db.Uuid amount Decimal @default(0) @db.Decimal(12, 2) payslip Payslip @relation(fields: [payslip_id], references: [id], onDelete: Cascade) salary_item SalaryItem @relation(fields: [salary_item_id], references: [id], onDelete: Restrict) @@unique([payslip_id, salary_item_id], map: "payslip_items_payslip_salary_item_ux") @@index([salary_item_id], map: "idx_payslip_items_salary_item") @@map("payslip_items") } model PerformanceReviewCycle { id String @id @default(uuid()) @db.Uuid name String cycle_type PerformanceReviewCycleType start_date DateTime @db.Date end_date DateTime @db.Date status PerformanceReviewCycleStatus @default(draft) activated_at DateTime? completed_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid reviews PerformanceReview[] @@index([status, start_date], map: "idx_performance_review_cycles_status_start") @@index([status, completed_at], map: "idx_performance_review_cycles_status_completed") @@map("performance_review_cycles") } model PerformanceReview { id String @id @default(uuid()) @db.Uuid cycle_id String @db.Uuid employee_id String @db.Uuid reviewer_employee_id String @db.Uuid overall_score Decimal @db.Decimal(3, 1) comment String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid cycle PerformanceReviewCycle @relation(fields: [cycle_id], references: [id], onDelete: Cascade) employee Employee @relation("PerformanceReviewEmployee", fields: [employee_id], references: [id], onDelete: Cascade) reviewer_employee Employee @relation("PerformanceReviewReviewer", fields: [reviewer_employee_id], references: [id], onDelete: Restrict) dimensions PerformanceReviewDimension[] @@unique([cycle_id, employee_id], map: "performance_reviews_cycle_employee_ux") @@index([cycle_id, reviewer_employee_id], map: "idx_performance_reviews_cycle_reviewer") @@index([employee_id, created_at], map: "idx_performance_reviews_employee_created") @@map("performance_reviews") } model PerformanceReviewDimension { id String @id @default(uuid()) @db.Uuid review_id String @db.Uuid dimension_type PerformanceReviewDimensionType score Decimal @db.Decimal(3, 1) review PerformanceReview @relation(fields: [review_id], references: [id], onDelete: Cascade) @@unique([review_id, dimension_type], map: "performance_review_dimensions_review_dimension_ux") @@index([dimension_type, score], map: "idx_performance_review_dimensions_dimension_score") @@map("performance_review_dimensions") } model ProjectDeliveryRecord { id String @id @default(uuid()) @db.Uuid project_id String @db.Uuid title String record_type ProjectDeliveryRecordType summary String occurred_at DateTime owner_employee_id String @db.Uuid created_at DateTime @default(now()) project Project @relation(fields: [project_id], references: [id], onDelete: Cascade) owner Employee @relation("ProjectDeliveryRecordOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict) @@index([project_id, occurred_at], map: "idx_project_delivery_records_project_occurred") @@map("project_delivery_records") } model ConfidentialDocumentRef { id String @id @default(uuid()) @db.Uuid project_id String? @db.Uuid contract_registry_id String? @db.Uuid title String document_no String? confidentiality_level ConfidentialityLevel @default(internal) storage_type DocumentStorageType storage_path String offline_archive_no String? owner_employee_id String @db.Uuid access_rule_json Json? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) contract_registry ContractRegistry? @relation(fields: [contract_registry_id], references: [id], onDelete: SetNull) owner Employee @relation("ConfidentialDocumentRefOwner", fields: [owner_employee_id], references: [id], onDelete: Restrict) @@index([project_id, confidentiality_level], map: "idx_confidential_doc_refs_project_level") @@index([contract_registry_id], map: "idx_confidential_doc_refs_contract") @@index([owner_employee_id, created_at], map: "idx_confidential_doc_refs_owner_created") @@map("confidential_document_refs") } model MigrationRun { id String @id @default(uuid()) @db.Uuid run_type String @db.VarChar(32) status String @default("draft") @db.VarChar(32) source_filename String summary_json Json? error_json Json? created_at DateTime @default(now()) created_by String? @db.Uuid @@index([run_type, status, created_at], map: "idx_migration_runs_type_status_created") @@map("migration_runs") } model CutoverScope { id String @id @default(uuid()) @db.Uuid scope_type String @db.VarChar(32) scope_key String @db.VarChar(64) enabled Boolean @default(false) starts_at DateTime? notes String? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@unique([scope_type, scope_key], map: "cutover_scopes_scope_type_scope_key_ux") @@index([enabled, scope_type], map: "idx_cutover_scopes_enabled_type") @@map("cutover_scopes") } model IntegrationOutbox { id String @id @default(uuid()) @db.Uuid event_type String @db.VarChar(64) status String @default("pending") @db.VarChar(16) payload Json dedupe_key String? @db.VarChar(128) attempts Int @default(0) max_attempts Int @default(5) last_error String? next_retry_at DateTime? processed_at DateTime? dead_letter_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@unique([event_type, dedupe_key], map: "integration_outbox_event_dedupe_ux") @@index([status, next_retry_at, created_at], map: "idx_integration_outbox_queue") @@map("integration_outbox") } model IntegrationBinding { id String @id @default(uuid()) @db.Uuid provider String @db.VarChar(32) entity_type String @db.VarChar(64) local_id String @db.Uuid external_id String? @db.VarChar(128) external_code String? @db.VarChar(128) last_synced_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@unique([provider, entity_type, local_id], map: "integration_bindings_provider_entity_local_ux") @@unique([provider, entity_type, external_id], map: "integration_bindings_provider_entity_external_id_ux") @@index([provider, entity_type, external_code], map: "idx_integration_bindings_provider_entity_external_code") @@map("integration_bindings") } model IntegrationSyncState { id String @id @default(uuid()) @db.Uuid provider String @db.VarChar(32) resource_type String @db.VarChar(32) status String @default("idle") @db.VarChar(16) last_result Json? last_error String? last_started_at DateTime? last_finished_at DateTime? last_success_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@unique([provider, resource_type], map: "integration_sync_states_provider_resource_ux") @@index([provider, status], map: "idx_integration_sync_states_provider_status") @@map("integration_sync_states") } model TravelRequest { id String @id @default(uuid()) @db.Uuid request_no String? @unique applicant_employee_id String @db.Uuid submitter_id String? @db.Uuid department_id String @db.Uuid legal_entity_id String @db.Uuid cost_center_id String @db.Uuid budget_pool_id String? @db.Uuid project_id String? @db.Uuid purpose String trip_type TravelTripType start_date DateTime @db.Date end_date DateTime @db.Date estimated_amount Decimal @db.Decimal(14, 2) status TravelRequestStatus @default(draft) created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid applicant Employee @relation("TravelRequestApplicant", fields: [applicant_employee_id], references: [id], onDelete: Restrict) submitter Employee? @relation("TravelRequestSubmitter", fields: [submitter_id], references: [id], onDelete: SetNull) department Department @relation(fields: [department_id], references: [id], onDelete: Restrict) legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) cost_center CostCenter @relation(fields: [cost_center_id], references: [id], onDelete: Restrict) budget_pool BudgetPool? @relation(fields: [budget_pool_id], references: [id], onDelete: SetNull) project Project? @relation(fields: [project_id], references: [id], onDelete: SetNull) segments TravelRequestSegment[] travel_orders TravelOrder[] linked_reimbursements ReimbursementForm[] reconciliation_items TravelReconciliationItem[] card_authorizations CardAuthorization[] card_transactions CardTransaction[] workflow_instances WorkflowInstance[] @@index([applicant_employee_id, start_date], map: "idx_travel_requests_applicant_start") @@index([submitter_id], map: "idx_travel_requests_submitter") @@index([project_id], map: "idx_travel_requests_project") @@index([department_id, status], map: "idx_travel_requests_department_status") @@index([legal_entity_id, cost_center_id], map: "idx_travel_requests_legal_cost_center") @@index([budget_pool_id], map: "idx_travel_requests_budget_pool") @@index([status], map: "idx_travel_requests_status") @@map("travel_requests") } model TravelRequestSegment { id String @id @default(uuid()) @db.Uuid travel_request_id String @db.Uuid sort_order Int segment_role TravelSegmentRole transport_type TravelTransportType from_city String to_city String depart_at DateTime arrive_at DateTime created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid travel_request TravelRequest @relation(fields: [travel_request_id], references: [id], onDelete: Cascade) @@index([travel_request_id, sort_order], map: "idx_travel_request_segments_request_sort") @@map("travel_request_segments") } model TravelOrder { id String @id @default(uuid()) @db.Uuid source String @default("manual") @db.VarChar(32) external_order_no String employee_id String @db.Uuid department_id String? @db.Uuid linked_reimbursement_id String? @db.Uuid travel_request_id String? @db.Uuid occurred_at DateTime? @db.Date amount Decimal? @db.Decimal(14, 2) currency String @default("CNY") @db.VarChar(8) status String @default("imported") @db.VarChar(20) payment_voucher_no String? @db.VarChar(50) payment_date DateTime? @db.Date payment_channel String? @db.VarChar(20) paid_at DateTime? paid_by String? @db.Uuid raw_payload Json? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation("TravelOrderEmployee", fields: [employee_id], references: [id], onDelete: Restrict) department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull) linked_reimbursement ReimbursementForm? @relation(fields: [linked_reimbursement_id], references: [id], onDelete: SetNull) travel_request TravelRequest? @relation(fields: [travel_request_id], references: [id], onDelete: SetNull) paid_by_employee Employee? @relation("TravelOrderPaidBy", fields: [paid_by], references: [id], onDelete: SetNull) invoice_pool_items InvoicePool[] card_transactions CardTransaction[] reconciliation_items TravelReconciliationItem[] @@unique([source, external_order_no], map: "travel_orders_source_order_ux") @@index([employee_id, occurred_at], map: "idx_travel_orders_employee_occurred") @@index([linked_reimbursement_id]) @@index([travel_request_id]) @@index([paid_by]) @@map("travel_orders") } model CardAuthorization { id String @id @default(uuid()) @db.Uuid source String @default("manual") @db.VarChar(32) external_auth_no String employee_id String @db.Uuid department_id String? @db.Uuid travel_request_id String @db.Uuid budget_pool_id String? @db.Uuid legal_entity_id String @db.Uuid cost_center_id String @db.Uuid authorized_amount Decimal @db.Decimal(14, 2) settled_amount Decimal @default(0) @db.Decimal(14, 2) reversed_amount Decimal @default(0) @db.Decimal(14, 2) currency String @default("CNY") @db.VarChar(8) occurred_at DateTime? expires_at DateTime? status String @default("authorized") @db.VarChar(32) raw_payload Json? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict) department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull) travel_request TravelRequest @relation(fields: [travel_request_id], references: [id], onDelete: Cascade) budget_pool BudgetPool? @relation(fields: [budget_pool_id], references: [id], onDelete: SetNull) legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) cost_center CostCenter @relation(fields: [cost_center_id], references: [id], onDelete: Restrict) card_transactions CardTransaction[] @@unique([source, external_auth_no], map: "card_authorizations_source_auth_ux") @@index([employee_id, occurred_at], map: "idx_card_authorizations_employee_occurred") @@index([department_id, status], map: "idx_card_authorizations_department_status") @@index([travel_request_id, status], map: "idx_card_authorizations_request_status") @@index([budget_pool_id], map: "idx_card_authorizations_budget_pool") @@index([legal_entity_id, cost_center_id], map: "idx_card_authorizations_legal_cost_center") @@map("card_authorizations") } model CardTransaction { id String @id @default(uuid()) @db.Uuid source String @default("manual") @db.VarChar(32) external_txn_id String card_authorization_id String? @db.Uuid employee_id String @db.Uuid department_id String? @db.Uuid travel_request_id String @db.Uuid travel_order_id String? @db.Uuid amount Decimal @db.Decimal(14, 2) currency String @default("CNY") @db.VarChar(8) txn_type String @db.VarChar(20) status String @default("pending") @db.VarChar(20) occurred_at DateTime? freeze_suggested_at DateTime? freeze_suggested_by String? @db.Uuid freeze_reason_code String? @db.VarChar(32) freeze_reason_note String? raw_payload Json? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid card_authorization CardAuthorization? @relation(fields: [card_authorization_id], references: [id], onDelete: SetNull) employee Employee @relation("CardTransactionEmployee", fields: [employee_id], references: [id], onDelete: Restrict) department Department? @relation(fields: [department_id], references: [id], onDelete: SetNull) travel_request TravelRequest @relation(fields: [travel_request_id], references: [id], onDelete: Cascade) travel_order TravelOrder? @relation(fields: [travel_order_id], references: [id], onDelete: SetNull) freeze_suggested_by_employee Employee? @relation("CardTransactionFreezeSuggestedBy", fields: [freeze_suggested_by], references: [id], onDelete: SetNull) reconciliation_items TravelReconciliationItem[] @@unique([source, external_txn_id], map: "card_transactions_source_txn_ux") @@index([card_authorization_id], map: "idx_card_transactions_authorization") @@index([employee_id, occurred_at], map: "idx_card_transactions_employee_occurred") @@index([department_id, status], map: "idx_card_transactions_department_status") @@index([travel_request_id], map: "idx_card_transactions_request") @@index([travel_order_id], map: "idx_card_transactions_order") @@index([freeze_suggested_by], map: "idx_card_transactions_freeze_suggested_by") @@map("card_transactions") } model TravelReconciliationBatch { id String @id @default(uuid()) @db.Uuid batch_no String @unique legal_entity_id String @db.Uuid cost_center_id String? @db.Uuid period_start DateTime @db.Date period_end DateTime @db.Date status TravelReconciliationBatchStatus @default(draft) summary_json Json confirmed_at DateTime? confirmed_by String? @db.Uuid created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) cost_center CostCenter? @relation(fields: [cost_center_id], references: [id], onDelete: SetNull) confirmed_by_employee Employee? @relation("TravelReconciliationBatchConfirmedBy", fields: [confirmed_by], references: [id], onDelete: SetNull) items TravelReconciliationItem[] @@index([status, period_start, period_end], map: "idx_travel_reconciliation_batches_status_period") @@index([legal_entity_id, cost_center_id], map: "idx_travel_reconciliation_batches_legal_cost_center") @@index([confirmed_by], map: "idx_travel_reconciliation_batches_confirmed_by") @@map("travel_reconciliation_batches") } model TravelReconciliationItem { id String @id @default(uuid()) @db.Uuid travel_reconciliation_batch_id String @db.Uuid item_kind TravelReconciliationItemKind travel_request_id String? @db.Uuid travel_order_id String? @db.Uuid card_transaction_id String? @db.Uuid match_status TravelReconciliationMatchStatus resolution_status TravelReconciliationResolutionStatus @default(pending) order_amount Decimal? @db.Decimal(14, 2) transaction_amount Decimal? @db.Decimal(14, 2) currency String @default("CNY") @db.VarChar(8) anomaly_code String? @db.VarChar(32) snapshot_json Json confirmed_at DateTime? confirmed_by String? @db.Uuid confirm_note String? created_at DateTime @default(now()) updated_at DateTime @default(now()) @updatedAt batch TravelReconciliationBatch @relation(fields: [travel_reconciliation_batch_id], references: [id], onDelete: Cascade) travel_request TravelRequest? @relation(fields: [travel_request_id], references: [id], onDelete: SetNull) travel_order TravelOrder? @relation(fields: [travel_order_id], references: [id], onDelete: SetNull) card_transaction CardTransaction? @relation(fields: [card_transaction_id], references: [id], onDelete: SetNull) confirmed_by_employee Employee? @relation("TravelReconciliationItemConfirmedBy", fields: [confirmed_by], references: [id], onDelete: SetNull) @@index([travel_reconciliation_batch_id, resolution_status], map: "idx_travel_reconciliation_items_batch_resolution") @@index([travel_request_id], map: "idx_travel_reconciliation_items_request") @@index([travel_order_id], map: "idx_travel_reconciliation_items_order") @@index([card_transaction_id], map: "idx_travel_reconciliation_items_transaction") @@index([confirmed_by], map: "idx_travel_reconciliation_items_confirmed_by") @@map("travel_reconciliation_items") } model NotificationChannel { id String @id @default(uuid()) @db.Uuid channel_type String @db.VarChar(32) name String enabled Boolean @default(true) config_json Json template_json Json? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid deliveries NotificationDelivery[] @@unique([channel_type, name], map: "notification_channels_type_name_ux") @@index([enabled, channel_type], map: "idx_notification_channels_enabled_type") @@map("notification_channels") } model WorkflowDefinition { id String @id @default(uuid()) @db.Uuid name String entity_type String definition_json Json version Int is_active Boolean @default(true) published_at DateTime? archived_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid workflow_instances WorkflowInstance[] @@unique([entity_type, version]) @@index([entity_type, is_active]) @@index([entity_type, archived_at], map: "idx_workflow_definitions_entity_archived") @@map("workflow_definitions") } model WorkflowInstance { id String @id @default(uuid()) @db.Uuid workflow_id String @db.Uuid entity_type String entity_id String @db.Uuid reimbursement_id String? @db.Uuid leave_request_id String? @db.Uuid purchase_request_id String? @db.Uuid travel_request_id String? @db.Uuid attendance_correction_id String? @db.Uuid submitter_id String @db.Uuid current_status WorkflowInstanceStatus @default(pending) current_step_id String context_data Json started_at DateTime @default(now()) completed_at DateTime? created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid workflow_definition WorkflowDefinition @relation(fields: [workflow_id], references: [id], onDelete: Restrict) reimbursement_form ReimbursementForm? @relation(fields: [reimbursement_id], references: [id], onDelete: Cascade) leave_request LeaveRequest? @relation(fields: [leave_request_id], references: [id], onDelete: Cascade) purchase_request PurchaseRequest? @relation(fields: [purchase_request_id], references: [id], onDelete: Cascade) travel_request TravelRequest? @relation(fields: [travel_request_id], references: [id], onDelete: Cascade) attendance_correction AttendanceCorrection? @relation(fields: [attendance_correction_id], references: [id], onDelete: Cascade) submitter Employee @relation("WorkflowInstanceSubmitter", fields: [submitter_id], references: [id], onDelete: Restrict) department Department? @relation(fields: [context_department_id], references: [id], onDelete: SetNull) workflow_tasks WorkflowTask[] workflow_history WorkflowHistory[] /// Denormalized for fast filtering (must match context_data.department_id) context_department_id String? @db.Uuid @@index([workflow_id]) @@index([entity_type, entity_id]) @@index([reimbursement_id]) @@index([leave_request_id]) @@index([purchase_request_id]) @@index([travel_request_id]) @@index([attendance_correction_id]) @@index([current_status]) @@index([submitter_id]) @@index([context_department_id]) @@map("workflow_instances") } model WorkflowTask { id String @id @default(uuid()) @db.Uuid instance_id String @db.Uuid step_id String step_name String assignee_id String? @db.Uuid assignee_role RoleCode? status WorkflowTaskStatus @default(pending) outcome WorkflowTaskOutcome? comment String? due_date DateTime? created_at DateTime @default(now()) completed_at DateTime? completed_by String? @db.Uuid workflow_instance WorkflowInstance @relation(fields: [instance_id], references: [id], onDelete: Cascade) assignee_employee Employee? @relation("WorkflowTaskAssignee", fields: [assignee_id], references: [id], onDelete: SetNull) completer_employee Employee? @relation("WorkflowTaskCompleter", fields: [completed_by], references: [id], onDelete: SetNull) workflow_history WorkflowHistory[] @@index([instance_id]) @@index([status]) @@index([assignee_id]) @@index([assignee_role]) @@index([status, assignee_id, assignee_role], map: "idx_workflow_tasks_status_assignee") @@index([status, assignee_id, created_at], map: "idx_workflow_tasks_status_assignee_id_created_at") @@index([status, assignee_role, created_at], map: "idx_workflow_tasks_status_assignee_role_created_at") @@map("workflow_tasks") } model WorkflowHistory { id String @id @default(uuid()) @db.Uuid instance_id String @db.Uuid task_id String? @db.Uuid actor_id String @db.Uuid action String comment String? payload Json? created_at DateTime @default(now()) workflow_instance WorkflowInstance @relation(fields: [instance_id], references: [id], onDelete: Cascade) workflow_task WorkflowTask? @relation(fields: [task_id], references: [id], onDelete: SetNull) actor Employee @relation("WorkflowHistoryActor", fields: [actor_id], references: [id], onDelete: Restrict) @@index([instance_id, created_at]) @@index([task_id]) @@index([actor_id]) @@map("workflow_history") } model ApprovalRule { id String @id @default(uuid()) @db.Uuid name String min_amount Decimal @db.Decimal(14, 2) max_amount Decimal? @db.Decimal(14, 2) level1_role RoleCode level2_role RoleCode? level3_role RoleCode? owner_self_fallback_role RoleCode? enabled Boolean @default(true) priority Int created_at DateTime @default(now()) created_by String? @db.Uuid updated_at DateTime @default(now()) @updatedAt updated_by String? @db.Uuid @@index([enabled, priority]) @@map("approval_rules") } model ApprovalTransfer { id String @id @default(uuid()) @db.Uuid reimbursement_id String @db.Uuid from_approver_id String @db.Uuid to_approver_id String @db.Uuid reason String status ApprovalTransferStatus @default(active) created_at DateTime @default(now()) created_by String? @db.Uuid reimbursement_form ReimbursementForm @relation(fields: [reimbursement_id], references: [id], onDelete: Cascade) from_approver Employee @relation("TransferFrom", fields: [from_approver_id], references: [id], onDelete: Restrict) to_approver Employee @relation("TransferTo", fields: [to_approver_id], references: [id], onDelete: Restrict) @@index([reimbursement_id]) @@index([from_approver_id]) @@index([to_approver_id]) @@map("approval_transfers") } // Scoped company authority for related-party loan repayment. Content and events // are immutable; a newer confirmed version supersedes earlier scope, never // falling back to an older version after stopping either permission. model LoanRelatedAuthorization { id String @id @default(uuid()) @db.Uuid legal_entity_id String @db.Uuid lender_id String @db.Uuid approver_id String @db.Uuid identity_version Int version Int basis String @db.VarChar(1000) proposed_by String @db.Uuid proposed_at DateTime @default(now()) request_key String @db.Uuid loans LoanRelatedAuthorizationLoan[] events LoanRelatedAuthorizationEvent[] @@unique([lender_id, version]) @@unique([proposed_by, request_key]) @@map("loan_related_authorizations") } model LoanRelatedAuthorizationLoan { authorization_id String @db.Uuid loan_id String @db.Uuid authorization LoanRelatedAuthorization @relation(fields: [authorization_id], references: [id], onDelete: Restrict) @@id([authorization_id, loan_id]) @@map("loan_related_authorization_loans") } model LoanRelatedAuthorizationEvent { id String @id @default(uuid()) @db.Uuid authorization_id String @db.Uuid sequence Int action String @db.VarChar(24) payment_enabled Boolean reconcile_enabled Boolean actor_id String @db.Uuid reason String @db.VarChar(500) created_at DateTime @default(now()) authorization LoanRelatedAuthorization @relation(fields: [authorization_id], references: [id], onDelete: Restrict) @@unique([authorization_id, sequence]) @@map("loan_related_authorization_events") } model LoanLenderAcknowledgement { id String @id @default(uuid()) @db.Uuid legal_entity_id String @db.Uuid lender_id String @db.Uuid employee_id String @db.Uuid identity_version Int account_version Int lender_name String @db.VarChar(120) company_name String @db.VarChar(200) loan_ids String[] @db.Uuid content_hash String @db.VarChar(64) request_hash String @db.VarChar(64) reason String @db.VarChar(500) proposed_by String @db.Uuid proposed_at DateTime @default(now()) request_key String @db.Uuid invalidated_at DateTime? invalid_reason String? @db.VarChar(40) loans LoanLenderAcknowledgementLoan[] decision LoanLenderAcknowledgementDecision? @@unique([proposed_by, request_key]) @@index([employee_id, proposed_at]) @@index([lender_id, proposed_at]) @@map("loan_lender_acknowledgements") } model LoanLenderAcknowledgementLoan { acknowledgement_id String @db.Uuid loan_id String @db.Uuid snapshot_json Json acknowledgement LoanLenderAcknowledgement @relation(fields: [acknowledgement_id], references: [id], onDelete: Restrict) loan CompanyLoan @relation(fields: [loan_id], references: [id], onDelete: Restrict) @@id([acknowledgement_id, loan_id]) @@index([loan_id]) @@map("loan_lender_acknowledgement_loans") } model LoanLenderAcknowledgementDecision { acknowledgement_id String @id @db.Uuid action String @db.VarChar(16) actor_id String @db.Uuid reason String @db.VarChar(500) original_checked Boolean created_at DateTime @default(now()) acknowledgement LoanLenderAcknowledgement @relation(fields: [acknowledgement_id], references: [id], onDelete: Restrict) @@map("loan_lender_acknowledgement_decisions") } model LoanLender { id String @id @default(uuid()) @db.Uuid legal_entity_id String @db.Uuid name String @db.VarChar(120) employee_id String? @db.Uuid identity_status String @default("unverified") @db.VarChar(16) identity_version Int @default(1) account_version Int @default(1) identity_confirmed_by String? @db.Uuid identity_confirmed_at DateTime? identity_confirmation String? bank_institution_id String @db.Uuid bank_name String @db.VarChar(200) bank_account_encrypted String account_name_encrypted String archived_at DateTime? created_at DateTime @default(now()) created_by String @db.Uuid updated_at DateTime @updatedAt updated_by String @db.Uuid request_key String @db.Uuid legal_entity LegalEntity @relation(fields: [legal_entity_id], references: [id], onDelete: Restrict) employee Employee? @relation(fields: [employee_id], references: [id], onDelete: Restrict) bank_institution BankInstitution @relation(fields: [bank_institution_id], references: [id], onDelete: Restrict) loans CompanyLoan[] repayments LoanRepayment[] freeze_reasons LoanFreezeReason[] @@unique([legal_entity_id, id]) @@unique([created_by, request_key]) // One lender per employee and company, archived rows included; NULL // employee_id (manual lenders) never conflicts. @@unique([legal_entity_id, employee_id]) @@index([employee_id]) @@map("loan_lenders") } model CompanyLoan { id String @id @default(uuid()) @db.Uuid loan_no String @unique @db.VarChar(64) origin_reference String @db.VarChar(200) legal_entity_id String @db.Uuid lender_id String @db.Uuid currency_code String @default("CNY") @db.VarChar(8) original_principal Decimal @db.Decimal(14, 2) opening_outstanding_principal Decimal @db.Decimal(14, 2) received_date DateTime @db.Date balance_as_of DateTime @db.Date historical_entry Boolean confirmation_status String @default("unconfirmed") @db.VarChar(16) version Int @default(1) confirmed_by String? @db.Uuid confirmed_at DateTime? accounting_confirmation_ref String? @db.VarChar(200) created_at DateTime @default(now()) created_by String @db.Uuid updated_at DateTime @updatedAt updated_by String @db.Uuid request_key String @db.Uuid lender LoanLender @relation(fields: [legal_entity_id, lender_id], references: [legal_entity_id, id], onDelete: Restrict) allocations LoanRepaymentAllocation[] evidences LoanEvidence[] supplemental_settlements LoanSupplementalSettlement[] lender_acknowledgements LoanLenderAcknowledgementLoan[] @@unique([created_by, request_key]) @@unique([legal_entity_id, lender_id, origin_reference]) @@index([lender_id, confirmation_status, received_date]) @@map("company_loans") } model LoanRepayment { approval_mode String @default("independent") @db.VarChar(16) authorization_id String? @db.Uuid approval_context Json? loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid repayment_no String @unique @db.VarChar(64) legal_entity_id String @db.Uuid lender_id String @db.Uuid currency_code String @default("CNY") @db.VarChar(8) reason String @db.VarChar(500) amount Decimal @db.Decimal(14, 2) version Int @default(1) submitted_by String @db.Uuid submitted_at DateTime @default(now()) lender_identity_version Int lender_account_version Int payee_snapshot_json Json bank_result_state String @default("not_sent") @db.VarChar(24) bank_result_ref String? @db.VarChar(500) accounting_handoff_by String? @db.Uuid accounting_handoff_at DateTime? accounting_handoff_ref String? @db.VarChar(200) request_key String @db.Uuid lender LoanLender @relation(fields: [legal_entity_id, lender_id], references: [legal_entity_id, id], onDelete: Restrict) allocations LoanRepaymentAllocation[] batches PaymentBatch[] @@unique([submitted_by, request_key]) @@index([lender_id, submitted_at]) @@map("loan_repayments") } model LoanRepaymentAllocation { id String @id @default(uuid()) @db.Uuid repayment_id String @db.Uuid loan_id String @db.Uuid amount Decimal @db.Decimal(14, 2) loan_version Int reservation_state String @default("reserved") @db.VarChar(16) settled_at DateTime? released_at DateTime? release_reason String? @db.VarChar(500) repayment LoanRepayment @relation(fields: [repayment_id], references: [id], onDelete: Restrict) loan CompanyLoan @relation(fields: [loan_id], references: [id], onDelete: Restrict) @@unique([repayment_id, loan_id]) @@index([loan_id, reservation_state]) @@map("loan_repayment_allocations") } model LoanEvidence { id String @id @default(uuid()) @db.Uuid loan_id String @db.Uuid kind String @db.VarChar(32) original_name String @db.VarChar(255) storage_path String mime_type String @db.VarChar(100) file_size Int file_sha256 String @db.VarChar(64) governance_status String @default("pending") @db.VarChar(16) uploaded_by String @db.Uuid uploaded_at DateTime @default(now()) archived_at DateTime? archive_reason String? @db.VarChar(500) loan CompanyLoan @relation(fields: [loan_id], references: [id], onDelete: Restrict) uploader Employee @relation(fields: [uploaded_by], references: [id], onDelete: Restrict) @@unique([loan_id, file_sha256, kind]) @@map("loan_evidences") } // Independently reviewed receipt-to-batch attribution for ambiguous loan // repayments (same lender and amount as another exported/receipted batch). // Partial unique index (one proposed/approved per batch) and history trigger // live in migration 20261006010000_loan_receipt_attribution. model LoanReceiptAttribution { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid fingerprint String @db.VarChar(64) key_id String @db.VarChar(64) verification_ids Json manual_proposal_ids Json kind String @default("settlement") @db.VarChar(16) covered_submission_ids Json @default("[]") failure_scope String @default("batch") @db.VarChar(16) competitor_batch_ids Json basis_kind String @db.VarChar(32) basis_note String @db.VarChar(1000) exclusion_note String @db.VarChar(1000) status String @default("proposed") @db.VarChar(16) proposed_by String @db.Uuid proposed_at DateTime @default(now()) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? @db.VarChar(500) superseded_at DateTime? payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) proposer Employee @relation("LoanReceiptAttributionProposer", fields: [proposed_by], references: [id], onDelete: Restrict) reviewer Employee? @relation("LoanReceiptAttributionReviewer", fields: [reviewed_by], references: [id], onDelete: Restrict) @@index([payment_batch_id, fingerprint], map: "loan_receipt_attributions_batch_fingerprint_idx") @@map("loan_receipt_attributions") } // Loan bank-result reconciliation S1 (migration 20261007010000_loan_bank_submissions). // Append-only/one-way history triggers and partial unique index live in the migration. model PaymentOrderExport { id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid sequence Int exported_at DateTime @default(now()) exported_by String @db.Uuid file_sha256 String @db.VarChar(64) customer_serials Json total_amount Decimal @db.Decimal(14, 2) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) exporter Employee @relation(fields: [exported_by], references: [id], onDelete: Restrict) submissions LoanBankSubmission[] @@unique([payment_batch_id, sequence], map: "payment_order_exports_batch_sequence_key") @@map("payment_order_exports") } model LoanLegacyExportSummary { payment_batch_id String @id @db.Uuid known_export_count Int last_exported_at DateTime? last_exported_by String? @db.Uuid unknown_facts String @default("per_export_detail,file_digest,bank_submission_mapping") @db.VarChar(200) created_at DateTime @default(now()) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) @@map("loan_legacy_export_summaries") } model LoanBankSubmission { id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid export_id String? @db.Uuid channel String @db.VarChar(32) submitted_at DateTime bank_instruction_ref String @db.VarChar(120) customer_serial String? @db.VarChar(64) note String @db.VarChar(1000) status String @default("active") @db.VarChar(16) withdrawn_reason String? @db.VarChar(500) withdrawn_at DateTime? registered_by String @db.Uuid registered_at DateTime @default(now()) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) export PaymentOrderExport? @relation(fields: [export_id], references: [id], onDelete: Restrict) registrar Employee @relation(fields: [registered_by], references: [id], onDelete: Restrict) terminal_facts LoanBankTerminalFact[] @@index([payment_batch_id, status], map: "loan_bank_submissions_batch_idx") @@map("loan_bank_submissions") } model LoanBankSubmissionAttestation { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid submission_ids Json all_submission_ids Json export_ids Json note String @db.VarChar(1000) status String @default("proposed") @db.VarChar(16) proposed_by String @db.Uuid proposed_at DateTime @default(now()) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? @db.VarChar(500) superseded_at DateTime? payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) proposer Employee @relation("LoanSubmissionAttestationProposer", fields: [proposed_by], references: [id], onDelete: Restrict) reviewer Employee? @relation("LoanSubmissionAttestationReviewer", fields: [reviewed_by], references: [id], onDelete: Restrict) @@map("loan_bank_submission_attestations") } // Loan bank-result reconciliation S3 (migration 20261008010000_loan_bank_terminal_facts). // Evidence is stored apart from payment receipts; history triggers live in the migration. model LoanBankTerminalEvidence { evidence_kind String @default("bank_terminal") @db.VarChar(32) id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid storage_path String original_name String @db.VarChar(255) mime_type String @db.VarChar(100) file_size Int file_sha256 String @db.VarChar(64) uploaded_by String @db.Uuid uploaded_at DateTime @default(now()) voided_by String? @db.Uuid voided_at DateTime? void_reason String? @db.VarChar(500) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) uploader Employee @relation(fields: [uploaded_by], references: [id], onDelete: Restrict) facts LoanBankTerminalFact[] bank_result_events LoanBankResultEvent[] @relation("LoanBankEventEvidence") bank_result_corrections LoanBankResultEvent[] @relation("LoanBankEventCorrection") @@index([payment_batch_id], map: "loan_bank_terminal_evidences_batch_idx") @@map("loan_bank_terminal_evidences") } model LoanBankTerminalFact { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid submission_id String @db.Uuid kind String @db.VarChar(32) terminal_status String @db.VarChar(16) evidence_id String? @db.Uuid receipt_attachment_id String? @db.Uuid verification_id String? @db.Uuid resolves_attachment_ids Json @default("[]") note String @db.VarChar(1000) status String @default("proposed") @db.VarChar(16) proposed_by String @db.Uuid proposed_at DateTime @default(now()) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? @db.VarChar(500) superseded_at DateTime? payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) submission LoanBankSubmission @relation(fields: [submission_id], references: [id], onDelete: Restrict) evidence LoanBankTerminalEvidence? @relation(fields: [evidence_id], references: [id], onDelete: Restrict) receipt_attachment PaymentBatchReceiptAttachment? @relation(fields: [receipt_attachment_id], references: [id], onDelete: Restrict) verification PaymentReceiptVerification? @relation(fields: [verification_id], references: [id], onDelete: Restrict) proposer Employee @relation("LoanTerminalFactProposer", fields: [proposed_by], references: [id], onDelete: Restrict) reviewer Employee? @relation("LoanTerminalFactReviewer", fields: [reviewed_by], references: [id], onDelete: Restrict) @@index([payment_batch_id, status], map: "loan_bank_terminal_facts_batch_idx") @@map("loan_bank_terminal_facts") } // One failed bank transaction backs the release of at most one batch. model LoanFailureEvidenceUse { fingerprint String @id @db.VarChar(64) key_id String @db.VarChar(64) payment_batch_id String @db.Uuid source String @db.VarChar(32) created_at DateTime @default(now()) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict) @@map("loan_failure_evidence_uses") } // SR: original bank conclusions remain immutable; recovery controls release only. model LoanReleaseRecovery { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid sequence Int previous_id String? @db.Uuid request_key String @db.Uuid original_state String @db.VarChar(32) original_ref String reason String @db.VarChar(1000) started_by String @db.Uuid started_at DateTime @default(now()) status String @default("collecting") @db.VarChar(16) submitted_by String? @db.Uuid submitted_at DateTime? snapshot_json Json? reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? @db.VarChar(500) ended_at DateTime? cancel_request_key String? @db.Uuid consumed_by String? @db.Uuid payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict, onUpdate: NoAction) starter Employee @relation("LoanReleaseStarter", fields: [started_by], references: [id], onDelete: Restrict, onUpdate: NoAction) submitter Employee? @relation("LoanReleaseSubmitter", fields: [submitted_by], references: [id], onDelete: Restrict, onUpdate: NoAction) reviewer Employee? @relation("LoanReleaseReviewer", fields: [reviewed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) consumer Employee? @relation("LoanReleaseConsumer", fields: [consumed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) previous LoanReleaseRecovery? @relation("LoanRecoveryPrevious", fields: [previous_id], references: [id], onDelete: Restrict, onUpdate: NoAction) next LoanReleaseRecovery[] @relation("LoanRecoveryPrevious") events LoanReleaseRecoveryEvent[] @@unique([payment_batch_id, sequence]) @@unique([payment_batch_id, request_key]) @@map("loan_release_recoveries") } model LoanReleaseRecoveryEvent { id String @id @default(uuid()) @db.Uuid recovery_id String @db.Uuid action String @db.VarChar(32) actor_id String @db.Uuid note String @db.VarChar(1000) created_at DateTime @default(now()) recovery LoanReleaseRecovery @relation(fields: [recovery_id], references: [id], onDelete: Restrict, onUpdate: NoAction) actor Employee @relation(fields: [actor_id], references: [id], onDelete: Restrict, onUpdate: NoAction) @@index([recovery_id]) @@map("loan_release_recovery_events") } model LoanReleaseMaterialRevision { payment_batch_id String @id @db.Uuid revision BigInt @default(0) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict, onUpdate: NoAction) @@map("loan_release_material_revisions") } model LoanNotSubmittedProposal { id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid sequence Int status String @default("proposed") @db.VarChar(16) proposed_by String @db.Uuid proposed_at DateTime @default(now()) payload_json Json snapshot_json Json payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict, onUpdate: NoAction) proposer Employee @relation(fields: [proposed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) reviews LoanNotSubmittedReview[] @@unique([payment_batch_id, sequence]) @@map("loan_not_submitted_proposals") } model LoanNotSubmittedReview { id String @id @default(uuid()) @db.Uuid proposal_id String @db.Uuid reviewed_by String @db.Uuid decision String @db.VarChar(16) reason String @db.VarChar(500) reviewed_at DateTime @default(now()) proposal LoanNotSubmittedProposal @relation(fields: [proposal_id], references: [id], onDelete: Restrict, onUpdate: NoAction) reviewer Employee @relation(fields: [reviewed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) @@unique([proposal_id, reviewed_by]) @@map("loan_not_submitted_reviews") } model LoanFreezeReason { id String @id @default(uuid()) @db.Uuid lender_id String @db.Uuid payment_batch_id String @db.Uuid kind String @db.VarChar(32) source_key String @db.VarChar(160) status String @default("active") @db.VarChar(16) created_by String @db.Uuid created_at DateTime @default(now()) closed_by String? @db.Uuid closed_at DateTime? closure_basis Json? lender LoanLender @relation(fields: [lender_id], references: [id], onDelete: Restrict, onUpdate: NoAction) payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict, onUpdate: NoAction) creator Employee @relation("LoanFreezeCreator", fields: [created_by], references: [id], onDelete: Restrict, onUpdate: NoAction) closer Employee? @relation("LoanFreezeCloser", fields: [closed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) @@unique([kind, source_key]) @@index([lender_id, status]) @@map("loan_freeze_reasons") } model LoanBankResultEvent { loan_approval_mode String @default("independent") @db.VarChar(16) loan_authorization_id String? @db.Uuid loan_approval_context Json? id String @id @default(uuid()) @db.Uuid payment_batch_id String @db.Uuid kind String @db.VarChar(16) parent_id String? @db.Uuid evidence_id String @db.Uuid request_key String @db.Uuid proposed_by String @db.Uuid proposed_at DateTime @default(now()) payload_encrypted String fingerprint String @db.VarChar(64) key_id String @db.VarChar(64) amount Decimal @db.Decimal(14,2) snapshot_json Json status String @default("proposed") @db.VarChar(16) reviewed_by String? @db.Uuid reviewed_at DateTime? review_note String? @db.VarChar(1000) correction_evidence_id String? @db.Uuid payment_batch PaymentBatch @relation(fields: [payment_batch_id], references: [id], onDelete: Restrict, onUpdate: NoAction) evidence LoanBankTerminalEvidence @relation("LoanBankEventEvidence", fields: [evidence_id], references: [id], onDelete: Restrict, onUpdate: NoAction) correction_evidence LoanBankTerminalEvidence? @relation("LoanBankEventCorrection", fields: [correction_evidence_id], references: [id], onDelete: Restrict, onUpdate: NoAction) proposer Employee @relation("LoanBankEventProposer", fields: [proposed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) reviewer Employee? @relation("LoanBankEventReviewer", fields: [reviewed_by], references: [id], onDelete: Restrict, onUpdate: NoAction) parent LoanBankResultEvent? @relation("LoanBankEventParent", fields: [parent_id], references: [id], onDelete: Restrict, onUpdate: NoAction) children LoanBankResultEvent[] @relation("LoanBankEventParent") settlements LoanSupplementalSettlement[] claim LoanBankEventClaim? @@unique([payment_batch_id, request_key]) @@index([payment_batch_id, kind]) @@map("loan_bank_result_events") } model LoanSupplementalSettlement { id String @id @default(uuid()) @db.Uuid event_id String @db.Uuid loan_id String @db.Uuid bank_amount Decimal @db.Decimal(14,2) settled_amount Decimal @db.Decimal(14,2) receivable_amount Decimal @db.Decimal(14,2) created_at DateTime @default(now()) event LoanBankResultEvent @relation(fields: [event_id], references: [id], onDelete: Restrict, onUpdate: NoAction) loan CompanyLoan @relation(fields: [loan_id], references: [id], onDelete: Restrict, onUpdate: NoAction) @@unique([event_id, loan_id]) @@map("loan_supplemental_settlements") } model LoanBankEventClaim { fingerprint String @id @db.VarChar(64) key_id String @db.VarChar(64) event_id String @unique @db.Uuid created_at DateTime @default(now()) event LoanBankResultEvent @relation(fields: [event_id], references: [id], onDelete: Restrict, onUpdate: NoAction) @@map("loan_bank_event_claims") }