Vollstaendige Next.js/Prisma-E-Commerce-Anwendung fuer eine Imkerei: Shop, Warenkorb, Stripe-Checkout, Kundenkonto mit 2FA, Admin-Bereich (Produkte, Ernten, Chargen, Bestellungen, Gutscheine, admin-editierbare Website-Inhalte), i18n (DE/EN), Rate-Limiting/CSP/Audit-Log-Haertung, PostgreSQL- und MySQL-Unterstuetzung ueber austauschbare Prisma- Treiber-Adapter, Unit-/Komponenten-/E2E-Tests.
51 lines
2.1 KiB
TypeScript
51 lines
2.1 KiB
TypeScript
export interface ShippingTierLike {
|
|
minQuantity: number;
|
|
maxQuantity: number | null;
|
|
priceCents: number;
|
|
}
|
|
|
|
// Greift nur, wenn im Admin-Bereich (noch) keine Staffeln gepflegt sind —
|
|
// verhindert einen kaputten Checkout statt einer korrekten Preisauskunft.
|
|
export const FALLBACK_SHIPPING_CENTS = 490;
|
|
|
|
/**
|
|
* Reine Zuordnungsfunktion ohne Datenbankzugriff — bewusst getrennt von
|
|
* shipping.ts, damit sowohl der serverseitige Checkout (lib/shipping.ts) als
|
|
* auch die client-seitige Warenkorb-Live-Vorschau (warenkorb-content.tsx)
|
|
* exakt dieselbe Staffel-Logik verwenden, ohne Prisma ins Client-Bundle zu
|
|
* ziehen.
|
|
*/
|
|
export function resolveShippingCostCents(tiers: ShippingTierLike[], totalQuantity: number): number {
|
|
if (totalQuantity <= 0) return 0;
|
|
if (tiers.length === 0) return FALLBACK_SHIPPING_CENTS;
|
|
|
|
const sorted = [...tiers].sort((a, b) => a.minQuantity - b.minQuantity);
|
|
const matching = sorted.find(
|
|
(tier) => totalQuantity >= tier.minQuantity && (tier.maxQuantity === null || totalQuantity <= tier.maxQuantity)
|
|
);
|
|
// Menge liegt oberhalb aller gepflegten Staffeln (z.B. nur bis 19 Stueck
|
|
// definiert) — die teuerste/oberste Staffel greift, statt die Bestellung
|
|
// mangels passendem Tarif abzulehnen.
|
|
return matching ? matching.priceCents : sorted[sorted.length - 1].priceCents;
|
|
}
|
|
|
|
/**
|
|
* Naechste (teurere) Staffel oberhalb der aktuellen Menge — fuer eine ehrliche
|
|
* Transparenz-Anzeige im Warenkorb ("noch X Stueck bis zur naechsten Stufe").
|
|
* Anders als ein "kostenloser Versand ab X"-Hinweis wird hier bewusst NICHT
|
|
* suggeriert, dass mehr kaufen guenstiger wird — die Staffeln steigen mit der
|
|
* Menge, siehe FALLBACK_SHIPPING_CENTS-Kommentar oben.
|
|
*/
|
|
export function getNextShippingTier(
|
|
tiers: ShippingTierLike[],
|
|
totalQuantity: number
|
|
): { unitsUntilNext: number; priceCents: number } | null {
|
|
if (tiers.length === 0 || totalQuantity <= 0) return null;
|
|
|
|
const sorted = [...tiers].sort((a, b) => a.minQuantity - b.minQuantity);
|
|
const next = sorted.find((tier) => tier.minQuantity > totalQuantity);
|
|
if (!next) return null;
|
|
|
|
return { unitsUntilNext: next.minQuantity - totalQuantity, priceCents: next.priceCents };
|
|
}
|