diff --git a/.idea/WooCommerce.iml b/.idea/WooCommerce.iml index 9aa75e6b..44b2cf64 100644 --- a/.idea/WooCommerce.iml +++ b/.idea/WooCommerce.iml @@ -3,11 +3,6 @@ - - - - - diff --git a/.idea/php.xml b/.idea/php.xml index 34031bf4..d7c33327 100644 --- a/.idea/php.xml +++ b/.idea/php.xml @@ -130,12 +130,16 @@ + + + + - - + + @@ -261,4 +265,4 @@ - + \ No newline at end of file diff --git a/inc/utils.php b/inc/utils.php index 984e54f3..bdd68c75 100644 --- a/inc/utils.php +++ b/inc/utils.php @@ -222,3 +222,17 @@ function mollieDeleteWPTranslationFiles() } } } + +function transformPhoneToNLFormat($phone) +{ + $startsWith06 = preg_match('/^06/', $phone); + if ($startsWith06) { + $prefix = '+316'; + $phone = substr($phone, 2); + if (!$phone) { + return null; + } + $phone = $prefix . $phone; + } + return $phone; +} diff --git a/resources/js/blocks/molliePaymentMethod.js b/resources/js/blocks/molliePaymentMethod.js index 3eeb5bc0..bbf305e3 100644 --- a/resources/js/blocks/molliePaymentMethod.js +++ b/resources/js/blocks/molliePaymentMethod.js @@ -161,36 +161,6 @@ const MollieComponent = (props) => { }, [activePaymentMethod, onCheckoutValidation, billing.billingData, item, companyNameString, inputCompany]); - useEffect(() => { - let phoneLabel = getPhoneField()?.labels?.[0] ?? null; - if (!phoneLabel || phoneLabel.length === 0) { - return - } - if (activePaymentMethod === 'mollie_wc_gateway_in3') { - phoneLabel.innerText = item.phonePlaceholder - } else { - if (phoneString !== false) { - phoneLabel.innerText = phoneString - } - } - let isPhoneEmpty = (billing.billingData.phone === '' && shippingData.shippingAddress.phone === '') && inputPhone === ''; - let isBirthdateEmpty = inputBirthdate === '' - const unsubscribeProcessing = onCheckoutValidation( - - () => { - if (activePaymentMethod === 'mollie_wc_gateway_in3' && (isPhoneEmpty || isBirthdateEmpty)) { - return { - errorMessage: item.errorMessage, - }; - } - } - ); - return () => { - unsubscribeProcessing() - }; - - }, [activePaymentMethod, onCheckoutValidation, billing.billingData, shippingData.shippingAddress, item, phoneString, inputBirthdate, inputPhone]); - onSubmitLocal = onSubmit const updateIssuer = ( changeEvent ) => { selectIssuer( changeEvent.target.value ) @@ -215,12 +185,14 @@ const MollieComponent = (props) => { function fieldMarkup(id, fieldType, label, action, value) { const className = "wc-block-components-text-input wc-block-components-address-form__" + id; - return
-
+ return
+ + +
} - if (item.name === "mollie_wc_gateway_billie"){ - if(isCompanyFieldVisible) { + if (item.name === "mollie_wc_gateway_billie") { + if (isCompanyFieldVisible) { return; } const companyField = item.companyPlaceholder ? item.companyPlaceholder : "Company name"; @@ -231,7 +203,7 @@ const MollieComponent = (props) => { let fields = []; const birthdateField = item.birthdatePlaceholder ? item.birthdatePlaceholder : "Birthdate"; fields.push(fieldMarkup("billing-birthdate", "date", birthdateField, updateBirthdate, inputBirthdate)); - if (!isPhoneFieldVisible) { + if (isPhoneFieldVisible === false) { const phoneField = item.phonePlaceholder ? item.phonePlaceholder : "Phone"; fields.push(fieldMarkup("billing-phone-in3", "tel", phoneField, updatePhone, inputPhone)); } diff --git a/resources/js/mollieBlockIndex.js b/resources/js/mollieBlockIndex.js index 8f4f9e3c..b919acb3 100644 --- a/resources/js/mollieBlockIndex.js +++ b/resources/js/mollieBlockIndex.js @@ -22,9 +22,11 @@ import molliePaymentMethod from './blocks/molliePaymentMethod' function getPhoneField() { - const shippingPhone = shipping_address.phone ?? false; - const billingPhone = billing_address.phone ?? false - return billingPhone || shippingPhone; + const phoneFieldDataset = document.querySelector('[data-show-phone-field]'); + if (!phoneFieldDataset) { + return true; + } + return phoneFieldDataset.dataset.showPhoneField !== "false" } const isCompanyFieldVisible = getCompanyField(); diff --git a/resources/scss/mollie-block-custom-field.scss b/resources/scss/mollie-block-custom-field.scss new file mode 100644 index 00000000..7d73bd89 --- /dev/null +++ b/resources/scss/mollie-block-custom-field.scss @@ -0,0 +1,28 @@ +/* Style the container to match WooCommerce styling */ +.custom-input { + margin-bottom: 1.5em; + display: flex; + flex-direction: column; +} + +.custom-input label { + margin-bottom: 0.5em; + font-weight: bold; +} + +#billing-birthdate, +#billing-phone-in3 { + width: 100%; + padding: 0.75em; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + font-size: 1em; + margin-bottom: 1.25em; +} + +#billing-birthdate { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} diff --git a/src/Assets/AssetsModule.php b/src/Assets/AssetsModule.php index da8c7a6e..66699511 100644 --- a/src/Assets/AssetsModule.php +++ b/src/Assets/AssetsModule.php @@ -34,6 +34,7 @@ public function enqueueBlockCheckoutScripts(Data $dataService, array $gatewayIns } wp_enqueue_script(MollieCheckoutBlocksSupport::getScriptHandle()); wp_enqueue_style('mollie-gateway-icons'); + wp_enqueue_style('mollie-block-custom-field'); MollieCheckoutBlocksSupport::localizeWCBlocksData($dataService, $gatewayInstances); } @@ -288,6 +289,13 @@ public function registerBlockScripts(string $pluginUrl, string $pluginPath): voi (string) filemtime($this->getPluginPath($pluginPath, '/public/js/mollieBlockIndex.min.js')), true ); + wp_register_style( + 'mollie-block-custom-field', + $this->getPluginUrl($pluginUrl, '/public/css/mollie-block-custom-field.min.css'), + [], + (string) filemtime($this->getPluginPath($pluginPath, '/public/css/mollie-block-custom-field.min.css')), + 'screen' + ); } /** diff --git a/src/Gateway/GatewayModule.php b/src/Gateway/GatewayModule.php index ad652069..e68da8d4 100644 --- a/src/Gateway/GatewayModule.php +++ b/src/Gateway/GatewayModule.php @@ -327,16 +327,13 @@ static function ($paymentContext) { } ); add_action('add_meta_boxes_woocommerce_page_wc-orders', [$this, 'addShopOrderMetabox'], 10); - add_filter('woocommerce_form_field_args', static function ($args, $key, $value) use ($container) { - if ($key !== 'billing_phone') { - return $args; - } - if ($args['required'] === true) { - update_option('mollie_wc_is_phone_required_flag', true); - } else { + add_filter('woocommerce_checkout_fields', static function ($fields) use ($container) { + if (!isset($fields['billing']['billing_phone'])) { update_option('mollie_wc_is_phone_required_flag', false); + } else { + update_option('mollie_wc_is_phone_required_flag', true); } - return $args; + return $fields; }, 10, 3); return true; } @@ -655,11 +652,8 @@ public function in3FieldsMandatory($fields, $errors) { $gatewayName = "mollie_wc_gateway_in3"; $phoneField = 'billing_phone_in3'; - $birthdateField = self::FIELD_IN3_BIRTHDATE; $phoneLabel = __('Phone', 'mollie-payments-for-woocommerce'); - $birthDateLabel = __('Birthdate', 'mollie-payments-for-woocommerce'); - $fields = $this->addPaymentMethodMandatoryFieldsPhoneVerification($fields, $gatewayName, $phoneField, $phoneLabel, $errors); - return $this->addPaymentMethodMandatoryFields($fields, $gatewayName, $birthdateField, $birthDateLabel, $errors); + return $this->addPaymentMethodMandatoryFieldsPhoneVerification($fields, $gatewayName, $phoneField, $phoneLabel, $errors); } /** @@ -673,31 +667,11 @@ public function in3FieldsMandatoryPayForOrder($order) return; } - $birthdateValue = filter_input(INPUT_POST, self::FIELD_IN3_BIRTHDATE, FILTER_SANITIZE_SPECIAL_CHARS) ?? false; - $birthDateLabel = __('Birthdate', 'mollie-payments-for-woocommerce'); - - if (!$birthdateValue) { - wc_add_notice( - sprintf( - __('%s is a required field.', 'woocommerce'), - "$birthDateLabel" - ), - 'error' - ); - } $phoneValue = filter_input(INPUT_POST, 'billing_phone_in3', FILTER_SANITIZE_SPECIAL_CHARS) ?? false; - $phoneValue = $phoneValue && $this->isPhoneValid($phoneValue) ? $phoneValue : false; - $phoneLabel = __('Phone', 'mollie-payments-for-woocommerce'); + $phoneValue = transformPhoneToNLFormat($phoneValue); + $phoneValid = $phoneValue && $this->isPhoneValid($phoneValue) ? $phoneValue : null; - if (!$phoneValue) { - wc_add_notice( - sprintf( - __('%s is a required field. Valid phone format +000000000', 'mollie-payments-for-woocommerce'), - "$phoneLabel" - ), - 'error' - ); - } else { + if ($phoneValid) { $order->set_billing_phone($phoneValue); } } @@ -773,33 +747,20 @@ public function addPaymentMethodMandatoryFieldsPhoneVerification( if ($fields['payment_method'] !== $gatewayName) { return $fields; } - if (isset($fields['billing_phone']) && $this->isPhoneValid($fields['billing_phone'])) { + if (!empty($fields['billing_phone']) && $this->isPhoneValid($fields['billing_phone'])) { return $fields; } - $fieldPosted = filter_input(INPUT_POST, $field, FILTER_SANITIZE_SPECIAL_CHARS) ?? false; - if (!$fieldPosted) { - $errors->add( - 'validation', - sprintf( - __('%s is a required field.', 'woocommerce'), - "$fieldLabel" - ) - ); + if (!empty($fields['billing_phone']) && !$this->isPhoneValid($fields['billing_phone'])) { + $fields['billing_phone'] = null; return $fields; } + $fieldPosted = filter_input(INPUT_POST, $field, FILTER_SANITIZE_SPECIAL_CHARS) ?? false; - if (!$this->isPhoneValid($fieldPosted)) { - $errors->add( - 'validation', - sprintf( - __('%s is not a valid phone number. Valid phone format +00000000000', 'woocommerce'), - "$fieldLabel" - ) - ); - return $fields; - } else { + if ($fieldPosted && !$this->isPhoneValid($fieldPosted)) { $fields['billing_phone'] = $fieldPosted; + return $fields; } + $fields['billing_phone'] = null; return $fields; } @@ -822,7 +783,7 @@ public function switchFields($data) private function isPhoneValid($billing_phone) { - return preg_match('/^\+[1-9]\d{10,13}$/', $billing_phone); + return preg_match('/^\+[1-9]\d{10,13}$|^[1-9]\d{9,13}$|^06\d{9,13}$/', $billing_phone); } public function addPhoneWhenRest($arrayContext) @@ -835,17 +796,15 @@ public function addPhoneWhenRest($arrayContext) if (!empty($billingPhone) && $this->isPhoneValid($billingPhone)) { return; } + if (!empty($billingPhone) && !$this->isPhoneValid($billingPhone)) { + $context->order->set_billing_phone(null); + $context->order->save(); + return; + } $billingPhone = $context->payment_data['billing_phone']; - if ($billingPhone) { + if ($billingPhone && $this->isPhoneValid($billingPhone)) { $context->order->set_billing_phone($billingPhone); $context->order->save(); - } else { - $message = __('Please introduce a valid phone number. +00000000000', 'mollie-payments-for-woocommerce'); - throw new RouteException( - 'woocommerce_rest_checkout_process_payment_error', - $message, - 402 - ); } } } diff --git a/src/Gateway/MolliePaymentGateway.php b/src/Gateway/MolliePaymentGateway.php index 7047080a..c9a72920 100644 --- a/src/Gateway/MolliePaymentGateway.php +++ b/src/Gateway/MolliePaymentGateway.php @@ -1014,8 +1014,8 @@ public function onOrderReceivedText($text, $order) public function getSelectedIssuer(): ?string { $issuer_id = $this->pluginId . '_issuer_' . $this->id; - - $postedIssuer = filter_input(INPUT_POST, $issuer_id, FILTER_SANITIZE_SPECIAL_CHARS); + //phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized + $postedIssuer = wc_clean(wp_unslash($_POST[$issuer_id] ?? '')); return !empty($postedIssuer) ? $postedIssuer : null; } diff --git a/src/Payment/MollieOrder.php b/src/Payment/MollieOrder.php index 4a3e0feb..8c4a85f7 100644 --- a/src/Payment/MollieOrder.php +++ b/src/Payment/MollieOrder.php @@ -1226,9 +1226,14 @@ protected function getFormatedPhoneNumber(string $phone) { //remove whitespaces and all non numerical characters except + $phone = preg_replace('/[^0-9+]+/', '', $phone); + if (!is_string($phone)) { + return null; + } + //check if phone starts with 06 and replace with +316 + $phone = transformPhoneToNLFormat($phone); - //check that $phone is in E164 format - if ($phone !== null && preg_match('/^\+[1-9]\d{1,14}$/', $phone)) { + //check that $phone is in E164 format or can be changed by api + if (preg_match('/^\+[1-9]\d{10,13}$|^[1-9]\d{9,13}$/', $phone)) { return $phone; } return null; diff --git a/src/PaymentMethods/In3.php b/src/PaymentMethods/In3.php index be4b7ec3..51e5d7bf 100644 --- a/src/PaymentMethods/In3.php +++ b/src/PaymentMethods/In3.php @@ -23,10 +23,10 @@ public function getConfig(): array 'confirmationDelayed' => false, 'orderMandatory' => true, 'errorMessage' => __( - 'Required field is empty. Phone and birthdate fields are required.', + 'Required field is empty or invalid. Phone (+316xxxxxxxx) and birthdate fields are required.', 'mollie-payments-for-woocommerce' ), - 'phonePlaceholder' => __('Please enter your phone here. +00..', 'mollie-payments-for-woocommerce'), + 'phonePlaceholder' => __('Please enter your phone here. +316xxxxxxxx', 'mollie-payments-for-woocommerce'), 'birthdatePlaceholder' => __('Please enter your birthdate here.', 'mollie-payments-for-woocommerce'), ]; } diff --git a/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php index 0952e392..777f9fe1 100644 --- a/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php +++ b/src/PaymentMethods/PaymentFieldsStrategies/BancomatpayFieldsStrategy.php @@ -46,7 +46,7 @@ protected function phoneNumber($phoneValue)

diff --git a/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php b/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php index 3c0fdcff..abdd3d23 100644 --- a/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php +++ b/src/PaymentMethods/PaymentFieldsStrategies/In3FieldsStrategy.php @@ -51,7 +51,6 @@ protected function dateOfBirth() ?>

diff --git a/tests/php/Functional/Payment/PaymentServiceTest.php b/tests/php/Functional/Payment/PaymentServiceTest.php index 4aef1f34..52e7e8bc 100644 --- a/tests/php/Functional/Payment/PaymentServiceTest.php +++ b/tests/php/Functional/Payment/PaymentServiceTest.php @@ -118,7 +118,7 @@ public function processPayment_Order_success(){ ->willReturn(''); $wcOrder->expects($this->any()) ->method('get_billing_phone') - ->willReturn('+1234567890'); + ->willReturn('+34345678900'); /* * Execute Test */ @@ -225,7 +225,7 @@ private function wcOrder($id, $orderKey) 'get_billing_city' => 'billingcity', 'get_billing_state' => 'billingregion', 'get_billing_country' => 'billingcountry', - 'get_billing_phone' => '+1234567890', + 'get_billing_phone' => '+34345678900', 'get_shipping_address_1' => 'shippingstreetAndNumber', 'get_shipping_address_2' => 'shippingstreetAdditional', 'get_shipping_postcode' => 'shippingpostalCode', diff --git a/webpack.config.js b/webpack.config.js index 1ae240bf..e15815b4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -46,6 +46,7 @@ function configCss ({ basePath }) .addStyleEntry('mollie-gateway-icons.min', './resources/scss/mollie-gateway-icons.scss') .addStyleEntry('unabledButton.min', './resources/scss/unabledButton.scss') .addStyleEntry('mollie-applepaydirect.min', './resources/scss/mollie-applepaydirect.scss') + .addStyleEntry('mollie-block-custom-field.min', './resources/scss/mollie-block-custom-field.scss') .enableSourceMaps(!Encore.isProduction()) return extractEncoreConfig('css-configuration')