Skip to content

Commit

Permalink
BO: Harmonize string to float conversion on the product page
Browse files Browse the repository at this point in the history
+ change price input on combinations to text in order to prevent problems when typing values with comma
  • Loading branch information
eternoendless committed Jun 22, 2017
1 parent 266cdde commit 676b2fc
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 49 deletions.
94 changes: 56 additions & 38 deletions admin-dev/themes/default/js/bundle/product/form.js
Expand Up @@ -444,7 +444,7 @@ var supplier = (function() {

var supplierInputManage = function(input) {
var supplierDefaultInput = $('#form_step6_suppliers input[name="form[step6][default_supplier]"][value=' + $(input).val() +']');
if($(input).is(':checked')) {
if ($(input).is(':checked')) {
supplierDefaultInput.prop('disabled', false).show();
} else {
supplierDefaultInput.prop('disabled', true).hide();
Expand Down Expand Up @@ -1741,26 +1741,26 @@ var priceCalculation = (function() {

/**
* Add taxes to a price
* @param {float} Price without tax
* @param {array} Rates rates to apply
* @param {int} computation_method The computation calculate method
* @param {Number} price -Price without tax
* @param {Number[]} rates - Rates to apply
* @param {Number} computationMethod The computation calculate method
*/
function addTaxes(price, rates, computation_method) {
function addTaxes(price, rates, computationMethod) {
var price_with_taxes = price;

var i = 0;
if (computation_method === '0') {
if (computationMethod === '0') {
for (i in rates) {
price_with_taxes *= (1.00 + parseFloat(rates[i]) / 100.00);
break;
}
} else if (computation_method === '1') {
} else if (computationMethod === '1') {
var rate = 0;
for (i in rates) {
rate += rates[i];
}
price_with_taxes *= (1.00 + parseFloat(rate) / 100.00);
} else if (computation_method === '2') {
} else if (computationMethod === '2') {
for (i in rates) {
price_with_taxes *= (1.00 + parseFloat(rates[i]) / 100.00);
}
Expand All @@ -1771,24 +1771,24 @@ var priceCalculation = (function() {

/**
* Remove taxes from a price
* @param {float} Price with tax
* @param {array} Rates rates to apply
* @param {int} computation_method The computation calculate method
* @param {Number} price - Price with tax
* @param {Number[]} rates - Rates to apply
* @param {Number} computationMethod - The computation method
*/
function removeTaxes(price, rates, computation_method) {
function removeTaxes(price, rates, computationMethod) {
var i = 0;
if (computation_method === '0') {
if (computationMethod === '0') {
for (i in rates) {
price /= (1 + rates[i] / 100);
break;
}
} else if (computation_method === '1') {
} else if (computationMethod === '1') {
var rate = 0;
for (i in rates) {
rate += rates[i];
}
price /= (1 + rate / 100);
} else if (computation_method === '2') {
} else if (computationMethod === '2') {
for (i in rates) {
price /= (1 + rates[i] / 100);
}
Expand All @@ -1797,18 +1797,28 @@ var priceCalculation = (function() {
return price;
}

/**
*
* @return {Number}
*/
function getEcotaxTaxIncluded() {
var displayPrecision = 6;
if ( ecoTaxElem.val() == 0) {
return ecoTaxElem.val();
var ecoTax = Tools.parseFloatFromString(ecoTaxElem.val());

if (isNaN(ecoTax)) {
ecoTax = 0;
}

if (ecoTax === 0) {
return ecoTax;
}
var ecotax_tax_excl = ecoTaxElem.val().replace(/,/g, '.') / (1 + ecoTaxRate);
var ecotaxTaxExcl = ecoTax / (1 + ecoTaxRate);

return ps_round(ecotax_tax_excl * (1 + ecoTaxRate), displayPrecision);
return ps_round(ecotaxTaxExcl * (1 + ecoTaxRate), displayPrecision);
}

function getEcotaxTaxExcluded() {
return ecoTaxElem.val().replace(/,/g, '.') / (1 + ecoTaxRate);
return Tools.parseFloatFromString(ecoTaxElem.val()) / (1 + ecoTaxRate);
}

return {
Expand Down Expand Up @@ -1858,10 +1868,10 @@ var priceCalculation = (function() {
var taxExcludedPrice = priceCalculation.normalizePrice($('#form_step2_price').val());
var taxIncludedPrice = priceCalculation.normalizePrice($('#form_step2_price_ttc').val());

formatCurrencyCldr(parseFloat(taxExcludedPrice), function(result) {
formatCurrencyCldr(taxExcludedPrice, function(result) {
$('#final_retail_price_te').text(result);
});
formatCurrencyCldr(parseFloat(taxIncludedPrice), function(result) {
formatCurrencyCldr(taxIncludedPrice, function(result) {
$('#final_retail_price_ti').text(result);
});
});
Expand Down Expand Up @@ -1890,19 +1900,13 @@ var priceCalculation = (function() {
$('#form_step2_price, #form_step2_price_ttc').change();
},
'normalizePrice': function (price) {
price = parseFloat(price.replace(/,/g, '.'));

if (isNaN(price) || price === '') {
price = 0;
}

return price;
return Tools.parseFloatFromString(price, true);
},
'addCurrentTax': function (price) {
var rates = taxElem.find('option:selected').attr('data-rates').split(',');
var rates = this.getRates();
var computation_method = taxElem.find('option:selected').attr('data-computation-method');
var priceWithTaxes = new Number(ps_round(addTaxes(price, rates, computation_method), displayPricePrecision));
var ecotaxIncluded = new Number(getEcotaxTaxIncluded());
var priceWithTaxes = Number(ps_round(addTaxes(price, rates, computation_method), displayPricePrecision));
var ecotaxIncluded = Number(getEcotaxTaxIncluded());

return priceWithTaxes + ecotaxIncluded;
},
Expand All @@ -1913,7 +1917,7 @@ var priceCalculation = (function() {
priceTTCShorcutElem.val(newPrice).change();
},
'removeCurrentTax': function (price) {
var rates = taxElem.find('option:selected').attr('data-rates').split(',');
var rates = this.getRates();
var computation_method = taxElem.find('option:selected').attr('data-computation-method');

return ps_round(removeTaxes(ps_round(price - getEcotaxTaxIncluded(), displayPricePrecision), rates, computation_method), displayPricePrecision);
Expand All @@ -1925,13 +1929,13 @@ var priceCalculation = (function() {
priceHTShortcutElem.val(newPrice).change();
},
'impactTaxInclude': function(obj) {
var price = this.normalizePrice(obj.val());
var price = Tools.parseFloatFromString(obj.val());
var targetInput = obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTI');
if (isNaN(price)) {
targetInput.val(0);
return;
}
var rates = taxElem.find('option:selected').attr('data-rates').split(',');
var rates = this.getRates();
var computation_method = taxElem.find('option:selected').attr('data-computation-method');
var newPrice = ps_round(addTaxes(price, rates, computation_method), 6);
newPrice = truncateDecimals(newPrice, 6);
Expand All @@ -1942,24 +1946,38 @@ var priceCalculation = (function() {
var price = this.normalizePrice(obj.val());
var finalPrice = obj.closest('div[id^="combination_form_"]').find('.final-price');
var defaultFinalPrice = finalPrice.attr('data-price');
var priceToBeChanged = new Number(price) + new Number(defaultFinalPrice);
var priceToBeChanged = Number(price) + Number(defaultFinalPrice);
priceToBeChanged = truncateDecimals(priceToBeChanged, 6);

finalPrice.html(priceToBeChanged);
},
'impactTaxExclude': function(obj) {
var price = this.normalizePrice(obj.val());
var price = Tools.parseFloatFromString(obj.val());
var targetInput = obj.closest('div[id^="combination_form_"]').find('input.attribute_priceTE');
if (isNaN(price)) {
targetInput.val(0);
return;
}
var rates = taxElem.find('option:selected').attr('data-rates').split(',');
var rates = this.getRates();
var computation_method = taxElem.find('option:selected').attr('data-computation-method');
var newPrice = removeTaxes(ps_round(price, displayPricePrecision), rates, computation_method);
newPrice = truncateDecimals(newPrice, 6);

targetInput.val(newPrice);
},

/**
*
* @return {Number[]}
*/
getRates: function() {
return taxElem
.find('option:selected')
.attr('data-rates')
.split(',')
.map(function(rate) {
return Tools.parseFloatFromString(rate, true);
});
}
};
})();
Expand Down
23 changes: 13 additions & 10 deletions admin-dev/themes/default/js/bundle/product/product-combinations.js
Expand Up @@ -45,19 +45,22 @@ var combinations = (function() {

/**
* Update final price, regarding the impact on price in combinations table
* @param {object} elem - The tableau row parent
* @param {jQuery} tableRow - Table row that contains the combination
*/
function updateFinalPrice(tableRow) {
if (!tableRow.is('tr')) {
throw new Error('Structure of table has changed, this function need to be updated.');
throw new Error('Structure of table has changed, this function needs to be updated.');
}
var priceImpactInput = tableRow.find('.attribute_priceTE');
var impactOnPrice = priceImpactInput.val() - priceImpactInput.attr('value');
var actualFinalPriceInput = tableRow.find('.attribute-finalprice span');
var actualFinalPrice = actualFinalPriceInput.data('price');
var priceImpactInput = tableRow.find('.attribute_priceTE').first();
var finalPriceLabel = tableRow.find('.attribute-finalprice span');

var finalPrice = new Number(actualFinalPrice) + new Number(impactOnPrice);
actualFinalPriceInput.html(ps_round(finalPrice, 6));
var impactOnPrice = Tools.parseFloatFromString(priceImpactInput.val());
var previousImpactOnPrice = Tools.parseFloatFromString(priceImpactInput.attr('value'));

var currentFinalPrice = Tools.parseFloatFromString(finalPriceLabel.data('price'), true);
var finalPrice = currentFinalPrice - previousImpactOnPrice + impactOnPrice;

finalPriceLabel.html(Number(ps_round(finalPrice, 6)).toFixed(6));
}

return {
Expand Down Expand Up @@ -130,7 +133,7 @@ var combinations = (function() {
$(document).on('keyup', 'input[id^="combination"][id$="_attribute_price"]', function() {
var id_attribute = $(this).closest('.combination-form').attr('data');
var attributePrice = $('#accordion_combinations #attribute_' + id_attribute).find('.attribute-price-display');
formatCurrencyCldr(parseFloat($(this).val()), function(result) {
formatCurrencyCldr(Tools.parseFloatFromString($(this).val(), true), function(result) {
attributePrice.html(result);
});
});
Expand Down Expand Up @@ -158,7 +161,7 @@ var combinations = (function() {
},
error: function(response) {
showErrorMessage(jQuery.parseJSON(response.responseText).message);
},
}
});
// enable the top header selector
// we want to use a "Simple product" without any combinations
Expand Down
45 changes: 45 additions & 0 deletions js/tools.js
Expand Up @@ -23,6 +23,51 @@
* International Registered Trademark & Property of PrestaShop SA
*/

var Tools = {

/**
* Constructs a float value from an arbitrarily-formatted string.
* In order to prevent unexpected behavior, make sure that your value has a decimal part.
* @param {String} value Value to convert to float
* @param {Boolean} [coerce=false] If true, this function will return 0 instad of NaN if the value cannot be parsed to float
*
* @return {Number}
*/
parseFloatFromString: function(value, coerce) {
value = String(value).trim();

if ('' === value) {
return 0;
}

// check if the string can be converted to float as-is
var parsed = parseFloat(value);
if (String(parsed) === value) {
return parsed;
}

// remove all non-digit characters
var split = value.split(/[^\dE-]+/);

if (1 === split.length) {
// there's no decimal part
return parseFloat(value);
}

for (var i = 0; i < split.length; i++) {
if ('' === split[i]) {
return coerce ? 0 : NaN;
}
}

// use the last part as decimal
var decimal = split.pop();

// reconstruct the number using dot as decimal separator
return parseFloat(split.join('') + '.' + decimal);
}
};

/**
* @returns float parsed from a string containing a formatted price
*/
Expand Down
Expand Up @@ -29,7 +29,7 @@
<td class="attribute-price">
<div class="input-group">
<span class="input-group-addon">{{ default_currency }}</span>
<input type="number" class="attribute_priceTE form-control text-xs-right" value="{{ form.vars.value.attribute_price }}">
<input type="text" class="attribute_priceTE form-control text-xs-right" value="{{ form.vars.value.attribute_price }}">
</div>
</td>
<td class="attribute-finalprice text-xs-right">
Expand Down

0 comments on commit 676b2fc

Please sign in to comment.