feat(P15B-1,P15B-6): 完成请假V1闭环
这个提交包含在:
+205
-110
@@ -44,6 +44,19 @@ enum LeaveRequestStatus {
|
||||
cancelled
|
||||
}
|
||||
|
||||
enum LeaveDaySession {
|
||||
am
|
||||
pm
|
||||
}
|
||||
|
||||
enum LeaveLedgerEntryType {
|
||||
grant
|
||||
reserve
|
||||
consume
|
||||
release
|
||||
adjust
|
||||
}
|
||||
|
||||
enum InvoicePoolStatus {
|
||||
pending_ocr
|
||||
ocr_failed
|
||||
@@ -159,13 +172,13 @@ model Employee {
|
||||
bank_name String
|
||||
id_number_encrypted String?
|
||||
|
||||
password_hash String
|
||||
token_version Int @default(0)
|
||||
must_change_password Boolean @default(false)
|
||||
login_failed_count Int @default(0)
|
||||
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?
|
||||
archived_at DateTime?
|
||||
archived_at DateTime?
|
||||
|
||||
created_at DateTime @default(now())
|
||||
created_by String? @db.Uuid
|
||||
@@ -182,19 +195,20 @@ model Employee {
|
||||
delegation_grants_as_delegate DelegationGrant[] @relation("DelegationDelegate")
|
||||
|
||||
auth_sessions AuthSession[]
|
||||
audit_logs AuditLog[] @relation("AuditActor")
|
||||
audit_logs AuditLog[] @relation("AuditActor")
|
||||
notifications Notification[]
|
||||
|
||||
submitted_reimbursements ReimbursementForm[] @relation("ReimbursementSubmitter")
|
||||
owned_reimbursements ReimbursementForm[] @relation("ReimbursementOwner")
|
||||
paid_reimbursements ReimbursementForm[] @relation("ReimbursementPaidBy")
|
||||
leave_requests LeaveRequest[]
|
||||
leave_ledgers LeaveLedger[]
|
||||
|
||||
owned_invoices InvoicePool[] @relation("InvoiceOwner")
|
||||
uploaded_invoices InvoicePool[] @relation("InvoiceUploader")
|
||||
overridden_invoices InvoicePool[] @relation("InvoiceOverrideBy")
|
||||
owned_invoices InvoicePool[] @relation("InvoiceOwner")
|
||||
uploaded_invoices InvoicePool[] @relation("InvoiceUploader")
|
||||
overridden_invoices InvoicePool[] @relation("InvoiceOverrideBy")
|
||||
requested_invoice_verifications InvoiceVerificationRecord[] @relation("InvoiceVerificationRequester")
|
||||
travel_orders TravelOrder[]
|
||||
travel_orders TravelOrder[]
|
||||
|
||||
workflow_instances_started WorkflowInstance[] @relation("WorkflowInstanceSubmitter")
|
||||
workflow_history_actions WorkflowHistory[] @relation("WorkflowHistoryActor")
|
||||
@@ -302,15 +316,15 @@ model AuditLog {
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
target_type String? @db.VarChar(64)
|
||||
target_id String? @db.Uuid
|
||||
read_at DateTime?
|
||||
created_at DateTime @default(now())
|
||||
created_at DateTime @default(now())
|
||||
|
||||
recipient Employee @relation(fields: [recipient_employee_id], references: [id], onDelete: Cascade)
|
||||
|
||||
@@ -383,10 +397,10 @@ model ReimbursementForm {
|
||||
paid_by_employee Employee? @relation("ReimbursementPaidBy", fields: [paid_by], references: [id], onDelete: SetNull)
|
||||
department Department @relation(fields: [department_id], references: [id], onDelete: Restrict)
|
||||
|
||||
items ReimbursementItem[]
|
||||
invoice_pool_items InvoicePool[]
|
||||
workflow_instances WorkflowInstance[]
|
||||
approval_transfers ApprovalTransfer[]
|
||||
items ReimbursementItem[]
|
||||
invoice_pool_items InvoicePool[]
|
||||
workflow_instances WorkflowInstance[]
|
||||
approval_transfers ApprovalTransfer[]
|
||||
budget_ledger_entries BudgetLedgerEntry[]
|
||||
travel_orders TravelOrder[]
|
||||
|
||||
@@ -424,32 +438,113 @@ model ReimbursementItem {
|
||||
@@map("reimbursement_items")
|
||||
}
|
||||
|
||||
model LeaveRequest {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
owner_id String @db.Uuid
|
||||
department_id String @db.Uuid
|
||||
start_date DateTime @db.Date
|
||||
end_date DateTime @db.Date
|
||||
reason String?
|
||||
status LeaveRequestStatus @default(draft)
|
||||
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 @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_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 @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 @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
|
||||
@@ -484,15 +579,15 @@ model InvoicePool {
|
||||
linked_item_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_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)
|
||||
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?
|
||||
@@ -517,9 +612,9 @@ model InvoicePool {
|
||||
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)
|
||||
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)
|
||||
verification_records InvoiceVerificationRecord[]
|
||||
|
||||
@@index([owner_employee_id])
|
||||
@@ -534,27 +629,27 @@ model InvoicePool {
|
||||
}
|
||||
|
||||
model InvoiceVerificationRecord {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
invoice_id String @db.Uuid
|
||||
provider String @db.VarChar(32)
|
||||
status String @db.VarChar(16)
|
||||
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
|
||||
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)
|
||||
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")
|
||||
|
||||
@@ -565,16 +660,16 @@ model InvoiceVerificationRecord {
|
||||
}
|
||||
|
||||
model BudgetPool {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code String @unique
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
code String @unique
|
||||
name String
|
||||
department_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)
|
||||
department_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())
|
||||
@@ -609,13 +704,13 @@ model BudgetLedgerEntry {
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
note String?
|
||||
version Int @default(1)
|
||||
|
||||
created_at DateTime @default(now())
|
||||
created_by String? @db.Uuid
|
||||
@@ -627,16 +722,16 @@ model FeatureFlag {
|
||||
}
|
||||
|
||||
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?
|
||||
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())
|
||||
@@ -650,16 +745,16 @@ model IntegrationOutbox {
|
||||
}
|
||||
|
||||
model TravelOrder {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
source String @default("manual") @db.VarChar(32)
|
||||
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
|
||||
employee_id String @db.Uuid
|
||||
department_id String? @db.Uuid
|
||||
linked_reimbursement_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)
|
||||
amount Decimal? @db.Decimal(14, 2)
|
||||
currency String @default("CNY") @db.VarChar(8)
|
||||
status String @default("imported") @db.VarChar(20)
|
||||
raw_payload Json?
|
||||
|
||||
created_at DateTime @default(now())
|
||||
@@ -678,11 +773,11 @@ model TravelOrder {
|
||||
}
|
||||
|
||||
model NotificationChannel {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
channel_type String @db.VarChar(32)
|
||||
name String
|
||||
enabled Boolean @default(true)
|
||||
config_json Json
|
||||
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())
|
||||
@@ -714,18 +809,18 @@ model WorkflowDefinition {
|
||||
}
|
||||
|
||||
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
|
||||
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?
|
||||
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
|
||||
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
|
||||
|
||||
在新工单中引用
屏蔽一个用户