From 27bc15d65a69bcd2c68dcd58b94e5511e505e5d2 Mon Sep 17 00:00:00 2001 From: Carangeot Date: Mon, 13 Apr 2026 16:18:11 +0200 Subject: [PATCH 1/2] feat: [SPE-95] Remove prefix for invoiceFields --- src/Form/OnePageCheckoutForm.php | 22 ++++++------- .../CheckoutOnePageStepRenderTest.php | 2 +- .../php/Unit/Form/OnePageCheckoutFormTest.php | 2 +- views/js/opc-address-modal.js | 6 ++-- views/js/opc-address.js | 18 +++++------ views/js/opc-payment-list.js | 3 +- views/js/opc-submit.js | 32 ++++++++++++++++++- 7 files changed, 55 insertions(+), 30 deletions(-) diff --git a/src/Form/OnePageCheckoutForm.php b/src/Form/OnePageCheckoutForm.php index bf7c290..265d714 100644 --- a/src/Form/OnePageCheckoutForm.php +++ b/src/Form/OnePageCheckoutForm.php @@ -320,8 +320,7 @@ public function submit() } else { $invoiceAddress = $this->buildAddressFromGroup( $fieldsByGroup['invoiceFields'], - null, - 'invoice_' + null ); $invoiceAddress->id_customer = $customer->id; $invoiceAddress->alias = $invoiceAddress->alias ?: $this->translator->trans( @@ -619,7 +618,7 @@ public function getInvoiceAddress() { $fieldsByGroup = $this->mapFieldsByGroup(); - return $this->buildAddressFromGroup($fieldsByGroup['invoiceFields'], null, 'invoice_'); + return $this->buildAddressFromGroup($fieldsByGroup['invoiceFields'], null); } public function getTemplateVariables() @@ -716,7 +715,10 @@ private function mapFieldsByGroup(): array } if ($this->isInvoiceField($key)) { - $fieldsByGroup['invoiceFields'][$key] = $field; + $strippedKey = substr($key, strlen('invoice_')); + $clonedField = clone $field; + $clonedField->setName($strippedKey); + $fieldsByGroup['invoiceFields'][$strippedKey] = $clonedField; continue; } @@ -838,22 +840,18 @@ private function buildCustomerFromFields(array $fields): \Customer * @param array $fields * @param int|null $idAddress */ - private function buildAddressFromGroup(array $fields, $idAddress, string $prefix = ''): \Address + private function buildAddressFromGroup(array $fields, $idAddress): \Address { $address = new \Address($idAddress ? (int) $idAddress : null, $this->language->id); foreach ($fields as $formField) { $fieldName = $formField->getName(); - $baseName = $prefix && strpos($fieldName, $prefix) === 0 - ? substr($fieldName, strlen($prefix)) - : $fieldName; - - if (property_exists($address, $baseName)) { - $address->{$baseName} = $formField->getValue(); + if (property_exists($address, $fieldName)) { + $address->{$fieldName} = $formField->getValue(); } } - if (!isset($fields[$prefix . 'id_state'])) { + if (!isset($fields['id_state'])) { $address->id_state = 0; } diff --git a/tests/php/Unit/Checkout/CheckoutOnePageStepRenderTest.php b/tests/php/Unit/Checkout/CheckoutOnePageStepRenderTest.php index e0c181b..c486093 100644 --- a/tests/php/Unit/Checkout/CheckoutOnePageStepRenderTest.php +++ b/tests/php/Unit/Checkout/CheckoutOnePageStepRenderTest.php @@ -74,7 +74,7 @@ public function getTemplateVarConfiguration(): array 'additionalCustomerFields' => [], 'useSameAddressField' => ['value' => true], 'deliveryFields' => ['firstname' => ['name' => 'firstname']], - 'invoiceFields' => ['invoice_firstname' => ['name' => 'invoice_firstname']], + 'invoiceFields' => ['firstname' => ['name' => 'firstname']], 'invoiceMetaFields' => [], 'errors' => ['' => []], 'token' => 'token', diff --git a/tests/php/Unit/Form/OnePageCheckoutFormTest.php b/tests/php/Unit/Form/OnePageCheckoutFormTest.php index 04ba4ae..61761b5 100644 --- a/tests/php/Unit/Form/OnePageCheckoutFormTest.php +++ b/tests/php/Unit/Form/OnePageCheckoutFormTest.php @@ -430,7 +430,7 @@ public function testItSeparatesTemplateVariablesByBusinessOrigin(): void self::assertSame('opcinvariantprobe_customer_text', $templateVariables['additionalCustomerFields']['customer_probe_text']['name']); self::assertSame('use_same_address', $templateVariables['formFields']['use_same_address']['name']); self::assertSame('firstname', $templateVariables['deliveryFields']['firstname']['name']); - self::assertSame('invoice_address1', $templateVariables['invoiceFields']['invoice_address1']['name']); + self::assertSame('address1', $templateVariables['invoiceFields']['address1']['name']); self::assertSame('id_address_invoice', $templateVariables['invoiceMetaFields']['id_address_invoice']['name']); } diff --git a/views/js/opc-address-modal.js b/views/js/opc-address-modal.js index d10eea0..8b0e6a5 100644 --- a/views/js/opc-address-modal.js +++ b/views/js/opc-address-modal.js @@ -45,9 +45,7 @@ const BILLING_FIELDS_SELECTOR = OPC_SELECTORS.opc.billingFields; const DISABLED_BY_SAME_ADDRESS_ATTRIBUTE = 'data-opc-disabled-by-same-address'; const SERVER_MANAGED_FIELDS = new Set([ 'id_country', - 'invoice_id_country', 'id_state', - 'invoice_id_state', 'use_same_address', ]); const NON_PRESERVABLE_FIELD_TYPES = new Set(['hidden', 'file', 'submit', 'button', 'image', 'reset']); @@ -759,7 +757,7 @@ function refreshAddressesSection(options = {}) { payload.id_address_delivery = getAddressSectionFieldValue($addressForm, DELIVERY_SECTION_SELECTOR, DELIVERY_FIELDS_SELECTOR, 'id_address_delivery'); payload.id_address_invoice = getAddressSectionFieldValue($addressForm, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'id_address_invoice'); payload.id_country = getAddressSectionFieldValue($addressForm, DELIVERY_SECTION_SELECTOR, DELIVERY_FIELDS_SELECTOR, 'id_country'); - payload.invoice_id_country = getAddressSectionFieldValue($addressForm, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'invoice_id_country'); + payload.invoice_id_country = getAddressSectionFieldValue($addressForm, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'id_country'); } const useSameAddress = payload.use_same_address !== '0'; @@ -776,7 +774,7 @@ function refreshAddressesSection(options = {}) { syncBillingSectionConstraints($addressForm, useSameAddress); if (!resetInlineAddressState) { setAddressSectionFieldValue($addressForm, DELIVERY_SECTION_SELECTOR, DELIVERY_FIELDS_SELECTOR, 'id_country', payload.id_country); - setAddressSectionFieldValue($addressForm, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'invoice_id_country', payload.invoice_id_country); + setAddressSectionFieldValue($addressForm, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'id_country', payload.invoice_id_country); } syncAllSavedAddressItemStyles(); diff --git a/views/js/opc-address.js b/views/js/opc-address.js index 5209da9..cd3b9a9 100644 --- a/views/js/opc-address.js +++ b/views/js/opc-address.js @@ -42,9 +42,7 @@ const DISABLED_BY_SAME_ADDRESS_ATTRIBUTE = 'data-opc-disabled-by-same-address'; const SERVER_MANAGED_FIELDS = new Set([ 'id_country', - 'invoice_id_country', 'id_state', - 'invoice_id_state', 'use_same_address', ]); @@ -303,7 +301,7 @@ function seedBillingFromDelivery(addressContainer) { addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR - ).find('[name="invoice_id_country"]').first(); + ).find('[name="id_country"]').first(); const previousBillingCountryValue = billingCountryField.length ? String(billingCountryField.val() || '') : ''; @@ -312,7 +310,7 @@ function seedBillingFromDelivery(addressContainer) { addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, - 'invoice_id_country', + 'id_country', deliveryCountryValue ); @@ -325,7 +323,7 @@ function seedBillingFromDelivery(addressContainer) { addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, - 'invoice_id_state', + 'id_state', deliveryStateValue ); } @@ -383,13 +381,13 @@ function refreshOpcAddressFormForCountryChange(target, selectors) { } // Send both country values so backend rebuilds delivery and billing sections consistently. - const targetName = String(target.attr('name') || ''); - const deliveryCountryValue = targetName === 'id_country' + const isBillingTarget = target.closest(BILLING_SECTION_SELECTOR).length > 0; + const deliveryCountryValue = !isBillingTarget ? String(target.val() || '') : getAddressSectionFieldValue(addressContainer, DELIVERY_SECTION_SELECTOR, DELIVERY_FIELDS_SELECTOR, 'id_country'); - const invoiceCountryValue = targetName === 'invoice_id_country' + const invoiceCountryValue = isBillingTarget ? String(target.val() || '') - : getAddressSectionFieldValue(addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'invoice_id_country'); + : getAddressSectionFieldValue(addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'id_country'); const requestData = { id_address_delivery: getAddressSectionFieldValue(addressContainer, DELIVERY_SECTION_SELECTOR, DELIVERY_FIELDS_SELECTOR, 'id_address_delivery'), id_address_invoice: getAddressSectionFieldValue(addressContainer, BILLING_SECTION_SELECTOR, BILLING_FIELDS_SELECTOR, 'id_address_invoice'), @@ -439,7 +437,7 @@ function refreshOpcAddressFormForCountryChange(target, selectors) { } function handleOpcCountryChange(selectors) { - $('body').on('change', `${OPC_SELECTORS.opc.deliveryFields} select[name="id_country"], ${OPC_SELECTORS.opc.billingFields} select[name="invoice_id_country"]`, (event) => { + $('body').on('change', `${OPC_SELECTORS.opc.deliveryFields} select[name="id_country"], ${OPC_SELECTORS.opc.billingFields} select[name="id_country"]`, (event) => { refreshOpcAddressFormForCountryChange($(event.target), selectors); }); } diff --git a/views/js/opc-payment-list.js b/views/js/opc-payment-list.js index d438b13..0eac90b 100644 --- a/views/js/opc-payment-list.js +++ b/views/js/opc-payment-list.js @@ -67,7 +67,8 @@ function buildPaymentMethodsUrl(baseUrl) { const idCountry = form.querySelector('[name="id_country"]')?.value || form.querySelector('[name="delivery_id_country"]')?.value || ''; - const invoiceIdCountry = form.querySelector('[name="invoice_id_country"]')?.value || ''; + const billingSection = form.querySelector(OPC_SELECTORS.opc.billingFields); + const invoiceIdCountry = (billingSection ? billingSection.querySelector('[name="id_country"]') : null)?.value || ''; const deliveryAddressId = getSelectedSavedAddressId(OPC_SELECTORS.opc.deliveryList, 'id_address_delivery') || form.querySelector('[name="id_address_delivery"]')?.value || ''; diff --git a/views/js/opc-submit.js b/views/js/opc-submit.js index 172c0e5..e7932df 100644 --- a/views/js/opc-submit.js +++ b/views/js/opc-submit.js @@ -338,7 +338,37 @@ function submitPaymentModuleForm(paymentRadio) { } function buildSubmitPayload(form, paymentRadio) { - const payload = new FormData(form); + const payload = new FormData(); + const billingFieldsContainer = form.querySelector(BILLING_FIELDS_SELECTOR); + const billingElements = billingFieldsContainer + ? new Set(Array.from(billingFieldsContainer.querySelectorAll('input, select, textarea'))) + : new Set(); + const BILLING_NO_PREFIX = new Set(['id_address_invoice']); + + Array.from(form.querySelectorAll('input, select, textarea')).forEach((el) => { + if (!(el instanceof HTMLInputElement) && !(el instanceof HTMLSelectElement) && !(el instanceof HTMLTextAreaElement)) { + return; + } + + if (!el.name) { + return; + } + + const isBillingField = billingElements.has(el) && !BILLING_NO_PREFIX.has(el.name); + const key = isBillingField ? ('invoice_' + el.name) : el.name; + + if (el instanceof HTMLInputElement && el.type === 'checkbox') { + if (el.checked) { + payload.append(key, el.value); + } + } else if (el instanceof HTMLInputElement && el.type === 'radio') { + if (el.checked) { + payload.set(key, el.value); + } + } else { + payload.append(key, String(el.value || '')); + } + }); appendConditionsToApproveToFormData(payload); From 956ea505e6184a03bedef5e307002563f45fe5e8 Mon Sep 17 00:00:00 2001 From: Carangeot Date: Tue, 14 Apr 2026 15:04:37 +0200 Subject: [PATCH 2/2] feat: [SPE-95] Remove prefix for invoiceFields --- controllers/front/addresseslist.php | 4 ++-- views/js/opc-submit.js | 32 +---------------------------- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/controllers/front/addresseslist.php b/controllers/front/addresseslist.php index 18abc5e..4903183 100644 --- a/controllers/front/addresseslist.php +++ b/controllers/front/addresseslist.php @@ -37,7 +37,7 @@ protected function handleOpcRequest(): array 'checkout/_partials/one-page-checkout/address-list', [ 'customer' => $response['customer'] ?? [], - 'prefix' => '', + 'address_type' => 'delivery', 'selected_address' => (int) ($response['selected_delivery_address'] ?? 0), ] ), @@ -45,7 +45,7 @@ protected function handleOpcRequest(): array 'checkout/_partials/one-page-checkout/address-list', [ 'customer' => $response['customer'] ?? [], - 'prefix' => 'invoice_', + 'address_type' => 'invoice', 'selected_address' => (int) ($response['selected_invoice_address'] ?? 0), ] ), diff --git a/views/js/opc-submit.js b/views/js/opc-submit.js index e7932df..172c0e5 100644 --- a/views/js/opc-submit.js +++ b/views/js/opc-submit.js @@ -338,37 +338,7 @@ function submitPaymentModuleForm(paymentRadio) { } function buildSubmitPayload(form, paymentRadio) { - const payload = new FormData(); - const billingFieldsContainer = form.querySelector(BILLING_FIELDS_SELECTOR); - const billingElements = billingFieldsContainer - ? new Set(Array.from(billingFieldsContainer.querySelectorAll('input, select, textarea'))) - : new Set(); - const BILLING_NO_PREFIX = new Set(['id_address_invoice']); - - Array.from(form.querySelectorAll('input, select, textarea')).forEach((el) => { - if (!(el instanceof HTMLInputElement) && !(el instanceof HTMLSelectElement) && !(el instanceof HTMLTextAreaElement)) { - return; - } - - if (!el.name) { - return; - } - - const isBillingField = billingElements.has(el) && !BILLING_NO_PREFIX.has(el.name); - const key = isBillingField ? ('invoice_' + el.name) : el.name; - - if (el instanceof HTMLInputElement && el.type === 'checkbox') { - if (el.checked) { - payload.append(key, el.value); - } - } else if (el instanceof HTMLInputElement && el.type === 'radio') { - if (el.checked) { - payload.set(key, el.value); - } - } else { - payload.append(key, String(el.value || '')); - } - }); + const payload = new FormData(form); appendConditionsToApproveToFormData(payload);