feat(P18B-1,P18B-2): 新增资产流转模型与受控接口

这个提交包含在:
2026-03-07 23:20:34 +08:00
父节点 1b2527eee0
当前提交 946a357f8b
共修改 8 个文件,包含 1276 行新增和 7 行删除
@@ -0,0 +1,113 @@
-- CreateEnum
CREATE TYPE "InventoryCheckScopeType" AS ENUM ('all', 'legal_entity', 'cost_center', 'location');
-- CreateEnum
CREATE TYPE "InventoryCheckStatus" AS ENUM ('draft', 'counting', 'completed');
-- CreateEnum
CREATE TYPE "InventoryCheckResult" AS ENUM ('matched', 'missing', 'extra', 'damaged');
-- CreateTable
CREATE TABLE "asset_assignments" (
"id" UUID NOT NULL,
"asset_id" UUID NOT NULL,
"employee_id" UUID NOT NULL,
"assigned_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"returned_at" TIMESTAMP(3),
"note" TEXT,
CONSTRAINT "asset_assignments_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "asset_transfers" (
"id" UUID NOT NULL,
"asset_id" UUID NOT NULL,
"from_employee_id" UUID,
"to_employee_id" UUID,
"from_location" TEXT,
"to_location" TEXT,
"transferred_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"note" TEXT,
CONSTRAINT "asset_transfers_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "inventory_checks" (
"id" UUID NOT NULL,
"check_no" TEXT NOT NULL,
"scope_type" "InventoryCheckScopeType" NOT NULL,
"scope_ref_id" VARCHAR(200),
"status" "InventoryCheckStatus" NOT NULL DEFAULT 'draft',
"started_at" TIMESTAMP(3),
"completed_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" UUID,
"updated_at" TIMESTAMP(3) NOT NULL,
"updated_by" UUID,
CONSTRAINT "inventory_checks_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "inventory_check_items" (
"id" UUID NOT NULL,
"inventory_check_id" UUID NOT NULL,
"asset_id" UUID NOT NULL,
"result" "InventoryCheckResult" NOT NULL,
"note" TEXT,
CONSTRAINT "inventory_check_items_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "idx_asset_assignments_asset_open" ON "asset_assignments"("asset_id", "returned_at");
-- CreateIndex
CREATE INDEX "idx_asset_assignments_employee_open" ON "asset_assignments"("employee_id", "returned_at");
-- CreateIndex
CREATE INDEX "idx_asset_transfers_asset_time" ON "asset_transfers"("asset_id", "transferred_at");
-- CreateIndex
CREATE INDEX "idx_asset_transfers_from_employee" ON "asset_transfers"("from_employee_id");
-- CreateIndex
CREATE INDEX "idx_asset_transfers_to_employee" ON "asset_transfers"("to_employee_id");
-- CreateIndex
CREATE UNIQUE INDEX "inventory_checks_check_no_key" ON "inventory_checks"("check_no");
-- CreateIndex
CREATE INDEX "idx_inventory_checks_status_created" ON "inventory_checks"("status", "created_at");
-- CreateIndex
CREATE INDEX "idx_inventory_checks_scope" ON "inventory_checks"("scope_type", "scope_ref_id");
-- CreateIndex
CREATE INDEX "idx_inventory_check_items_asset" ON "inventory_check_items"("asset_id");
-- CreateIndex
CREATE UNIQUE INDEX "inventory_check_asset_ux" ON "inventory_check_items"("inventory_check_id", "asset_id");
-- AddForeignKey
ALTER TABLE "asset_assignments" ADD CONSTRAINT "asset_assignments_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "asset_cards"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "asset_assignments" ADD CONSTRAINT "asset_assignments_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "asset_transfers" ADD CONSTRAINT "asset_transfers_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "asset_cards"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "asset_transfers" ADD CONSTRAINT "asset_transfers_from_employee_id_fkey" FOREIGN KEY ("from_employee_id") REFERENCES "employees"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "asset_transfers" ADD CONSTRAINT "asset_transfers_to_employee_id_fkey" FOREIGN KEY ("to_employee_id") REFERENCES "employees"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "inventory_check_items" ADD CONSTRAINT "inventory_check_items_inventory_check_id_fkey" FOREIGN KEY ("inventory_check_id") REFERENCES "inventory_checks"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "inventory_check_items" ADD CONSTRAINT "inventory_check_items_asset_id_fkey" FOREIGN KEY ("asset_id") REFERENCES "asset_cards"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+98
查看文件
@@ -60,6 +60,26 @@ enum AssetCardStatus {
archived
}
enum InventoryCheckScopeType {
all
legal_entity
cost_center
location
}
enum InventoryCheckStatus {
draft
counting
completed
}
enum InventoryCheckResult {
matched
missing
extra
damaged
}
enum LeaveDaySession {
am
pm
@@ -242,6 +262,9 @@ model Employee {
purchase_attachments_uploaded PurchaseAttachment[] @relation("PurchaseAttachmentUploader")
purchase_order_archives PurchaseOrderArchive[] @relation("PurchaseOrderArchiveArchivedBy")
assigned_asset_cards AssetCard[] @relation("AssetCardAssignee")
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")
@@ -715,6 +738,9 @@ model AssetCard {
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)
assignments AssetAssignment[]
transfers AssetTransfer[]
inventory_items InventoryCheckItem[]
@@index([category_id], map: "idx_asset_cards_category")
@@index([legal_entity_id], map: "idx_asset_cards_legal_entity")
@@ -725,6 +751,78 @@ model AssetCard {
@@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 @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 {
id String @id @default(uuid()) @db.Uuid
form_number String? @unique