From a646d96bec3768368be3524e85569bc76dedc3e2 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Wed, 31 Jul 2019 19:48:22 -0300 Subject: [PATCH 1/8] Make wc_format_decimal() strip multiple decimal separators --- includes/wc-formatting-functions.php | 1 + 1 file changed, 1 insertion(+) diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php index f0cd54c647e..2fdd57b0739 100644 --- a/includes/wc-formatting-functions.php +++ b/includes/wc-formatting-functions.php @@ -293,6 +293,7 @@ function wc_format_decimal( $number, $dp = false, $trim_zeros = false ) { if ( ! is_float( $number ) ) { $number = str_replace( $decimals, '.', $number ); $number = preg_replace( '/[^0-9\.,-]/', '', wc_clean( $number ) ); + $number = preg_replace( '/\.+/', '.', $number ); } if ( false !== $dp ) { From 83c0e696374366207696d0c5fccd63963db2c5fb Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Wed, 31 Jul 2019 19:54:58 -0300 Subject: [PATCH 2/8] Update wc_format_decimal() tests to check for multiple decimals points --- includes/wc-formatting-functions.php | 2 ++ tests/unit-tests/formatting/functions.php | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php index 2fdd57b0739..e2677c4d57a 100644 --- a/includes/wc-formatting-functions.php +++ b/includes/wc-formatting-functions.php @@ -293,6 +293,8 @@ function wc_format_decimal( $number, $dp = false, $trim_zeros = false ) { if ( ! is_float( $number ) ) { $number = str_replace( $decimals, '.', $number ); $number = preg_replace( '/[^0-9\.,-]/', '', wc_clean( $number ) ); + + // Convert multiple dots to just one. $number = preg_replace( '/\.+/', '.', $number ); } diff --git a/tests/unit-tests/formatting/functions.php b/tests/unit-tests/formatting/functions.php index a2d9be890fe..3c61ee12da9 100644 --- a/tests/unit-tests/formatting/functions.php +++ b/tests/unit-tests/formatting/functions.php @@ -290,6 +290,9 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { // Given string. $this->assertEquals( '9.99', wc_format_decimal( '9.99' ) ); + // Given string with multiple decimals points. + $this->assertEquals( '9.99', wc_format_decimal( '9...99' ) ); + // Float. $this->assertEquals( '9.99', wc_format_decimal( 9.99 ) ); @@ -316,7 +319,10 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { update_option( 'woocommerce_price_thousand_sep', '.' ); // Given string. - $this->assertEquals( '9.99', wc_format_decimal( '9.99' ) ); + $this->assertEquals( '9.99', wc_format_decimal( '9,99' ) ); + + // Given string with multiple decimals points. + $this->assertEquals( '9.99', wc_format_decimal( '9,,,99' ) ); // Float. $this->assertEquals( '9.99', wc_format_decimal( 9.99 ) ); From 375b989322c7d8f45ae62cd5752f3f0630686d43 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Fri, 2 Aug 2019 13:58:02 -0300 Subject: [PATCH 3/8] Added validation for multiple decimal points --- assets/js/admin/woocommerce_admin.js | 12 +++++++++++- includes/admin/class-wc-admin-assets.php | 4 ++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/assets/js/admin/woocommerce_admin.js b/assets/js/admin/woocommerce_admin.js index f9e88587d00..c4a2b09e6c1 100644 --- a/assets/js/admin/woocommerce_admin.js +++ b/assets/js/admin/woocommerce_admin.js @@ -78,22 +78,32 @@ }) .on( 'keyup', '.wc_input_price[type=text], .wc_input_decimal[type=text], .wc_input_country_iso[type=text], .wc-order-totals #refund_amount[type=text]', function() { - var regex, error; + var regex, error, decimalRegex; + var checkDecimalNumbers = false; if ( $( this ).is( '.wc_input_price' ) || $( this ).is( '#refund_amount' ) ) { + checkDecimalNumbers = true; regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.mon_decimal_point + ']+', 'gi' ); + decimalRegex = new RegExp( '[^\\' + woocommerce_admin.mon_decimal_point + ']', 'gi' ); error = 'i18n_mon_decimal_error'; } else if ( $( this ).is( '.wc_input_country_iso' ) ) { regex = new RegExp( '([^A-Z])+|(.){3,}', 'im' ); error = 'i18n_country_iso_error'; } else { + checkDecimalNumbers = true; regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.decimal_point + ']+', 'gi' ); + decimalRegex = new RegExp( '[^\\' + woocommerce_admin.decimal_point + ']', 'gi' ); error = 'i18n_decimal_error'; } var value = $( this ).val(); var newvalue = value.replace( regex, '' ); + // Check if newvalue have more than one decimal point. + if ( checkDecimalNumbers && 1 < newvalue.replace( decimalRegex, '' ).length ) { + newvalue = newvalue.replace( decimalRegex, '' ); + } + if ( value !== newvalue ) { $( document.body ).triggerHandler( 'wc_add_error_tip', [ $( this ), error ] ); } else { diff --git a/includes/admin/class-wc-admin-assets.php b/includes/admin/class-wc-admin-assets.php index 8a5c7b7f955..34defe99fc6 100644 --- a/includes/admin/class-wc-admin-assets.php +++ b/includes/admin/class-wc-admin-assets.php @@ -169,9 +169,9 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) : $params = array( /* translators: %s: decimal */ - 'i18n_decimal_error' => sprintf( __( 'Please enter in decimal (%s) format without thousand separators.', 'woocommerce' ), $decimal ), + 'i18n_decimal_error' => sprintf( __( 'Please enter with one decimal point (%s) without thousand separators.', 'woocommerce' ), $decimal ), /* translators: %s: price decimal separator */ - 'i18n_mon_decimal_error' => sprintf( __( 'Please enter in monetary decimal (%s) format without thousand separators and currency symbols.', 'woocommerce' ), wc_get_price_decimal_separator() ), + 'i18n_mon_decimal_error' => sprintf( __( 'Please enter with one monetary decimal point (%s) without thousand separators and currency symbols.', 'woocommerce' ), wc_get_price_decimal_separator() ), 'i18n_country_iso_error' => __( 'Please enter in country code with two capital letters.', 'woocommerce' ), 'i18n_sale_less_than_regular_error' => __( 'Please enter in a value less than the regular price.', 'woocommerce' ), 'i18n_delete_product_notice' => __( 'This product has produced sales and may be linked to existing orders. Are you sure you want to delete it?', 'woocommerce' ), From 2b0fc6f50a84234b6f717b84f8be2481bb500884 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Fri, 2 Aug 2019 14:02:33 -0300 Subject: [PATCH 4/8] Added sanitization for number of decimal points in JS --- assets/js/admin/woocommerce_admin.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/assets/js/admin/woocommerce_admin.js b/assets/js/admin/woocommerce_admin.js index c4a2b09e6c1..936bfe9a232 100644 --- a/assets/js/admin/woocommerce_admin.js +++ b/assets/js/admin/woocommerce_admin.js @@ -61,16 +61,20 @@ }) .on( 'change', '.wc_input_price[type=text], .wc_input_decimal[type=text], .wc-order-totals #refund_amount[type=text]', function() { - var regex; + var regex, decimalRegex, decimailPoint; if ( $( this ).is( '.wc_input_price' ) || $( this ).is( '#refund_amount' ) ) { - regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.mon_decimal_point + ']+', 'gi' ); + decimailPoint = woocommerce_admin.mon_decimal_point; + regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' ); + decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' ); } else { - regex = new RegExp( '[^\-0-9\%\\' + woocommerce_admin.decimal_point + ']+', 'gi' ); + decimailPoint = woocommerce_admin.decimal_point; + regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' ); + decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' ); } var value = $( this ).val(); - var newvalue = value.replace( regex, '' ); + var newvalue = value.replace( regex, '' ).replace( decimalRegex, decimailPoint ); if ( value !== newvalue ) { $( this ).val( newvalue ); From 9851b1f0f3dabc9b2e14fe0abc6278edd8d9240c Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Thu, 3 Oct 2019 21:19:52 -0300 Subject: [PATCH 5/8] DRY --- assets/js/admin/woocommerce_admin.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/assets/js/admin/woocommerce_admin.js b/assets/js/admin/woocommerce_admin.js index 936bfe9a232..fd5034073d0 100644 --- a/assets/js/admin/woocommerce_admin.js +++ b/assets/js/admin/woocommerce_admin.js @@ -61,18 +61,16 @@ }) .on( 'change', '.wc_input_price[type=text], .wc_input_decimal[type=text], .wc-order-totals #refund_amount[type=text]', function() { - var regex, decimalRegex, decimailPoint; + var regex, decimalRegex, + decimailPoint = woocommerce_admin.decimal_point; if ( $( this ).is( '.wc_input_price' ) || $( this ).is( '#refund_amount' ) ) { decimailPoint = woocommerce_admin.mon_decimal_point; - regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' ); - decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' ); - } else { - decimailPoint = woocommerce_admin.decimal_point; - regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' ); - decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' ); } + regex = new RegExp( '[^\-0-9\%\\' + decimailPoint + ']+', 'gi' ); + decimalRegex = new RegExp( '\\' + decimailPoint + '+', 'gi' ); + var value = $( this ).val(); var newvalue = value.replace( regex, '' ).replace( decimalRegex, decimailPoint ); From b4af5f3c8985376931bb6d48cfa4fa196cf7abc7 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Fri, 6 Dec 2019 11:11:47 -0300 Subject: [PATCH 6/8] Updated regex to allow only one decimal point --- includes/wc-formatting-functions.php | 3 +-- tests/unit-tests/formatting/functions.php | 12 ++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php index e2677c4d57a..cb163de4fd6 100644 --- a/includes/wc-formatting-functions.php +++ b/includes/wc-formatting-functions.php @@ -292,10 +292,9 @@ function wc_format_decimal( $number, $dp = false, $trim_zeros = false ) { // Remove locale from string. if ( ! is_float( $number ) ) { $number = str_replace( $decimals, '.', $number ); - $number = preg_replace( '/[^0-9\.,-]/', '', wc_clean( $number ) ); // Convert multiple dots to just one. - $number = preg_replace( '/\.+/', '.', $number ); + $number = preg_replace( '/\.(?![^.]+$)|[^0-9.-]/', '', wc_clean( $number ) ); } if ( false !== $dp ) { diff --git a/tests/unit-tests/formatting/functions.php b/tests/unit-tests/formatting/functions.php index 3c61ee12da9..0b1ab14ca7a 100644 --- a/tests/unit-tests/formatting/functions.php +++ b/tests/unit-tests/formatting/functions.php @@ -293,6 +293,12 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { // Given string with multiple decimals points. $this->assertEquals( '9.99', wc_format_decimal( '9...99' ) ); + // Given string with multiple decimals points. + $this->assertEquals( '99.9', wc_format_decimal( '9...9....9' ) ); + + // Negative string. + $this->assertEquals( '-9.99', wc_format_decimal( '-9.99' ) ); + // Float. $this->assertEquals( '9.99', wc_format_decimal( 9.99 ) ); @@ -324,6 +330,12 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { // Given string with multiple decimals points. $this->assertEquals( '9.99', wc_format_decimal( '9,,,99' ) ); + // Given string with multiple decimals points. + $this->assertEquals( '99.9', wc_format_decimal( '9,,,9,,,,9' ) ); + + // Negative string. + $this->assertEquals( '-9.99', wc_format_decimal( '-9,99' ) ); + // Float. $this->assertEquals( '9.99', wc_format_decimal( 9.99 ) ); From 78e382e4d68d5dc97edde05eecc5de8a833b7284 Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Fri, 6 Dec 2019 12:37:23 -0300 Subject: [PATCH 7/8] Fixed incorrect concatenation of variation sale prices with ".00" --- .../data-stores/class-wc-product-variable-data-store-cpt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/data-stores/class-wc-product-variable-data-store-cpt.php b/includes/data-stores/class-wc-product-variable-data-store-cpt.php index 7bfb90f6774..da79be368c7 100644 --- a/includes/data-stores/class-wc-product-variable-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-variable-data-store-cpt.php @@ -361,7 +361,7 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple $prices_array['price'][ $variation_id ] = wc_format_decimal( $price, wc_get_price_decimals() ); $prices_array['regular_price'][ $variation_id ] = wc_format_decimal( $regular_price, wc_get_price_decimals() ); - $prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price . '.00', wc_get_price_decimals() ); + $prices_array['sale_price'][ $variation_id ] = wc_format_decimal( $sale_price, wc_get_price_decimals() ); $prices_array = apply_filters( 'woocommerce_variation_prices_array', $prices_array, $variation, $for_display ); } From 85635773e918aa286f455c880c9d5a506d9ddd8b Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Fri, 6 Dec 2019 12:51:10 -0300 Subject: [PATCH 8/8] Fixed coding standards --- includes/wc-formatting-functions.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php index cb163de4fd6..77475fc24c4 100644 --- a/includes/wc-formatting-functions.php +++ b/includes/wc-formatting-functions.php @@ -737,7 +737,8 @@ function wc_timezone_string() { // Last try, guess timezone string manually. foreach ( timezone_abbreviations_list() as $abbr ) { foreach ( $abbr as $city ) { - if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { + // WordPress restrict the use of date(), since it's affected by timezone settings, but in this case is just what we need to guess the correct timezone. + if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) { // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date return $city['timezone_id']; } }