L14 Abrechnungsübersicht: Backoffice-Übersicht, Detail, Druckansicht, Meilensteine im Auftrag und mobil, API
/billing mit Tabs Offen/Abgerechnet/Storniert, Filtern und Mehrfachdruck; /billing/[id] mit Abrechnungsblatt und Aktionen (abgerechnet mit Rechnungsnummer, PDF, Rechnungsnummer ändern, stornieren); /billing/print; Auftrags-Tab „Meilensteine & Abrechnung“; mobiler Abschnitt „Erreicht melden“ (offline); Dashboard-Kachel „Bereit zur Abrechnung“; /api/v1/billing*, Meilenstein-Endpunkte und OpenAPI. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import { requireApiContext } from "@/server/api/context";
|
||||
import { paginated, parsePagination, withApi } from "@/server/api/respond";
|
||||
import { listBillingRecords } from "@/server/services/billing/queries";
|
||||
|
||||
/**
|
||||
* GET /api/v1/billing — billing overview (L14). Query: status (open|billed|voided, default open), kind,
|
||||
* customerId, teamId, from/to (YYYY-MM-DD), q, page, pageSize. No prices or amounts.
|
||||
*/
|
||||
export const GET = withApi(async (req: Request) => {
|
||||
const ctx = await requireApiContext("billing", "billing:read");
|
||||
const url = new URL(req.url);
|
||||
const { page, pageSize } = parsePagination(url);
|
||||
const sp = url.searchParams;
|
||||
const res = await listBillingRecords(ctx, {
|
||||
status: (sp.get("status") ?? undefined) as never,
|
||||
kind: (sp.get("kind") ?? undefined) as never,
|
||||
customerId: sp.get("customerId") ?? undefined,
|
||||
teamId: sp.get("teamId") ?? undefined,
|
||||
from: sp.get("from") ?? undefined,
|
||||
to: sp.get("to") ?? undefined,
|
||||
q: sp.get("q") ?? undefined,
|
||||
page,
|
||||
pageSize,
|
||||
});
|
||||
return paginated(res.items, res.total, res.page, res.pageSize);
|
||||
});
|
||||
Reference in New Issue
Block a user