/** * Ersteinrichtung der Bienenpatenschaft in einer bestehenden Installation. * * Wiederholbar: legt nur an, was fehlt, und aendert nie ein Angebot, das der * Inhaber schon bearbeitet hat (Felder werden nur gesetzt, wenn sie leer sind). * * - legt die beiden Abo-Angebote INAKTIV an (Testpreise, im Admin pruefen), * - legt fuer jedes Abo-Angebot Stripe-Produkt, Monatspreis und * Traegerprodukt an (syncOfferStripePrice). * * Einen Honig verknuepft das Skript nicht mehr (frueher --honey=): * Pakete und Abos bekommen ihren Honig automatisch — nie cremig, neueste * Ernte, genug Bestand (lib/sponsorship/honey-selection.ts). Die Spalte * honeyProductId bleibt ungenutzt im Schema; der Probelauf zeigt zur * Kontrolle, welchen Honig die Regel gerade waehlen wuerde. * * Aufruf (Werkzeug-Image, Umgebung wie die App): * tsx scripts/sponsorship-bootstrap.ts (Probelauf) * tsx scripts/sponsorship-bootstrap.ts --apply (ausfuehren) */ import { prisma } from "@/lib/prisma"; import { syncOfferStripePrice } from "@/lib/sponsorship-subscription/stripe-prices"; import { loadHoneyCandidates } from "@/lib/sponsorship/honey-candidates"; import { honeyLabel, pickHoneyProduct } from "@/lib/sponsorship/honey-selection"; interface AboTemplate { slug: string; name: string; nameEn: string; description: string; descriptionEn: string; features: string[]; featuresEn: string[]; priceCents: number; honeyJars: number; honeyShareCentsPerMonth: number; cycle: "VIERTELJAEHRLICH" | "ERNTE"; maxActiveSubscriptions: number; sortOrder: number; } // Kurze Namen: die Verkaufsseite zeigt sie unter "Im Abo", Stripe und die // Rechnung als "Bienenpatenschaft-Abo ". // Testpreise — vor der Aktivierung kaufmaennisch pruefen (Spec, "Geschaeftliche // Konfiguration"). Honiganteil je Monat = Glaeser je Lieferung × 7 € ÷ Monate // je Lieferung, zum Honig-Steuersatz. const ABO_TEMPLATES: AboTemplate[] = [ { slug: "abo-vierteljaehrlich", name: "Vierteljährlich", nameEn: "Quarterly", description: "Monatlich zahlen, alle drei bezahlten Monate zwei Gläser Wabenhain-Honig. Versand inklusive, monatlich kündbar.", descriptionEn: "Pay monthly, two jars of Wabenhain honey after every three paid months. Shipping included, cancel monthly.", features: ["Symbolische Namensgebung mit Urkunde", "2 × 500 g Honig nach jeweils 3 bezahlten Monaten", "Versand inklusive", "Monatlich kündbar"], featuresEn: ["Symbolic naming with certificate", "2 × 500 g honey after every 3 paid months", "Shipping included", "Cancel monthly"], priceCents: 1290, honeyJars: 2, honeyShareCentsPerMonth: 467, cycle: "VIERTELJAEHRLICH", maxActiveSubscriptions: 20, sortOrder: 10, }, { slug: "abo-ernte", name: "Nach der Ernte", nameEn: "After the harvest", description: "Monatlich zahlen, Honig frisch nach der Ernte: drei Gläser, sobald seit der letzten Lieferung sechs Monate bezahlt sind. Versand inklusive, monatlich kündbar.", descriptionEn: "Pay monthly, honey fresh after the harvest: three jars once six months have been paid since the last delivery. Shipping included, cancel monthly.", features: ["Symbolische Namensgebung mit Urkunde", "3 × 500 g Honig im Erntefenster", "Versand inklusive", "Monatlich kündbar"], featuresEn: ["Symbolic naming with certificate", "3 × 500 g honey in the harvest window", "Shipping included", "Cancel monthly"], priceCents: 990, honeyJars: 3, honeyShareCentsPerMonth: 350, cycle: "ERNTE", maxActiveSubscriptions: 10, sortOrder: 11, }, ]; async function main(): Promise { const apply = process.argv.includes("--apply"); const honey = pickHoneyProduct(await loadHoneyCandidates(), 1); console.log( `${apply ? "AUSFUEHREN" : "PROBELAUF"} — Honig automatisch, derzeit: ${honey ? honeyLabel(honey) : "kein nicht-cremiger Honig mit freiem Bestand"}` ); for (const template of ABO_TEMPLATES) { const existing = await prisma.sponsorshipOffer.findUnique({ where: { slug: template.slug }, select: { id: true, stripePriceId: true } }); if (existing) { console.log(` Abo ${template.slug}: vorhanden${existing.stripePriceId ? "" : ", Stripe-Preis fehlt"}`); if (apply && !existing.stripePriceId) await syncOfferStripePrice(existing.id); continue; } console.log(` Abo ${template.slug}: anlegen (inaktiv, ${(template.priceCents / 100).toFixed(2)} €/Monat) + Stripe-Preis`); if (!apply) continue; const created = await prisma.sponsorshipOffer.create({ data: { ...template, kind: "ABO", isActive: false, isPhysical: true, medalTier: "ABO", }, }); await syncOfferStripePrice(created.id); } const offers = await prisma.sponsorshipOffer.findMany({ orderBy: { sortOrder: "asc" }, select: { slug: true, kind: true, isActive: true, priceCents: true, honeyJars: true, stripePriceId: true, productId: true }, }); console.table(offers); } main() .catch((error: unknown) => { console.error(error); process.exitCode = 1; }) .finally(async () => { await prisma.$disconnect(); });