feat: Patenschafts-Honig automatisch waehlen (nie cremig, neueste Ernte)
Docker Image bauen und veroeffentlichen / typecheck (push) Successful in 2m18s
Docker Image bauen und veroeffentlichen / test (push) Successful in 5m32s
Docker Image bauen und veroeffentlichen / lint (push) Successful in 3m41s
Docker Image bauen und veroeffentlichen / build-and-push (push) Canceled after 20m38s

Pakete, Abo-Reservierung und Abo-Lieferungen nehmen immer den aktiven,
nicht cremigen Honig der neuesten Ernte mit genug freiem Bestand, bei
gleichem Jahrgang den mit dem meisten Bestand. Feste Honig-Zuordnung
im Admin entfaellt (Spalte bleibt, wird nicht mehr genutzt).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick.RosenloecherandClaude Opus 5.5 committed 2026-10-16 18:35:04 +02:00
1 parent 3ddf0bfa73
commit 1d88bac52e
30 files changed
+1152 -394

No files matched your search

+15 -27
View File
@@ -4,17 +4,24 @@
* 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).
*
* - verknuepft die physischen Einmal-Pakete mit einem Honigprodukt,
* - 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=<slug>):
* 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 --honey=<produkt-slug> (Probelauf)
* tsx scripts/sponsorship-bootstrap.ts --honey=<produkt-slug> --apply (ausfuehren)
* 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;
@@ -70,30 +77,12 @@ const ABO_TEMPLATES: AboTemplate[] = [
},
];
function arg(name: string): string | undefined {
const hit = process.argv.find((value) => value.startsWith(`--${name}=`));
return hit ? hit.slice(name.length + 3) : undefined;
}
async function main(): Promise<void> {
const apply = process.argv.includes("--apply");
const honeySlug = arg("honey");
if (!honeySlug) throw new Error("--honey=<produkt-slug> fehlt.");
const honey = await prisma.product.findUnique({ where: { slug: honeySlug }, select: { id: true, name: true, category: true, isActive: true } });
if (!honey || honey.category !== "HONIG" || !honey.isActive) {
throw new Error(`Honigprodukt "${honeySlug}" nicht gefunden, nicht HONIG oder nicht aktiv.`);
}
console.log(`${apply ? "AUSFUEHREN" : "PROBELAUF"} — Honig: ${honey.name}`);
const physical = await prisma.sponsorshipOffer.findMany({
where: { kind: "EINMALIG", isPhysical: true, honeyProductId: null },
select: { id: true, slug: true },
});
for (const offer of physical) {
console.log(` Paket ${offer.slug}: Honig verknuepfen`);
if (apply) await prisma.sponsorshipOffer.update({ where: { id: offer.id }, data: { honeyProductId: honey.id } });
}
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 } });
@@ -110,7 +99,6 @@ async function main(): Promise<void> {
kind: "ABO",
isActive: false,
isPhysical: true,
honeyProductId: honey.id,
medalTier: "ABO",
},
});
@@ -119,7 +107,7 @@ async function main(): Promise<void> {
const offers = await prisma.sponsorshipOffer.findMany({
orderBy: { sortOrder: "asc" },
select: { slug: true, kind: true, isActive: true, priceCents: true, honeyProductId: true, stripePriceId: true, productId: true },
select: { slug: true, kind: true, isActive: true, priceCents: true, honeyJars: true, stripePriceId: true, productId: true },
});
console.table(offers);
}