feat(P20T2-1,P20T2-2,P20T2-3): 卡授权/交易/支付标记/发票绑定/ERP出站后端
这个提交包含在:
@@ -0,0 +1,152 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "invoice_pool" ADD COLUMN "travel_order_id" UUID;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "travel_orders" ADD COLUMN "paid_at" TIMESTAMP(3),
|
||||
ADD COLUMN "paid_by" UUID,
|
||||
ADD COLUMN "payment_channel" VARCHAR(20),
|
||||
ADD COLUMN "payment_date" DATE,
|
||||
ADD COLUMN "payment_voucher_no" VARCHAR(50);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "card_authorizations" (
|
||||
"id" UUID NOT NULL,
|
||||
"source" VARCHAR(32) NOT NULL DEFAULT 'manual',
|
||||
"external_auth_no" TEXT NOT NULL,
|
||||
"employee_id" UUID NOT NULL,
|
||||
"department_id" UUID,
|
||||
"travel_request_id" UUID NOT NULL,
|
||||
"budget_pool_id" UUID,
|
||||
"legal_entity_id" UUID NOT NULL,
|
||||
"cost_center_id" UUID NOT NULL,
|
||||
"authorized_amount" DECIMAL(14,2) NOT NULL,
|
||||
"settled_amount" DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
"reversed_amount" DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
"currency" VARCHAR(8) NOT NULL DEFAULT 'CNY',
|
||||
"occurred_at" TIMESTAMP(3),
|
||||
"expires_at" TIMESTAMP(3),
|
||||
"status" VARCHAR(32) NOT NULL DEFAULT 'authorized',
|
||||
"raw_payload" JSONB,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by" UUID,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"updated_by" UUID,
|
||||
|
||||
CONSTRAINT "card_authorizations_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "card_transactions" (
|
||||
"id" UUID NOT NULL,
|
||||
"source" VARCHAR(32) NOT NULL DEFAULT 'manual',
|
||||
"external_txn_id" TEXT NOT NULL,
|
||||
"card_authorization_id" UUID,
|
||||
"employee_id" UUID NOT NULL,
|
||||
"department_id" UUID,
|
||||
"travel_request_id" UUID NOT NULL,
|
||||
"travel_order_id" UUID,
|
||||
"amount" DECIMAL(14,2) NOT NULL,
|
||||
"currency" VARCHAR(8) NOT NULL DEFAULT 'CNY',
|
||||
"txn_type" VARCHAR(20) NOT NULL,
|
||||
"status" VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
"occurred_at" TIMESTAMP(3),
|
||||
"freeze_suggested_at" TIMESTAMP(3),
|
||||
"freeze_suggested_by" UUID,
|
||||
"freeze_reason_code" VARCHAR(32),
|
||||
"freeze_reason_note" TEXT,
|
||||
"raw_payload" JSONB,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"created_by" UUID,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"updated_by" UUID,
|
||||
|
||||
CONSTRAINT "card_transactions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_authorizations_employee_occurred" ON "card_authorizations"("employee_id", "occurred_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_authorizations_department_status" ON "card_authorizations"("department_id", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_authorizations_request_status" ON "card_authorizations"("travel_request_id", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_authorizations_budget_pool" ON "card_authorizations"("budget_pool_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_authorizations_legal_cost_center" ON "card_authorizations"("legal_entity_id", "cost_center_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "card_authorizations_source_auth_ux" ON "card_authorizations"("source", "external_auth_no");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_authorization" ON "card_transactions"("card_authorization_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_employee_occurred" ON "card_transactions"("employee_id", "occurred_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_department_status" ON "card_transactions"("department_id", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_request" ON "card_transactions"("travel_request_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_order" ON "card_transactions"("travel_order_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "idx_card_transactions_freeze_suggested_by" ON "card_transactions"("freeze_suggested_by");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "card_transactions_source_txn_ux" ON "card_transactions"("source", "external_txn_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "invoice_pool_travel_order_id_idx" ON "invoice_pool"("travel_order_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "travel_orders_paid_by_idx" ON "travel_orders"("paid_by");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "invoice_pool" ADD CONSTRAINT "invoice_pool_travel_order_id_fkey" FOREIGN KEY ("travel_order_id") REFERENCES "travel_orders"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "travel_orders" ADD CONSTRAINT "travel_orders_paid_by_fkey" FOREIGN KEY ("paid_by") REFERENCES "employees"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_department_id_fkey" FOREIGN KEY ("department_id") REFERENCES "departments"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_travel_request_id_fkey" FOREIGN KEY ("travel_request_id") REFERENCES "travel_requests"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_budget_pool_id_fkey" FOREIGN KEY ("budget_pool_id") REFERENCES "budget_pools"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_legal_entity_id_fkey" FOREIGN KEY ("legal_entity_id") REFERENCES "legal_entities"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_authorizations" ADD CONSTRAINT "card_authorizations_cost_center_id_fkey" FOREIGN KEY ("cost_center_id") REFERENCES "cost_centers"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_card_authorization_id_fkey" FOREIGN KEY ("card_authorization_id") REFERENCES "card_authorizations"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_department_id_fkey" FOREIGN KEY ("department_id") REFERENCES "departments"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_travel_request_id_fkey" FOREIGN KEY ("travel_request_id") REFERENCES "travel_requests"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_travel_order_id_fkey" FOREIGN KEY ("travel_order_id") REFERENCES "travel_orders"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "card_transactions" ADD CONSTRAINT "card_transactions_freeze_suggested_by_fkey" FOREIGN KEY ("freeze_suggested_by") REFERENCES "employees"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
+111
-5
@@ -230,6 +230,8 @@ model Department {
|
||||
workflow_instances WorkflowInstance[]
|
||||
budget_pools BudgetPool[]
|
||||
travel_orders TravelOrder[]
|
||||
card_authorizations CardAuthorization[]
|
||||
card_transactions CardTransaction[]
|
||||
|
||||
@@index([parent_id])
|
||||
@@map("departments")
|
||||
@@ -300,7 +302,11 @@ model Employee {
|
||||
uploaded_invoices InvoicePool[] @relation("InvoiceUploader")
|
||||
overridden_invoices InvoicePool[] @relation("InvoiceOverrideBy")
|
||||
requested_invoice_verifications InvoiceVerificationRecord[] @relation("InvoiceVerificationRequester")
|
||||
travel_orders TravelOrder[]
|
||||
travel_orders TravelOrder[] @relation("TravelOrderEmployee")
|
||||
paid_travel_orders TravelOrder[] @relation("TravelOrderPaidBy")
|
||||
card_authorizations CardAuthorization[]
|
||||
card_transactions CardTransaction[] @relation("CardTransactionEmployee")
|
||||
freeze_suggested_card_transactions CardTransaction[] @relation("CardTransactionFreezeSuggestedBy")
|
||||
|
||||
workflow_instances_started WorkflowInstance[] @relation("WorkflowInstanceSubmitter")
|
||||
workflow_history_actions WorkflowHistory[] @relation("WorkflowHistoryActor")
|
||||
@@ -487,6 +493,7 @@ model LegalEntity {
|
||||
suppliers Supplier[]
|
||||
purchase_requests PurchaseRequest[]
|
||||
travel_requests TravelRequest[]
|
||||
card_authorizations CardAuthorization[]
|
||||
asset_cards AssetCard[]
|
||||
budget_pools BudgetPool[] @relation("BudgetPoolLegalEntity")
|
||||
|
||||
@@ -517,6 +524,7 @@ model CostCenter {
|
||||
budget_pools BudgetPool[] @relation("BudgetPoolCostCenter")
|
||||
purchase_requests PurchaseRequest[]
|
||||
travel_requests TravelRequest[]
|
||||
card_authorizations CardAuthorization[]
|
||||
asset_cards AssetCard[]
|
||||
|
||||
@@unique([legal_entity_id, code], map: "legal_entity_cost_center_code_ux")
|
||||
@@ -1061,6 +1069,7 @@ model InvoicePool {
|
||||
|
||||
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)
|
||||
@@ -1099,6 +1108,7 @@ model InvoicePool {
|
||||
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])
|
||||
@@ -1109,6 +1119,7 @@ model InvoicePool {
|
||||
@@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")
|
||||
}
|
||||
|
||||
@@ -1169,6 +1180,7 @@ model BudgetPool {
|
||||
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")
|
||||
@@ -1307,9 +1319,11 @@ model TravelRequest {
|
||||
cost_center CostCenter @relation(fields: [cost_center_id], references: [id], onDelete: Restrict)
|
||||
budget_pool BudgetPool? @relation(fields: [budget_pool_id], references: [id], onDelete: SetNull)
|
||||
|
||||
segments TravelRequestSegment[]
|
||||
travel_orders TravelOrder[]
|
||||
workflow_instances WorkflowInstance[]
|
||||
segments TravelRequestSegment[]
|
||||
travel_orders TravelOrder[]
|
||||
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")
|
||||
@@ -1354,6 +1368,11 @@ model TravelOrder {
|
||||
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())
|
||||
@@ -1361,18 +1380,105 @@ model TravelOrder {
|
||||
updated_at DateTime @updatedAt
|
||||
updated_by String? @db.Uuid
|
||||
|
||||
employee Employee @relation(fields: [employee_id], references: [id], onDelete: Restrict)
|
||||
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[]
|
||||
|
||||
@@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 @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 @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)
|
||||
|
||||
@@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 NotificationChannel {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
channel_type String @db.VarChar(32)
|
||||
|
||||
在新工单中引用
屏蔽一个用户