R47 A1-A8:完成薪资管理模块

这个提交包含在:
2026-03-29 19:05:55 +08:00
父节点 c0384b5bbf
当前提交 7ba72ca87d
共修改 25 个文件,包含 3598 行新增和 4 行删除
@@ -0,0 +1,108 @@
-- CreateEnum
CREATE TYPE "SalaryItemType" AS ENUM ('earning', 'deduction');
-- CreateEnum
CREATE TYPE "PayslipStatus" AS ENUM ('draft', 'issued');
-- CreateTable
CREATE TABLE "salary_items" (
"id" UUID NOT NULL,
"name" TEXT NOT NULL,
"item_type" "SalaryItemType" NOT NULL,
"sort_order" INTEGER NOT NULL,
"enabled" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" UUID,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_by" UUID,
CONSTRAINT "salary_items_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "employee_salaries" (
"id" UUID NOT NULL,
"employee_id" UUID NOT NULL,
"salary_item_id" UUID NOT NULL,
"monthly_amount" DECIMAL(12,2) NOT NULL,
"effective_date" DATE NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" UUID,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_by" UUID,
CONSTRAINT "employee_salaries_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "payslips" (
"id" UUID NOT NULL,
"employee_id" UUID NOT NULL,
"pay_month" DATE NOT NULL,
"status" "PayslipStatus" NOT NULL DEFAULT 'draft',
"gross_amount" DECIMAL(12,2) NOT NULL DEFAULT 0,
"deduction_amount" DECIMAL(12,2) NOT NULL DEFAULT 0,
"net_amount" DECIMAL(12,2) NOT NULL DEFAULT 0,
"issued_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" UUID,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_by" UUID,
CONSTRAINT "payslips_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "payslip_items" (
"id" UUID NOT NULL,
"payslip_id" UUID NOT NULL,
"salary_item_id" UUID NOT NULL,
"amount" DECIMAL(12,2) NOT NULL DEFAULT 0,
CONSTRAINT "payslip_items_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "salary_items_name_key" ON "salary_items"("name");
-- CreateIndex
CREATE INDEX "idx_salary_items_enabled_sort" ON "salary_items"("enabled", "sort_order");
-- CreateIndex
CREATE UNIQUE INDEX "employee_salaries_employee_item_effective_ux" ON "employee_salaries"("employee_id", "salary_item_id", "effective_date");
-- CreateIndex
CREATE INDEX "idx_employee_salaries_employee_effective" ON "employee_salaries"("employee_id", "effective_date");
-- CreateIndex
CREATE INDEX "idx_employee_salaries_salary_item" ON "employee_salaries"("salary_item_id");
-- CreateIndex
CREATE UNIQUE INDEX "payslips_employee_month_ux" ON "payslips"("employee_id", "pay_month");
-- CreateIndex
CREATE INDEX "idx_payslips_month_status" ON "payslips"("pay_month", "status");
-- CreateIndex
CREATE INDEX "idx_payslips_employee_month" ON "payslips"("employee_id", "pay_month");
-- CreateIndex
CREATE UNIQUE INDEX "payslip_items_payslip_salary_item_ux" ON "payslip_items"("payslip_id", "salary_item_id");
-- CreateIndex
CREATE INDEX "idx_payslip_items_salary_item" ON "payslip_items"("salary_item_id");
-- AddForeignKey
ALTER TABLE "employee_salaries" ADD CONSTRAINT "employee_salaries_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "employee_salaries" ADD CONSTRAINT "employee_salaries_salary_item_id_fkey" FOREIGN KEY ("salary_item_id") REFERENCES "salary_items"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "payslips" ADD CONSTRAINT "payslips_employee_id_fkey" FOREIGN KEY ("employee_id") REFERENCES "employees"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "payslip_items" ADD CONSTRAINT "payslip_items_payslip_id_fkey" FOREIGN KEY ("payslip_id") REFERENCES "payslips"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "payslip_items" ADD CONSTRAINT "payslip_items_salary_item_id_fkey" FOREIGN KEY ("salary_item_id") REFERENCES "salary_items"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
+90
查看文件
@@ -363,6 +363,16 @@ enum EmployeeTrainingStatus {
cancelled
}
enum SalaryItemType {
earning
deduction
}
enum PayslipStatus {
draft
issued
}
enum PerformanceReviewCycleType {
monthly
quarterly
@@ -630,6 +640,8 @@ model Employee {
contracts EmployeeContract[]
trainings EmployeeTraining[]
certificates EmployeeCertificate[]
salary_profiles EmployeeSalary[]
payslips Payslip[]
performance_reviews_received PerformanceReview[] @relation("PerformanceReviewEmployee")
performance_reviews_authored PerformanceReview[] @relation("PerformanceReviewReviewer")
@@ -2089,6 +2101,84 @@ model EmployeeCertificate {
@@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