L14 Abrechnungsübersicht: Tests, Backfill, Smoke und Lane-Bericht

test-abrechnung-service (118 Prüfungen inkl. Mandantentrennung und PDF-Render-Smoke), test-abrechnung-sync (21), Fixture-Zeilen für die neuen Tenant-Modelle, Rollen-Matrix billing:*, smoke-auth um /billing, Detail, Druckansicht, Auftrags-Tab und mobile Meilensteine erweitert, scripts/billing-backfill.ts, docs/craftvia/lanes/abrechnung.md, ABNAHME §3 „Abrechnungsübersicht“ (keine Buchhaltung). Gate 69/69, RLS 69/69.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 10:36:10 +02:00
co-authored by Claude Opus 5
parent b76c1bdbfd
commit 2df785dd14
8 changed files with 662 additions and 2 deletions
+12
View File
@@ -38,6 +38,8 @@ import { queryAuditLog } from "../src/server/services/audit/viewer";
import { getAiGenerationContent } from "../src/server/services/lotse/protocol";
import { checkCompleteness } from "../src/server/services/lotse/completeness";
import { noteCreatePayload } from "../src/lib/sync/ops";
import { listBillingRecords } from "../src/server/services/billing/queries";
import { confirmMilestone } from "../src/server/services/billing/milestones";
import { codeOf, createTenant, ok, runSuite, section, type Persona, type TenantFixture } from "./lib/e2e-fixture";
const SLUG = "zz-q-sec-roles";
@@ -123,6 +125,16 @@ runSuite("Sicherheit: Rollen-Matrix", [SLUG], async () => {
{ permission: "notification:read", label: "Benachrichtigungen", run: (c) => listNotifications(c, {}) },
{ permission: "settings:templates", label: "Auftragsart anlegen", run: (c) => createOrderType(c, { key: `rolle_${randomUUID().slice(0, 8).replace(/-/g, "")}`, name: "Rollenprüfung" }) },
{ permission: "lotse:use", label: "Lotse-Vollständigkeitsprüfung", run: (c) => checkCompleteness(c, shared.id) },
// L14 Abrechnungsübersicht
{ permission: "billing:read", label: "Abrechnungsübersicht lesen", run: (c) => listBillingRecords(c) },
{
permission: "billing:write",
label: "Meilenstein bestätigen",
run: async (c) => {
const m = await prisma.workOrderMilestone.create({ data: { tenantId: A.tenantId, workOrderId: shared.id, title: `Rollen ${randomUUID()}`, status: "reached" } });
return confirmMilestone(c, m.id);
},
},
];
section("Matrix-Abdeckung");