L14 Abrechnungsübersicht: Datenmodell, Migration, Rechte und Modul
Neue Tenant-Tabellen work_order_milestones und billing_records (RLS, TENANT_MODELS, PII-Felder), Partial-Unique-Indizes je Quelle, billing_record_id an time_entries/material_usages. Rechte billing:read/billing:write (Backoffice, Mandantenadmin), Modul billing, Events milestone.*. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "MilestoneStatus" AS ENUM ('open', 'reached', 'confirmed', 'billed');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "BillingRecordKind" AS ENUM ('order_completion', 'milestone', 'daily_report');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "BillingRecordStatus" AS ENUM ('open', 'billed', 'voided');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "material_usages" ADD COLUMN "billing_record_id" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "time_entries" ADD COLUMN "billing_record_id" TEXT;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "work_order_milestones" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenant_id" TEXT NOT NULL,
|
||||
"work_order_id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"sort_order" INTEGER NOT NULL DEFAULT 0,
|
||||
"status" "MilestoneStatus" NOT NULL DEFAULT 'open',
|
||||
"reached_by_id" TEXT,
|
||||
"reached_at" TIMESTAMP(3),
|
||||
"reached_note" TEXT,
|
||||
"confirmed_by_id" TEXT,
|
||||
"confirmed_at" TIMESTAMP(3),
|
||||
"rejected_by_id" TEXT,
|
||||
"rejected_at" TIMESTAMP(3),
|
||||
"rejection_reason" TEXT,
|
||||
"billing_record_id" TEXT,
|
||||
"created_by_id" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
"deleted_at" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "work_order_milestones_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "billing_records" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tenant_id" TEXT NOT NULL,
|
||||
"work_order_id" TEXT NOT NULL,
|
||||
"kind" "BillingRecordKind" NOT NULL,
|
||||
"milestone_id" TEXT,
|
||||
"report_id" TEXT,
|
||||
"period_from" TIMESTAMP(3) NOT NULL,
|
||||
"period_to" TIMESTAMP(3) NOT NULL,
|
||||
"status" "BillingRecordStatus" NOT NULL DEFAULT 'open',
|
||||
"snapshot" JSONB,
|
||||
"pdf_document_id" TEXT,
|
||||
"pdf_checksum" TEXT,
|
||||
"invoice_number" TEXT,
|
||||
"billed_by_id" TEXT,
|
||||
"billed_at" TIMESTAMP(3),
|
||||
"voided_by_id" TEXT,
|
||||
"voided_at" TIMESTAMP(3),
|
||||
"void_reason" TEXT,
|
||||
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "billing_records_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "work_order_milestones_tenant_id_work_order_id_idx" ON "work_order_milestones"("tenant_id", "work_order_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "work_order_milestones_tenant_id_status_idx" ON "work_order_milestones"("tenant_id", "status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "billing_records_tenant_id_status_created_at_idx" ON "billing_records"("tenant_id", "status", "created_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "billing_records_tenant_id_work_order_id_idx" ON "billing_records"("tenant_id", "work_order_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "material_usages_tenant_id_billing_record_id_idx" ON "material_usages"("tenant_id", "billing_record_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "time_entries_tenant_id_billing_record_id_idx" ON "time_entries"("tenant_id", "billing_record_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "work_order_milestones" ADD CONSTRAINT "work_order_milestones_work_order_id_fkey" FOREIGN KEY ("work_order_id") REFERENCES "work_orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "billing_records" ADD CONSTRAINT "billing_records_work_order_id_fkey" FOREIGN KEY ("work_order_id") REFERENCES "work_orders"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
|
||||
-- L14 Abrechnungsübersicht: Mandantentrennung (RLS) für die neuen Tabellen
|
||||
SELECT enable_tenant_rls('work_order_milestones');
|
||||
SELECT enable_tenant_rls('billing_records');
|
||||
|
||||
-- Höchstens ein nicht stornierter Abrechnungseintrag je Quelle (Stornierung legt einen neuen offenen Eintrag an)
|
||||
CREATE UNIQUE INDEX "billing_records_order_completion_active_key" ON "billing_records"("tenant_id", "work_order_id") WHERE "kind" = 'order_completion' AND "status" <> 'voided';
|
||||
CREATE UNIQUE INDEX "billing_records_milestone_active_key" ON "billing_records"("tenant_id", "milestone_id") WHERE "kind" = 'milestone' AND "status" <> 'voided';
|
||||
CREATE UNIQUE INDEX "billing_records_daily_report_active_key" ON "billing_records"("tenant_id", "report_id") WHERE "kind" = 'daily_report' AND "status" <> 'voided';
|
||||
Reference in New Issue
Block a user