Versandkosten-System (Pflichtenheft Punkt 9) + kritischen Warenkorb/Checkout-Bug behoben
Neu: - Produkte können eigene Versandkosten je Land (DE/AT/CH/LU) bekommen, gelten nur bei Einzelkauf (genau 1 Stück von 1 Produkt) - Versandkosten-Staffel nach Warenwert je Land, von VanVan im Adminbereich bearbeitbar (neuer Bereich "Versandkosten-Staffel"), greift bei mehreren Produkten/Stück - Versandkostenfrei ab 75 € gilt immer, unabhängig von Einzelkauf/Staffel - Checkout berechnet und zeigt jetzt die echten Versandkosten live beim Länderwechsel an Kritischer Bugfix (unabhängig vom neuen Feature entdeckt): - Warenkorb- und Checkout-Skripte haben "import" innerhalb von define:vars-Skripten benutzt, was Astro als IIFE rendert (kein ES-Modul) — das hat in der echten Live-Version die ganze Zeit zu "Cannot use import statement outside a module" geführt, wodurch Warenkorb und Checkout praktisch nie funktioniert haben. Behoben durch Trennung: define:vars-Skript setzt nur Werte auf window, separates <script type="module"> mit den echten Imports liest sie aus. Mit echtem End-to-End-Test verifiziert (Artikel in Warenkorb legen, Land wechseln, Summe prüfen) statt nur Screenshot.
This commit is contained in:
@@ -29,6 +29,11 @@ export interface Product {
|
||||
lieferzeit?: string;
|
||||
badges: Badge[];
|
||||
bilder?: string[]; // Pfade zu Produktfotos, von VanVan im Admin-Bereich hochgeladen
|
||||
// Eigene Versandkosten je Land — gelten NUR, wenn genau 1 Stück dieses einen Produkts
|
||||
// gekauft wird (Einzelkauf). Bei mehreren Produkten/Stückzahlen greift stattdessen die
|
||||
// Versandkosten-Staffel (siehe src/data/versand.ts). Optional, damit Bestandsprodukte ohne
|
||||
// diese Angabe nicht kaputtgehen — dann greift automatisch die Staffel als Rückfalllösung.
|
||||
versand?: { de?: number; at?: number; ch?: number; lu?: number };
|
||||
}
|
||||
|
||||
const modules = import.meta.glob("/src/content/products/*.json", { eager: true }) as Record<
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Versandkosten-Logik. Regeln (mit dem Nutzer am 02.08.2026 abgestimmt):
|
||||
// 1. Warenkorb-Gesamtwert >= 75 € → Versand immer kostenlos, egal wie viele Produkte/Stück.
|
||||
// 2. Genau 1 Stück von genau 1 Produkt im Warenkorb → der am Produkt selbst hinterlegte
|
||||
// Versandpreis für das Zielland gilt (falls hinterlegt, sonst Fallback auf die Staffel).
|
||||
// 3. Alles andere (mehrere Produkte und/oder mehrere Stück) → Versandkosten-Staffel nach
|
||||
// Gesamt-Warenwert für das Zielland (src/content/versandstaffel.json), von VanVan im
|
||||
// Adminbereich bearbeitbar.
|
||||
|
||||
import type { Product } from "./products";
|
||||
|
||||
export type CountryCode = "de" | "at" | "ch" | "lu";
|
||||
|
||||
export interface VersandStufe {
|
||||
abWarenwert: number;
|
||||
kosten: number;
|
||||
}
|
||||
|
||||
export interface Versandstaffel {
|
||||
de: VersandStufe[];
|
||||
at: VersandStufe[];
|
||||
ch: VersandStufe[];
|
||||
lu: VersandStufe[];
|
||||
}
|
||||
|
||||
// @ts-ignore -- JSON-Import, zur Build-Zeit von Astro/Vite aufgelöst
|
||||
import versandstaffelRaw from "../content/versandstaffel.json";
|
||||
export const versandstaffel = versandstaffelRaw as Versandstaffel;
|
||||
|
||||
export const FREE_SHIPPING_FROM = 75;
|
||||
|
||||
function tierLookup(land: CountryCode, warenwert: number): number {
|
||||
const stufen = versandstaffel[land] ?? [];
|
||||
const sortiert = [...stufen].sort((a, b) => a.abWarenwert - b.abWarenwert);
|
||||
let kosten = sortiert[0]?.kosten ?? 0;
|
||||
for (const s of sortiert) {
|
||||
if (warenwert >= s.abWarenwert) kosten = s.kosten;
|
||||
}
|
||||
return kosten;
|
||||
}
|
||||
|
||||
export interface MinimalCartItem {
|
||||
slug: string;
|
||||
preis: number;
|
||||
menge: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Berechnet die Versandkosten für einen Warenkorb in ein bestimmtes Land.
|
||||
* `alleProdukte` wird gebraucht, um bei Einzelkäufen den produktspezifischen Versandpreis
|
||||
* nachzuschlagen (die Cart-Items selbst kennen nur slug/preis/menge, keine Versanddaten).
|
||||
*/
|
||||
export function berechneVersandkosten(
|
||||
land: CountryCode,
|
||||
items: MinimalCartItem[],
|
||||
alleProdukte: Product[]
|
||||
): number {
|
||||
if (items.length === 0) return 0;
|
||||
|
||||
const warenwert = items.reduce((sum, i) => sum + i.preis * i.menge, 0);
|
||||
if (warenwert >= FREE_SHIPPING_FROM) return 0;
|
||||
|
||||
const gesamtmenge = items.reduce((sum, i) => sum + i.menge, 0);
|
||||
const istEinzelkauf = items.length === 1 && gesamtmenge === 1;
|
||||
|
||||
if (istEinzelkauf) {
|
||||
const produkt = alleProdukte.find((p) => p.slug === items[0].slug);
|
||||
const eigenerPreis = produkt?.versand?.[land];
|
||||
if (typeof eigenerPreis === "number") return eigenerPreis;
|
||||
// Kein eigener Versandpreis hinterlegt -> Staffel als Rückfalllösung
|
||||
}
|
||||
|
||||
return tierLookup(land, warenwert);
|
||||
}
|
||||
Reference in New Issue
Block a user