first commit
Docker-Images bauen und veroeffentlichen / build-and-push (push) Failing after 1m32s

This commit is contained in:
Nick Szaunig committed 2026-09-27 06:06:56 +02:00
commit 59bb5a38a3
132 files changed
+19435

No files matched your search

+143
View File
@@ -0,0 +1,143 @@
import type {
CheckoutSessionInfo,
CreateCheckoutParams,
OffSessionResult,
PaymentGateway,
PaymentIntentInfo,
} from "@/lib/payment-gateway";
import type { StripeMode } from "@/lib/sales-gate";
type StoredSession = CheckoutSessionInfo & { params: CreateCheckoutParams };
/**
* Stripe-Attrappe im Speicher. Bildet die fuer die Geschaeftslogik
* relevanten Eigenschaften nach: Idempotenzschluessel, Session-Zustaende,
* PaymentIntents und das Ergebnis von Off-Session-Einzuegen.
*/
export class FakeGateway implements PaymentGateway {
private seq = 0;
private readonly byKey = new Map<string, unknown>();
readonly sessions = new Map<string, StoredSession>();
readonly paymentIntents = new Map<string, PaymentIntentInfo>();
readonly offSessionCharges: { key: string; amountCents: number; installmentId: string }[] = [];
readonly detached: string[] = [];
readonly refunds: { id: string; paymentIntentId: string; amountCents: number }[] = [];
/** Ergebnisse fuer die naechsten Off-Session-Einzuege (Standard: Erfolg). */
offSessionOutcomes: OffSessionResult["outcome"][] = [];
failNextCheckout = false;
constructor(readonly mode: StripeMode = "test") {}
private id(prefix: string): string {
this.seq++;
return `${prefix}_test_${this.seq}`;
}
private once<T>(key: string, create: () => T): T {
if (!this.byKey.has(key)) this.byKey.set(key, create());
return this.byKey.get(key) as T;
}
async createCustomer(_params: { email: string; name: string }, key: string) {
return this.once(`cus:${key}`, () => ({ id: this.id("cus") }));
}
async createCheckoutSession(params: CreateCheckoutParams, key: string) {
if (this.failNextCheckout) {
this.failNextCheckout = false;
throw new Error("Stripe nicht erreichbar (simuliert)");
}
return this.once(`cs:${key}`, () => {
const id = this.id("cs");
const url = `https://checkout.stripe.test/${id}`;
this.sessions.set(id, {
id,
status: "open",
paymentStatus: "unpaid",
paymentIntentId: null,
customerId: params.customerId,
url,
metadata: params.metadata,
params,
});
return { id, url };
});
}
async retrieveCheckoutSession(id: string): Promise<CheckoutSessionInfo> {
const s = this.sessions.get(id);
if (!s) throw new Error(`Unbekannte Session ${id}`);
return { ...s };
}
async expireCheckoutSession(id: string): Promise<void> {
const s = this.sessions.get(id);
if (s && s.status === "open") s.status = "expired";
}
/** Simuliert die Zahlung durch die Kundin in Stripe Checkout. */
completeSession(id: string, opts: { paid?: boolean; paymentMethodId?: string; amountCents?: number } = {}): CheckoutSessionInfo {
const s = this.sessions.get(id);
if (!s) throw new Error(`Unbekannte Session ${id}`);
const piId = this.id("pi");
const paid = opts.paid ?? true;
this.paymentIntents.set(piId, {
id: piId,
status: paid ? "succeeded" : "processing",
amountReceived: paid ? (opts.amountCents ?? s.params.amountCents) : 0,
paymentMethodId: opts.paymentMethodId ?? this.id("pm"),
chargeId: paid ? this.id("ch") : null,
metadata: s.metadata,
});
s.status = "complete";
s.paymentStatus = paid ? "paid" : "unpaid";
s.paymentIntentId = piId;
return { ...s };
}
async retrievePaymentIntent(id: string): Promise<PaymentIntentInfo> {
const pi = this.paymentIntents.get(id);
if (!pi) throw new Error(`Unbekannter PaymentIntent ${id}`);
return { ...pi };
}
async chargeOffSession(
params: { customerId: string; paymentMethodId: string; amountCents: number; metadata: Record<string, string> },
key: string,
): Promise<OffSessionResult> {
return this.once(`pi:${key}`, () => {
const outcome = this.offSessionOutcomes.shift() ?? "succeeded";
const piId = this.id("pi");
const chargeId = outcome === "succeeded" ? this.id("ch") : null;
this.paymentIntents.set(piId, {
id: piId,
status: outcome === "succeeded" ? "succeeded" : outcome === "processing" ? "processing" : outcome === "requires_action" ? "requires_action" : "requires_payment_method",
amountReceived: outcome === "succeeded" ? params.amountCents : 0,
paymentMethodId: params.paymentMethodId,
chargeId,
metadata: params.metadata,
});
if (outcome === "succeeded") {
this.offSessionCharges.push({ key, amountCents: params.amountCents, installmentId: params.metadata.installmentId! });
}
return {
outcome,
paymentIntentId: piId,
chargeId,
failureCode: outcome === "failed" ? "card_declined" : outcome === "requires_action" ? "authentication_required" : null,
};
});
}
async detachPaymentMethod(id: string): Promise<void> {
this.detached.push(id);
}
async createRefund(params: { paymentIntentId: string; amountCents: number }, key: string) {
return this.once(`re:${key}`, () => {
const refund = { id: this.id("re"), paymentIntentId: params.paymentIntentId, amountCents: params.amountCents };
this.refunds.push(refund);
return { id: refund.id, status: "succeeded", amount: params.amountCents };
});
}
}