feat: Bienenpatenschaft mit Urkunde, Abo, Medaillen und 3D-Konto
Setzt Teilprojekte 1-5 der Spec 2026-10-16 um: - Urkunden-Engine (lib/certificate): ein Layout fuer PDF, Vorschau und 3D-Textur, Vorlage classic@1, eingebettete OFL-Schriften, Testmatrix - Einmal-Patenschaft ueber Traegerprodukte (Kategorie PATENSCHAFT), Paket wird im Checkout in Patenschaft (Regelsatz) und Honig aufgeteilt, Kontopflicht, rein digitale Bestellungen (FulfillmentMethod DIGITAL) - Ausstellung nach Zahlung idempotent, Wiederholung im App-Prozess (instrumentation + background-jobs), Ablage in CERTIFICATE_DIR - Verkaufsseite /patenschaft mit Konfigurator und Live-Vorschau, Warenkorb mit Schluessel je Position - Kundenkonto: 3D-Ansicht von Urkunde und Medaille, Downloads, ZIP, Uebertragung per befristetem Einmal-Link, Treuestufen bis VIP - Admin: Angebote, Patenschaften, Druck, Korrektur mit Revisionen, Abos, Erntefenster, Deckung, SEPA-Frist, Treuestufen - Abo ueber Stripe Billing: Lieferung erst nach bezahlten Monaten, SEPA-Neukunden-Frist und Rueckbuchungsschutz, Honigreservierung, Kuendigungsbutton, Monatsrechnungen, Stripe-Einrichtungsskript Startangebote werden inaktiv angelegt; Livebetrieb erst nach Freigabe. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
dcb578f062
commit
f227aeb8f9
269 files changed
+28054
-141
No files matched your search
@@ -11,6 +11,7 @@ import { checkUploadFiles } from "@/lib/upload-health";
|
||||
import { checkUploadVolume } from "@/lib/uploads";
|
||||
import { getCurrentAdmin } from "@/lib/auth";
|
||||
import { HexMark } from "@/components/honeycomb";
|
||||
import { getSponsorshipAttentionItems } from "@/app/admin/patenschaften/_lib/attention";
|
||||
|
||||
const DASHBOARD_ICON_PROPS = {
|
||||
width: 20,
|
||||
@@ -266,7 +267,7 @@ export default async function AdminDashboardPage(props: PageProps<"/admin">) {
|
||||
const stockRejected = stockIssues.rejected;
|
||||
const unlinkedProducts = stockIssues.unlinked;
|
||||
|
||||
const [admin, waitingOrders, waitingReturns, waitingReviews, waitingInquiries] = await Promise.all([
|
||||
const [admin, waitingOrders, waitingReturns, waitingReviews, waitingInquiries, sponsorshipItems] = await Promise.all([
|
||||
getCurrentAdmin(),
|
||||
prisma.order.count({
|
||||
where: { status: { in: ["BEZAHLT", "IN_VORBEREITUNG", "VERSANDBEREIT", "ABHOLBEREIT"] }, archivedAt: null },
|
||||
@@ -274,6 +275,9 @@ export default async function AdminDashboardPage(props: PageProps<"/admin">) {
|
||||
prisma.returnRequest.count({ where: { status: "ANGEFRAGT" } }),
|
||||
prisma.review.count({ where: pendingReviewWhere() }),
|
||||
prisma.businessInquiry.count({ where: { status: "NEU" } }),
|
||||
// Bienenpatenschaft: gescheiterte Ausstellung, liegengebliebener Druck,
|
||||
// Honigdeckung der Abos, Abos im Verzug (siehe patenschaften/_lib/attention.ts).
|
||||
getSponsorshipAttentionItems(locale),
|
||||
]);
|
||||
const toDo = [
|
||||
{ count: waitingOrders, href: "/admin/bestellungen", label: t.adminDashboardPage.toDoOrders(waitingOrders) },
|
||||
@@ -283,6 +287,7 @@ export default async function AdminDashboardPage(props: PageProps<"/admin">) {
|
||||
{ count: stockRejected, href: "/admin/bestellungen", label: t.adminDashboardPage.toDoStockRejected(stockRejected) },
|
||||
{ count: stockOverdue, href: "/admin", label: t.adminDashboardPage.toDoStockOverdue(stockOverdue) },
|
||||
{ count: unlinkedProducts, href: "/admin/produkte", label: t.adminDashboardPage.toDoUnlinkedProducts(unlinkedProducts) },
|
||||
...sponsorshipItems,
|
||||
].filter((item) => item.count > 0);
|
||||
|
||||
// Begruessung nach Tageszeit in Berliner Zeit (der Server laeuft in UTC).
|
||||
|
||||
Reference in new issue
Block a user