Fix shipping cost formatting to respect shipping formula (#42916)
This commit is contained in:
parent
4d7bf10c96
commit
4a5373409b
|
@ -3,7 +3,44 @@
|
|||
*/
|
||||
import { useContext, useEffect } from '@wordpress/element';
|
||||
import { CurrencyContext } from '@woocommerce/currency';
|
||||
import { numberFormat } from '@woocommerce/number';
|
||||
import { numberFormat, parseNumber } from '@woocommerce/number';
|
||||
|
||||
/**
|
||||
* Escape special characters for user input in regex.
|
||||
*
|
||||
* @param {string} string
|
||||
* @return {string} string
|
||||
*/
|
||||
const escapeRegExp = ( string ) => {
|
||||
return string.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Format number when it's exclusively a number or a string of numbers, otherwise return the input.
|
||||
*/
|
||||
export const safeNumberFormat = ( config, number ) => {
|
||||
if ( typeof number === 'number' ) {
|
||||
return numberFormat( config, number );
|
||||
}
|
||||
|
||||
if ( typeof number === 'string' ) {
|
||||
const dot = escapeRegExp( config.decimalSeparator );
|
||||
const comma = escapeRegExp( config.thousandSeparator );
|
||||
|
||||
// Regex to match strictly numbers with arbitrary thousands and decimal separators.
|
||||
// Example: /^\s*(\d+|\d{1,3}(?:,\d{3})*)(?:\.\d+)?\s*$/ for default config.
|
||||
const regex = new RegExp(
|
||||
`^\\s*(\\d+|\\d{1,3}(?:${ comma }\\d{3})*)(?:${ dot }\\d+)?\\s*$`
|
||||
);
|
||||
|
||||
return number.replace( regex, ( n ) => {
|
||||
const parsed = parseNumber( config, n );
|
||||
return numberFormat( config, parsed );
|
||||
} );
|
||||
}
|
||||
|
||||
return number;
|
||||
};
|
||||
|
||||
export const ShippingCurrencyContext = () => {
|
||||
const context = useContext( CurrencyContext );
|
||||
|
@ -12,7 +49,7 @@ export const ShippingCurrencyContext = () => {
|
|||
window.wc.ShippingCurrencyContext =
|
||||
window.wc.ShippingCurrencyContext || context;
|
||||
window.wc.ShippingCurrencyNumberFormat =
|
||||
window.wc.ShippingCurrencyNumberFormat || numberFormat;
|
||||
window.wc.ShippingCurrencyNumberFormat || safeNumberFormat;
|
||||
}, [ context ] );
|
||||
|
||||
return null;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { numberFormat } from '@woocommerce/number';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { safeNumberFormat } from '../currency-context';
|
||||
|
||||
const config = {
|
||||
code: 'USD',
|
||||
symbol: '$',
|
||||
symbolPosition: 'left',
|
||||
decimalSeparator: '.',
|
||||
priceFormat: '%1$s%2$s',
|
||||
thousandSeparator: ',',
|
||||
precision: 2,
|
||||
};
|
||||
|
||||
describe( 'CurrencyContext', () => {
|
||||
it( 'should format a number input correctly', () => {
|
||||
expect( safeNumberFormat( config, 1234 ) ).toBe(
|
||||
numberFormat( config, 1234 )
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should format string numbers correctly', () => {
|
||||
expect( safeNumberFormat( config, '123456789' ) ).toBe(
|
||||
'123,456,789.00'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should format with swapped decimal and thousand separator', () => {
|
||||
const customConfig = {
|
||||
...config,
|
||||
decimalSeparator: ',',
|
||||
thousandSeparator: '.',
|
||||
};
|
||||
expect( safeNumberFormat( customConfig, '123.456.789' ) ).toBe(
|
||||
'123.456.789,00'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should not format incorrectly formatted numbers according to current config', () => {
|
||||
const customConfig = {
|
||||
...config,
|
||||
decimalSeparator: ',',
|
||||
thousandSeparator: '.',
|
||||
};
|
||||
expect( safeNumberFormat( customConfig, '7.5' ) ).toBe( '7.5' );
|
||||
} );
|
||||
|
||||
it( 'should format number according to precision', () => {
|
||||
const customConfig = {
|
||||
...config,
|
||||
precision: 5,
|
||||
};
|
||||
expect( safeNumberFormat( customConfig, '123.4' ) ).toBe( '123.40000' );
|
||||
} );
|
||||
|
||||
it( 'should format number and trim leading and trailing spaces', () => {
|
||||
expect( safeNumberFormat( config, ' 1234 ' ) ).toBe( '1,234.00' );
|
||||
} );
|
||||
|
||||
it( 'should not format numbers when text is included', () => {
|
||||
expect( safeNumberFormat( config, 'Value 1234' ) ).toBe( 'Value 1234' );
|
||||
} );
|
||||
|
||||
it( 'should not format when formula is included', () => {
|
||||
expect(
|
||||
safeNumberFormat( config, '50 + (([qty]*2+1)(5*10))(1)' )
|
||||
).toBe( '50 + (([qty]*2+1)(5*10))(1)' );
|
||||
} );
|
||||
|
||||
it( 'should return the original input for non-string, non-number inputs', () => {
|
||||
const input = { some: 'object' };
|
||||
expect( safeNumberFormat( config, input ) ).toBe( input );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: fix
|
||||
|
||||
Fix shipping cost formatting to respect shipping formula
|
|
@ -281,7 +281,7 @@ class WC_Shipping_Flat_Rate extends WC_Shipping_Method {
|
|||
public function sanitize_cost( $value ) {
|
||||
$value = is_null( $value ) ? '' : $value;
|
||||
$value = wp_kses_post( trim( wp_unslash( $value ) ) );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ), wc_get_price_thousand_separator() ), '', $value );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ) ), '', $value );
|
||||
// Thrown an error on the front end if the evaluate_cost will fail.
|
||||
$dummy_cost = $this->evaluate_cost(
|
||||
$value,
|
||||
|
|
|
@ -94,9 +94,12 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
|
|||
public function sanitize_cost( $value ) {
|
||||
$value = is_null( $value ) ? '' : $value;
|
||||
$value = wp_kses_post( trim( wp_unslash( $value ) ) );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ), wc_get_price_thousand_separator() ), '', $value );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ) ), '', $value );
|
||||
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
$test_value = str_replace( wc_get_price_decimal_separator(), '.', $value );
|
||||
$test_value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ), wc_get_price_thousand_separator() ), '', $test_value );
|
||||
|
||||
if ( $test_value && ! is_numeric( $test_value ) ) {
|
||||
throw new Exception( __( 'Please enter a valid number', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -90,9 +90,12 @@ class WC_Shipping_Local_Pickup extends WC_Shipping_Method {
|
|||
public function sanitize_cost( $value ) {
|
||||
$value = is_null( $value ) ? '' : $value;
|
||||
$value = wp_kses_post( trim( wp_unslash( $value ) ) );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ), wc_get_price_thousand_separator() ), '', $value );
|
||||
$value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ) ), '', $value );
|
||||
|
||||
if ( $value && ! is_numeric( $value ) ) {
|
||||
$test_value = str_replace( wc_get_price_decimal_separator(), '.', $value );
|
||||
$test_value = str_replace( array( get_woocommerce_currency_symbol(), html_entity_decode( get_woocommerce_currency_symbol() ), wc_get_price_thousand_separator() ), '', $test_value );
|
||||
|
||||
if ( $test_value && ! is_numeric( $test_value ) ) {
|
||||
throw new Exception( __( 'Please enter a valid number', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue