3812 行
146 KiB
Plaintext
3812 行
146 KiB
Plaintext
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
|
|
}
|
|
|
|
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])
|
|
@@map("employees")
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
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")
|
|
@@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")
|
|
@@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 {
|
|
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 {
|
|
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")
|
|
@@map("payment_batches")
|
|
}
|
|
|
|
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?
|
|
|
|
@@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[]
|
|
|
|
@@index([attachment_id, created_at])
|
|
@@map("payment_receipt_verifications")
|
|
}
|
|
|
|
model PaymentReceiptManualProposal {
|
|
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")
|
|
}
|