/** * Forms Component - Handles form data and validation */ const FormsComponent = { /** * Initialize forms state * @returns {Object} */ getInitialState() { return { form: { initials: '', lastname: '', postcode: '', houseno: '', suffix: '', street: '', city: '', email: '', phone: '' }, meta: { mediacode: '' }, addressError: '' }; }, /** * Get forms methods for Alpine.js component * @returns {Object} */ getMethods() { return { /** * Format initials with dots (e.g., "JK" -> "J.K.") */ formatInitials() { let v = this.form.initials.replace(/[^a-z]/gi, '').toUpperCase(); this.form.initials = v.split('').join('.') + (v ? '.' : ''); }, /** * Capitalize first letter of lastname */ formatLastname() { this.form.lastname = this.form.lastname.charAt(0).toUpperCase() + this.form.lastname.slice(1); }, /** * Lookup address by postcode and house number */ async lookupAddress() { this.addressError = ''; if (this.form.postcode.length >= 6 && this.form.houseno) { try { const data = await ApiService.lookupPostcode(this.form.postcode, this.form.houseno); if (data.street) { this.form.street = data.street; this.form.city = data.city; } else if (data.error) { this.addressError = data.error; } else { this.addressError = 'Adres niet gevonden'; } } catch (e) { this.addressError = 'Fout bij ophalen adres'; } } }, /** * Reset form for new order */ resetForm() { this.form = { initials: '', lastname: '', postcode: '', houseno: '', suffix: '', street: '', city: '', email: '', phone: '' }; this.addressError = ''; }, /** * Build order payload from form data * Includes prices from sales screen to ensure discounts and free items are applied correctly * @returns {Object} */ buildOrderPayload() { const address = (this.form.street + ' ' + this.form.houseno + ' ' + (this.form.suffix || '')).trim(); return { mediacode_internal: this.meta.mediacode, shipping_total: this.shipping, billing: { first_name: this.form.initials, last_name: this.form.lastname, address_1: address, city: this.form.city, postcode: this.form.postcode, country: 'NL', email: this.form.email, phone: this.form.phone }, shipping: { first_name: this.form.initials, last_name: this.form.lastname, address_1: address, city: this.form.city, postcode: this.form.postcode, country: 'NL', email: this.form.email, phone: this.form.phone }, line_items: this.cart.map(i => { // Calculate price excluding VAT (21%) const priceExclVat = (parseFloat(i.price) / 1.21).toFixed(4); // For free items, use originalPrice if available, otherwise use price const originalPriceExclVat = i.originalPrice ? (parseFloat(i.originalPrice) / 1.21).toFixed(4) : priceExclVat; // Build line item object const lineItem = { product_id: i.id, variation_id: i.variation_id || 0, quantity: 1, // Set subtotal and total to override WooCommerce's price calculation // subtotal = price before line-level discounts (shows original value) // total = price after line-level discounts (actual charged amount) subtotal: i.isFree ? originalPriceExclVat : priceExclVat, total: i.isFree ? '0.0000' : priceExclVat }; // Add metadata for tracking discounts and free items if (i.isFree) { lineItem.meta_data = [ { key: '_is_free_item', value: 'yes' }, { key: '_bogo_rule_id', value: String(i.ruleId || '') }, { key: '_original_price_incl_vat', value: String(i.originalPrice || i.price) } ]; } else if (i.isDiscounted) { lineItem.meta_data = [ { key: '_is_discounted_item', value: 'yes' }, { key: '_original_price_incl_vat', value: String(i.originalPrice || '') }, { key: '_bogo_rule_id', value: String(i.ruleId || '') } ]; } return lineItem; }) }; }, /** * Validate form before submission * @returns {boolean} */ isFormValid() { return this.form.email && this.meta.mediacode && this.cart.length > 0; } }; } };