fix: Befunde aus Sicherheits- und Korrektheitsreview der Bienenpatenschaft
Docker Image bauen und veroeffentlichen / typecheck (push) Successful in 2m57s
Docker Image bauen und veroeffentlichen / lint (push) Successful in 3m7s
Docker Image bauen und veroeffentlichen / build-and-push (push) Canceled after 0s
Docker Image bauen und veroeffentlichen / test (push) Canceled after 1m22s
Docker Image bauen und veroeffentlichen / typecheck (push) Successful in 2m57s
Docker Image bauen und veroeffentlichen / lint (push) Successful in 3m7s
Docker Image bauen und veroeffentlichen / build-and-push (push) Canceled after 0s
Docker Image bauen und veroeffentlichen / test (push) Canceled after 1m22s
- Oeffentliche Kuendigung: exakte Identifikation, Limits je Vertrag und Adresse, Bestaetigung nur an die Kontoadresse mit Ruecknahme-Link (HMAC) - Vorschau: Body-Grenze beim Lesen, Parallelitaets- und Minutenlimit, Cache - Rabatte gelten nicht fuer Patenschaftspositionen - Abo aktiv erst nach bestaetigter Zahlung, offene Abschluesse zaehlen zum Kontingent und werden nach 24 h aufgeraeumt, Sitzung 58 Minuten - Konto-Loeschung nur ohne laufendes Abo, Urkunden-Dateien werden entfernt - Abo-Lieferungen mit Zahlungszeile (DHL-Marke moeglich) - Shop zeigt freien Bestand nach Abo-Reservierung - Storno/volle Erstattung widerruft die Patenschaft (Status WIDERRUFEN) - Umsatzsteuer der Patenschaft per VAT_RATE_PERCENT_PATENSCHAFT (19 %) - Digitale Bestellungen archivieren sich, Kalendertage in Europe/Berlin, Monatsenden begrenzt, Datenauskunft um Patenschaften ergaenzt Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
f227aeb8f9
commit
515fca1c16
97 files changed
+2979
-254
No files matched your search
@@ -7,6 +7,7 @@ import { sendMail } from "@/lib/mail";
|
||||
import { cancellationInvoiceEmail } from "@/lib/email-templates";
|
||||
import { sendInvoiceCopy } from "@/lib/invoice-mail";
|
||||
import { isLocale, defaultLocale } from "@/i18n/config";
|
||||
import { revokeOrderSponsorships } from "@/lib/sponsorship/revoke";
|
||||
|
||||
/**
|
||||
* Stornorechnung: der Gegenbeleg, wenn eine Bestellung mit Rechnung
|
||||
@@ -54,7 +55,12 @@ export async function issueCancellationInvoice(orderId: string, reason: Cancella
|
||||
select: { id: true, totalCents: true, cancellation: { select: { number: true } } },
|
||||
});
|
||||
if (!invoice) return null;
|
||||
if (invoice.cancellation) return { number: invoice.cancellation.number, created: false };
|
||||
// Auch beim zweiten Ausloeser: der Widerruf ist idempotent und holt nach,
|
||||
// falls er beim ersten Mal gescheitert ist.
|
||||
if (invoice.cancellation) {
|
||||
await revokeSponsorships(orderId);
|
||||
return { number: invoice.cancellation.number, created: false };
|
||||
}
|
||||
|
||||
let number: string;
|
||||
try {
|
||||
@@ -81,13 +87,29 @@ export async function issueCancellationInvoice(orderId: string, reason: Cancella
|
||||
if (!isUniqueConstraintError(error)) throw error;
|
||||
const existing = await prisma.cancellationInvoice.findUnique({ where: { invoiceId: invoice.id }, select: { number: true } });
|
||||
if (!existing) throw error;
|
||||
await revokeSponsorships(orderId);
|
||||
return { number: existing.number, created: false };
|
||||
}
|
||||
|
||||
await revokeSponsorships(orderId);
|
||||
await deliverCancellationInvoice(number);
|
||||
return { number, created: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Storniert oder voll erstattet = Patenschaft widerrufen (lib/sponsorship/
|
||||
* revoke.ts). Wirft nicht: die Stornorechnung steht bereits fest; ein
|
||||
* Fehlschlag wird laut geloggt und beim naechsten Ausloeser nachgeholt.
|
||||
*/
|
||||
async function revokeSponsorships(orderId: string): Promise<void> {
|
||||
try {
|
||||
const revoked = await revokeOrderSponsorships(orderId);
|
||||
if (revoked.length > 0) console.info(`[cancellation] ${revoked.length} Patenschaft(en) der Bestellung ${orderId} widerrufen.`);
|
||||
} catch (error: unknown) {
|
||||
console.error(`[cancellation] Patenschaften der Bestellung ${orderId} konnten NICHT widerrufen werden — bitte im Admin pruefen:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCancellation(number: string) {
|
||||
return prisma.cancellationInvoice.findUnique({
|
||||
where: { number },
|
||||
|
||||
Reference in new issue
Block a user