// static/shared/js/money.js /** * Money handling utilities using integer cents. * * All monetary values are stored as integers representing cents in the database. * The API returns euros (converted from cents on the backend), but these utilities * can be used if cents are passed to the frontend. * * Example: * 105.91 EUR is stored as 10591 (integer cents) * * Usage: * Money.format(10591) // Returns "105.91" * Money.format(10591, 'EUR') // Returns "105,91 EUR" * Money.toCents(105.91) // Returns 10591 * Money.toEuros(10591) // Returns 105.91 * Money.formatEuros(105.91, 'EUR') // Returns "105,91 EUR" * * See docs/architecture/money-handling.md for full documentation. */ const Money = { /** * Format cents as a currency string. * * @param {number} cents - Amount in cents * @param {string} currency - Currency code (default: '', no currency shown) * @param {string} locale - Locale for formatting (default: 'de-DE') * @returns {string} Formatted price string * * @example * Money.format(10591) // "105.91" * Money.format(10591, 'EUR') // "105,91 EUR" (German locale) * Money.format(1999) // "19.99" */ format(cents, currency = '', locale = 'de-DE') { if (cents === null || cents === undefined) { cents = 0; } const euros = cents / 100; if (currency) { return new Intl.NumberFormat(locale, { style: 'currency', currency: currency }).format(euros); } return new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(euros); }, /** * Convert euros to cents. * * @param {number|string} euros - Amount in euros * @returns {number} Amount in cents (integer) * * @example * Money.toCents(105.91) // 10591 * Money.toCents('19.99') // 1999 * Money.toCents(null) // 0 */ toCents(euros) { if (euros === null || euros === undefined || euros === '') { return 0; } return Math.round(parseFloat(euros) * 100); }, /** * Convert cents to euros. * * @param {number} cents - Amount in cents * @returns {number} Amount in euros * * @example * Money.toEuros(10591) // 105.91 * Money.toEuros(1999) // 19.99 * Money.toEuros(null) // 0 */ toEuros(cents) { if (cents === null || cents === undefined) { return 0; } return cents / 100; }, /** * Format a euro amount for display. * * Use this when the value is already in euros (e.g., from API response). * * @param {number} euros - Amount in euros * @param {string} currency - Currency code (default: 'EUR') * @param {string} locale - Locale for formatting (default: 'de-DE') * @returns {string} Formatted price string * * @example * Money.formatEuros(105.91, 'EUR') // "105,91 EUR" * Money.formatEuros(19.99) // "19.99" */ formatEuros(euros, currency = '', locale = 'de-DE') { if (euros === null || euros === undefined) { euros = 0; } if (currency) { return new Intl.NumberFormat(locale, { style: 'currency', currency: currency }).format(euros); } return new Intl.NumberFormat(locale, { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(euros); }, /** * Parse a price string to cents. * * Handles various formats: * - "19.99 EUR" * - "19,99" * - 19.99 * * @param {string|number} priceStr - Price string or number * @returns {number} Amount in cents * * @example * Money.parse("19.99 EUR") // 1999 * Money.parse("19,99") // 1999 * Money.parse(19.99) // 1999 */ parse(priceStr) { if (priceStr === null || priceStr === undefined || priceStr === '') { return 0; } if (typeof priceStr === 'number') { return Math.round(priceStr * 100); } // Remove currency symbols and spaces let cleaned = priceStr.toString().replace(/[^\d,.-]/g, ''); // Handle European decimal comma cleaned = cleaned.replace(',', '.'); try { return Math.round(parseFloat(cleaned) * 100); } catch { return 0; } }, /** * Calculate line total (unit price * quantity). * * @param {number} unitPriceCents - Price per unit in cents * @param {number} quantity - Number of units * @returns {number} Total in cents */ calculateLineTotal(unitPriceCents, quantity) { return unitPriceCents * quantity; }, /** * Calculate order total. * * @param {number} subtotalCents - Sum of line items in cents * @param {number} taxCents - Tax amount in cents (default: 0) * @param {number} shippingCents - Shipping cost in cents (default: 0) * @param {number} discountCents - Discount amount in cents (default: 0) * @returns {number} Total in cents */ calculateOrderTotal(subtotalCents, taxCents = 0, shippingCents = 0, discountCents = 0) { return subtotalCents + taxCents + shippingCents - discountCents; } }; // Make available globally window.Money = Money; // Export for modules if (typeof module !== 'undefined' && module.exports) { module.exports = Money; }