/** * 🌐 JS 13: ES MODULE & ARCHITEKTUR (CLEAN CODE & SEPARATION OF CONCERNS) 🌐 * ========================================================================= * In diesem Modul lernst du, wie modularer Code mit klarer Trennung von * Geschäftslogik (Math), Präsentation (Formatter) und Controller (Engine) * aufgebaut wird. */ // ============================================================================ // 1. MODUL: MathModule (Reine mathematische Geschäftslogik) // ============================================================================ const MathModule = { /** * 🎯 TEILZIEL 1 (TODO 1a): addieren(a, b) * Addiert zwei Zahlen. Wirft TypeError falls a oder b keine gültige Zahl ist. * @param {number} a * @param {number} b * @returns {number} */ addieren(a, b) { // TODO: Validierung & Addition return 0; }, /** * 🎯 TEILZIEL 1 (TODO 1b): subtrahieren(a, b) * Subtrahiert b von a. Wirft TypeError falls a oder b keine gültige Zahl ist. * @param {number} a * @param {number} b * @returns {number} */ subtrahieren(a, b) { // TODO: Validierung & Subtraktion return 0; }, /** * 🎯 TEILZIEL 1 (TODO 1c): multiplizieren(a, b) * Multipliziert zwei Zahlen. Wirft TypeError falls a oder b keine gültige Zahl ist. * @param {number} a * @param {number} b * @returns {number} */ multiplizieren(a, b) { // TODO: Validierung & Multiplikation return 0; }, /** * 🎯 TEILZIEL 1 (TODO 1d): dividieren(a, b) * Dividiert a durch b. Wirft TypeError bei ungültigen Zahlen und * Error("Division durch 0 nicht erlaubt") falls b === 0 ist. * @param {number} a * @param {number} b * @returns {number} */ dividieren(a, b) { // TODO: Validierung, 0-Prüfung & Division return 0; }, /** * 🎯 TEILZIEL 1 (TODO 1e): runden(betrag, dezimalstellen = 2) * Rundet kaufmännisch auf die übergebene Anzahl von Nachkommastellen. * @param {number} betrag * @param {number} [dezimalstellen=2] * @returns {number} */ runden(betrag, dezimalstellen = 2) { // TODO: Kaufmännisches Runden return 0; } }; // ============================================================================ // 2. MODUL: FormatterModule (Präsentations- & Formatierungslogik) // ============================================================================ const FormatterModule = { /** * 🎯 TEILZIEL 2 (TODO 2a): formatiereWaehrung(betrag, waehrung = "EUR") * Formatiert eine Zahl im deutschen Währungsformat mit 2 Nachkommastellen * und Tausender-Trennzeichen: * z.B. 1250.5 -> "1.250,50 EUR", 49.99 -> "49,99 EUR", 0 -> "0,00 EUR" * Wirft TypeError falls betrag keine Zahl ist oder waehrung ungültig ist. * * @param {number} betrag * @param {string} [waehrung="EUR"] * @returns {string} */ formatiereWaehrung(betrag, waehrung = "EUR") { // TODO: Betrag runden, deutsches Format mit Komma und Tausender-Punkt erstellen return ""; }, /** * 🎯 TEILZIEL 2 (TODO 2b): formatiereDatumIso(datum) * Wandelt ein Date-Objekt oder einen Datums-String in das ISO-Format "YYYY-MM-DD" um. * Wirft TypeError falls das Datum ungültig ist. * z.B. new Date(2026, 7, 30) -> "2026-08-30" * * @param {Date | string | number} datum * @returns {string} */ formatiereDatumIso(datum) { // TODO: Date-Objekt validieren und als YYYY-MM-DD formatieren return ""; } }; // ============================================================================ // 3. HAUPT-CONTROLLER: RechnungsEngine (Orchestrator mit Dependency Injection) // ============================================================================ /** * @typedef {Object} Rechnungsposition * @property {string} bezeichnung - Name des Artikels / der Dienstleistung * @property {number} menge - Anzahl (muss > 0 sein) * @property {number} einzelpreis - Preis pro Einheit (muss >= 0 sein) * @property {number} gesamtpreis - menge * einzelpreis */ /** * @typedef {Object} Rechnung * @property {Rechnungsposition[]} positionen * @property {number} nettoSumme * @property {number} steuersatzProzent * @property {number} steuerBetrag * @property {number} bruttoSumme * @property {string} nettoFormatiert * @property {string} steuerFormatiert * @property {string} bruttoFormatiert */ class RechnungsEngine { /** * Konstruktor mit Dependency Injection: * Erlaubt das Austauschen der Module für Tests oder andere Währungen/Formate. * @param {typeof MathModule} [mathMod=MathModule] * @param {typeof FormatterModule} [formatMod=FormatterModule] */ constructor(mathMod = MathModule, formatMod = FormatterModule) { this.math = mathMod; this.formatter = formatMod; } /** * 🎯 TEILZIEL 3 (TODO 3): erstellePosition(bezeichnung, menge, einzelpreis) * Erstellt eine validierte Rechnungsposition und berechnet den gesamtpreis. * * Anforderungen: * - bezeichnung: string (nach .trim() nicht leer, sonst Error werfen) * - menge: number (> 0, sonst RangeError) * - einzelpreis: number (>= 0, sonst RangeError) * - gesamtpreis berechnen über this.math.multiplizieren(menge, einzelpreis) * - Rückgabe: { bezeichnung, menge, einzelpreis, gesamtpreis } * * @param {string} bezeichnung * @param {number} menge * @param {number} einzelpreis * @returns {Rechnungsposition} */ erstellePosition(bezeichnung, menge, einzelpreis) { // TODO: Validierung & Erstellung der Position return null; } /** * 🎯 TEILZIEL 4 (TODO 4): berechneRechnung(positionen, steuersatzProzent = 19) * Berechnet Gesamtsummen, Steuern und formatierte Ausgaben für eine Liste von Positionen. * * Anforderungen: * - positionen: Array von Rechnungspositionen (falls leer, Summen = 0) * - steuersatzProzent: number (Standard: 19) * - nettoSumme: Summe aller p.gesamtpreis (mit this.math.addieren berechnen) * - steuerBetrag: this.math.runden(this.math.multiplizieren(nettoSumme, steuersatzProzent / 100), 2) * - bruttoSumme: this.math.addieren(nettoSumme, steuerBetrag) * - Formatierte Werte über this.formatter.formatiereWaehrung() erzeugen * - Rückgabe: Das fertige Rechnung-Objekt * * @param {Rechnungsposition[]} positionen * @param {number} [steuersatzProzent=19] * @returns {Rechnung} */ berechneRechnung(positionen, steuersatzProzent = 19) { // TODO: Netto, Steuer, Brutto und formatierte Werte berechnen return null; } }