feat: Buchung sofort möglich, sobald alle Freigaben erteilt sind
Docker-Images bauen und veroeffentlichen / build-and-push (push) Successful in 2m54s

Vor dem 01.11.2026 gilt dann der Early-Bird-Preis. Fehlt eine Freigabe, bleibt die Vorschau.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-06 23:07:39 +02:00
1 parent a76a9cf616
commit 5c2878875b
3 files changed
+18 -4

No files matched your search

+1 -1
View File
@@ -85,7 +85,7 @@ Der gehostete Checkout bildet den Ablauf vollständig ab: Betrag, Ablaufzeit, da
`src/lib/sales-gate.ts` wird von jedem Checkout-Endpunkt aufgerufen. `src/lib/sales-gate.ts` wird von jedem Checkout-Endpunkt aufgerufen.
- **Livemodus (`sk_live_`):** Verkauf nur mit laufender echter Preisphase, eingeschaltetem Live-Verkauf und allen elf Bestätigungen. - **Livemodus (`sk_live_`):** Verkauf nur mit eingeschaltetem Live-Verkauf und allen elf Bestätigungen. Sind alle erteilt, startet der Verkauf sofort, auch vor dem 01.11.2026; bis dahin gilt der Early-Bird-Preis (seit 06.10.2026).
- **Testmodus:** Checkout ist ohne Freigaben möglich, die Preisphase lässt sich simulieren. - **Testmodus:** Checkout ist ohne Freigaben möglich, die Preisphase lässt sich simulieren.
- **Schutz vor Fehlkonfiguration:** Ein Live-Schlüssel außerhalb von `APP_ENV=production` bricht mit einem Fehler ab. - **Schutz vor Fehlkonfiguration:** Ein Live-Schlüssel außerhalb von `APP_ENV=production` bricht mit einem Fehler ab.
+4 -1
View File
@@ -107,8 +107,11 @@ export function releaseBlockers(camp: CampGateFields): ReleaseBlocker[] {
export function evaluateSales(now: Date, camp: CampGateFields, mode: StripeMode): SalesState { export function evaluateSales(now: Date, camp: CampGateFields, mode: StripeMode): SalesState {
const phase = pricePhaseAt(now); const phase = pricePhaseAt(now);
const simulate = mode === "test" && camp.testPhaseOverride !== null && camp.testPhaseOverride !== "PREVIEW"; const simulate = mode === "test" && camp.testPhaseOverride !== null && camp.testPhaseOverride !== "PREVIEW";
const effectivePhase = simulate ? camp.testPhaseOverride! : phase;
const blockers = releaseBlockers(camp); const blockers = releaseBlockers(camp);
// Sind alle Freigaben bestaetigt, startet der Verkauf sofort, auch vor dem
// 01.11.2026: Bis dahin gilt der Early-Bird-Preis.
const releasedEarly = phase === "PREVIEW" && blockers.length === 0;
const effectivePhase = simulate ? camp.testPhaseOverride! : releasedEarly ? "EARLY_BIRD" : phase;
const campStarted = camp.campStartDate !== null && now.getTime() >= berlinStartOfDay(camp.campStartDate).getTime(); const campStarted = camp.campStartDate !== null && now.getTime() >= berlinStartOfDay(camp.campStartDate).getTime();
let closedReason: SalesState["closedReason"] = null; let closedReason: SalesState["closedReason"] = null;
+13 -2
View File
@@ -73,8 +73,19 @@ describe("Verkaufsfreigabe", () => {
expect(evaluateSales(earlyBird, released, "live").checkoutOpen).toBe(true); expect(evaluateSales(earlyBird, released, "live").checkoutOpen).toBe(true);
}); });
test("Livemodus vor dem 01.11.2026: Vorschau ohne Kaufmoeglichkeit, Override wirkungslos", () => { test("Livemodus vor dem 01.11.2026 mit allen Freigaben: offen zum Early-Bird-Preis", () => {
const state = evaluateSales(new Date("2026-10-01T12:00:00Z"), { ...released, testPhaseOverride: "EARLY_BIRD" }, "live"); const state = evaluateSales(new Date("2026-10-01T12:00:00Z"), released, "live");
expect(state.checkoutOpen).toBe(true);
expect(state.effectivePhase).toBe("EARLY_BIRD");
expect(state.phaseSimulated).toBe(false);
});
test("Livemodus vor dem 01.11.2026 mit fehlender Freigabe: Vorschau, Override wirkungslos", () => {
const state = evaluateSales(
new Date("2026-10-01T12:00:00Z"),
{ ...released, travelLawChecked: false, testPhaseOverride: "REGULAR" },
"live",
);
expect(state.checkoutOpen).toBe(false); expect(state.checkoutOpen).toBe(false);
expect(state.closedReason).toBe("PREVIEW"); expect(state.closedReason).toBe("PREVIEW");
}); });