diff --git a/app/assets/javascripts/admin/products/controllers/units_controller.js.coffee b/app/assets/javascripts/admin/products/controllers/units_controller.js.coffee index df4cb42df4..89a7027e07 100644 --- a/app/assets/javascripts/admin/products/controllers/units_controller.js.coffee +++ b/app/assets/javascripts/admin/products/controllers/units_controller.js.coffee @@ -1,5 +1,5 @@ angular.module("admin.products") - .controller "unitsCtrl", ($scope, VariantUnitManager, OptionValueNamer, UnitPrices) -> + .controller "unitsCtrl", ($scope, VariantUnitManager, OptionValueNamer, UnitPrices, PriceParser) -> $scope.product = { master: {} } $scope.product.master.product = $scope.product $scope.placeholder_text = "" @@ -26,9 +26,9 @@ angular.module("admin.products") $scope.processUnitValueWithDescription = -> if $scope.product.master.hasOwnProperty("unit_value_with_description") - match = $scope.product.master.unit_value_with_description.match(/^([\d\.]+(?= *|$)|)( *)(.*)$/) + match = $scope.product.master.unit_value_with_description.match(/^([\d\.,]+(?= *|$)|)( *)(.*)$/) if match - $scope.product.master.unit_value = parseFloat(match[1]) + $scope.product.master.unit_value = PriceParser.parse(match[1]) $scope.product.master.unit_value = null if isNaN($scope.product.master.unit_value) $scope.product.master.unit_value *= $scope.product.variant_unit_scale if $scope.product.master.unit_value && $scope.product.variant_unit_scale $scope.product.master.unit_description = match[3] diff --git a/app/assets/javascripts/admin/products/controllers/variant_units_controller.js.coffee b/app/assets/javascripts/admin/products/controllers/variant_units_controller.js.coffee index 33c01542ff..39400c036e 100644 --- a/app/assets/javascripts/admin/products/controllers/variant_units_controller.js.coffee +++ b/app/assets/javascripts/admin/products/controllers/variant_units_controller.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout, UnitPrices) -> +angular.module("admin.products").controller "variantUnitsCtrl", ($scope, VariantUnitManager, $timeout, UnitPrices, PriceParser) -> $scope.unitName = (scale, type) -> VariantUnitManager.getUnitName(scale, type) @@ -23,7 +23,7 @@ angular.module("admin.products").controller "variantUnitsCtrl", ($scope, Variant $scope.updateValue = -> unit_value_human = angular.element('#unit_value_human').val() - $scope.unit_value = unit_value_human * $scope.scale + $scope.unit_value = PriceParser.parse(unit_value_human) * $scope.scale variant_unit_value = angular.element('#variant_unit_value').val() $scope.unit_value_human = variant_unit_value / $scope.scale diff --git a/app/assets/javascripts/admin/products/services/unit_prices.js.coffee b/app/assets/javascripts/admin/products/services/unit_prices.js.coffee index a5cb4d67de..f5da0569f9 100644 --- a/app/assets/javascripts/admin/products/services/unit_prices.js.coffee +++ b/app/assets/javascripts/admin/products/services/unit_prices.js.coffee @@ -1,7 +1,7 @@ -angular.module("admin.products").factory "UnitPrices", (VariantUnitManager, localizeCurrencyFilter, unlocalizeCurrencyFilter) -> +angular.module("admin.products").factory "UnitPrices", (VariantUnitManager, localizeCurrencyFilter, PriceParser) -> class UnitPrices @displayableUnitPrice: (price, scale, unit_type, unit_value, variant_unit_name) -> - price = unlocalizeCurrencyFilter(price) + price = PriceParser.parse(price) if price && !isNaN(price) && unit_type && unit_value value = localizeCurrencyFilter(UnitPrices.price(price, scale, unit_type, unit_value, variant_unit_name)) unit = UnitPrices.unit(scale, unit_type, variant_unit_name) diff --git a/app/assets/javascripts/admin/utils/filters/unlocalize_currency.js.coffee b/app/assets/javascripts/admin/utils/filters/unlocalize_currency.js.coffee deleted file mode 100644 index 1d176db9ac..0000000000 --- a/app/assets/javascripts/admin/utils/filters/unlocalize_currency.js.coffee +++ /dev/null @@ -1,15 +0,0 @@ -angular.module("admin.utils").filter "unlocalizeCurrency", ()-> - # Convert string to number using injected currency configuration. - (price) -> - # used decimal and thousands separators from currency configuration - decimal_separator = I18n.toCurrency(.1, {precision: 1, unit: ''}).substring(1,2) - thousands_separator = I18n.toCurrency(1000, {precision: 1, unit: ''}).substring(1,2) - - if (price.length > 4) - # remove configured thousands separator if price is greater than 999 - price = price.replaceAll(thousands_separator, '') - - if (decimal_separator == ",") - price = price.replace(",", ".") - - return parseFloat(price) diff --git a/app/assets/javascripts/admin/utils/services/price_parser.js.coffee b/app/assets/javascripts/admin/utils/services/price_parser.js.coffee new file mode 100644 index 0000000000..ce7cd3b874 --- /dev/null +++ b/app/assets/javascripts/admin/utils/services/price_parser.js.coffee @@ -0,0 +1,31 @@ +angular.module("admin.utils").factory "PriceParser", -> + new class PriceParser + parse: (price) => + return null unless price + # used decimal and thousands separators from currency configuration + decimal_separator = I18n.toCurrency(.1, {precision: 1, unit: ''}).substring(1,2) + thousands_separator = I18n.toCurrency(1000, {precision: 1, unit: ''}).substring(1,2) + + # Replace comma used as a decimal separator and remplace by "." + price = this.replaceCommaByFinalPoint(price) + + # Remove configured thousands separator if it is actually a thousands separator + price = this.removeThousandsSeparator(price, thousands_separator) + + if (decimal_separator == ",") + price = price.replace(",", ".") + + price = parseFloat(price) + + return null if isNaN(price) + + return price + + replaceCommaByFinalPoint : (price) => + if price.match(/^[0-9]*(,{1})[0-9]{1,2}$/g) then price.replace(",", ".") else price + + removeThousandsSeparator : (price, thousands_separator) => + if (new RegExp("^([0-9]*(" + thousands_separator + "{1})[0-9]{3}[0-9\.,]*)*$", "g").test(price)) + price.replaceAll(thousands_separator, '') + else + price diff --git a/spec/javascripts/unit/admin/filters/unlocalize_currency_spec.js.coffee b/spec/javascripts/unit/admin/filters/unlocalize_currency_spec.js.coffee deleted file mode 100644 index a21db8d05f..0000000000 --- a/spec/javascripts/unit/admin/filters/unlocalize_currency_spec.js.coffee +++ /dev/null @@ -1,91 +0,0 @@ -describe 'convert string to number with configurated currency', -> - filter = null - - beforeEach -> - module 'ofn.admin' - inject ($filter) -> - filter = $filter('unlocalizeCurrency') - - describe "with point as decimal separator and comma as thousands separator for I18n service", -> - - beforeEach -> - spyOn(I18n,'toCurrency').and.callFake (arg) -> - if (arg == 0.1) - return "0.1" - else if (arg == 1000) - return "1,000" - - it "handle point as decimal separator", -> - expect(filter("1.00")).toEqual 1.0 - - it "handle point as decimal separator", -> - expect(filter("1.000")).toEqual 1.0 - - it "also handle comma as decimal separator", -> - expect(filter("1,00")).toEqual 1.0 - - it "handle point as decimal separator and comma as thousands separator", -> - expect(filter("1,000,000.00")).toEqual 1000000 - - it "handle integer number", -> - expect(filter("10")).toEqual 10 - - it "handle integer number with comma as thousands separator", -> - expect(filter("1,000")).toEqual 1000 - - it "handle integer number with no thousands separator", -> - expect(filter("1000")).toEqual 1000 - - describe "with comma as decimal separator and final point as thousands separator for I18n service", -> - - beforeEach -> - spyOn(I18n,'toCurrency').and.callFake (arg) -> - if (arg == 0.1) - return "0,1" - else if (arg == 1000) - return "1.000" - - it "handle comma as decimal separator", -> - expect(filter("1,00")).toEqual 1.0 - - it "also handle point as decimal separator", -> - expect(filter("1.00")).toEqual 1.0 - - it "handle point as decimal separator and final point as thousands separator", -> - expect(filter("1.000.000,00")).toEqual 1000000 - - it "handle integer number", -> - expect(filter("10")).toEqual 10 - - it "handle integer number with final point as thousands separator", -> - expect(filter("1.000")).toEqual 1000 - - it "handle integer number with no thousands separator", -> - expect(filter("1000")).toEqual 1000 - - describe "with comma as decimal separator and space as thousands separator for I18n service", -> - - beforeEach -> - spyOn(I18n,'toCurrency').and.callFake (arg) -> - if (arg == 0.1) - return "0,1" - else if (arg == 1000) - return "1 000" - - it "handle comma as decimal separator", -> - expect(filter("1,00")).toEqual 1.0 - - it "also handle final point as decimal separator", -> - expect(filter("1.00")).toEqual 1.0 - - it "handle point as decimal separator and space as thousands separator", -> - expect(filter("1 000 000,00")).toEqual 1000000 - - it "handle integer number", -> - expect(filter("10")).toEqual 10 - - it "handle integer number with space as thousands separator", -> - expect(filter("1 000")).toEqual 1000 - - it "handle integer number with no thousands separator", -> - expect(filter("1000")).toEqual 1000 diff --git a/spec/javascripts/unit/admin/products/units_controller_spec.js.coffee b/spec/javascripts/unit/admin/products/units_controller_spec.js.coffee index 7e7ea03888..72046716cc 100644 --- a/spec/javascripts/unit/admin/products/units_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/products/units_controller_spec.js.coffee @@ -75,3 +75,21 @@ describe "unitsCtrl", -> scope.processUnitValueWithDescription() expect(scope.product.master.unit_value).toEqual 123 expect(scope.product.master.unit_description).toEqual "54 boxes" + + it "handle final point as decimal separator", -> + scope.product.master.unit_value_with_description = "22.22" + scope.processUnitValueWithDescription() + expect(scope.product.master.unit_value).toEqual 22.22 + expect(scope.product.master.unit_description).toEqual "" + + it "handle comma as decimal separator", -> + scope.product.master.unit_value_with_description = "22,22" + scope.processUnitValueWithDescription() + expect(scope.product.master.unit_value).toEqual 22.22 + expect(scope.product.master.unit_description).toEqual "" + + it "handle comma as decimal separator with description", -> + scope.product.master.unit_value_with_description = "22,22 things" + scope.processUnitValueWithDescription() + expect(scope.product.master.unit_value).toEqual 22.22 + expect(scope.product.master.unit_description).toEqual "things" diff --git a/spec/javascripts/unit/admin/utils/services/price_parser_spec.js.coffee b/spec/javascripts/unit/admin/utils/services/price_parser_spec.js.coffee new file mode 100644 index 0000000000..fb97815741 --- /dev/null +++ b/spec/javascripts/unit/admin/utils/services/price_parser_spec.js.coffee @@ -0,0 +1,152 @@ +describe "PriceParser service", -> + priceParser = null + + beforeEach -> + module('admin.utils') + inject (PriceParser) -> + priceParser = PriceParser + + describe "test internal method with Regexp", -> + describe "test replaceCommaByFinalPoint() method", -> + it "handle the default case (with two numbers after comma)", -> + expect(priceParser.replaceCommaByFinalPoint("1,00")).toEqual "1.00" + it "doesn't confuse with thousands separator", -> + expect(priceParser.replaceCommaByFinalPoint("1,000")).toEqual "1,000" + it "handle also when there is only one number after the decimal separator", -> + expect(priceParser.replaceCommaByFinalPoint("1,0")).toEqual "1.0" + describe "test removeThousandsSeparator() method", -> + it "handle the default case", -> + expect(priceParser.removeThousandsSeparator("1,000", ",")).toEqual "1000" + expect(priceParser.removeThousandsSeparator("1,000,000", ",")).toEqual "1000000" + it "handle the case with decimal separator", -> + expect(priceParser.removeThousandsSeparator("1,000,000.00", ",")).toEqual "1000000.00" + it "handle the case when it is actually a decimal separator (and not a thousands one)", -> + expect(priceParser.removeThousandsSeparator("1,00", ",")).toEqual "1,00" + + describe "with point as decimal separator and comma as thousands separator for I18n service", -> + + beforeEach -> + spyOn(I18n,'toCurrency').and.callFake (arg) -> + if (arg == 0.1) + return "0.1" + else if (arg == 1000) + return "1,000" + + it "handle point as decimal separator", -> + expect(priceParser.parse("1.00")).toEqual 1.0 + + it "handle point as decimal separator", -> + expect(priceParser.parse("1.000")).toEqual 1.0 + + it "also handle comma as decimal separator", -> + expect(priceParser.parse("1,0")).toEqual 1.0 + + it "also handle comma as decimal separator", -> + expect(priceParser.parse("1,00")).toEqual 1.0 + + it "also handle comma as decimal separator", -> + expect(priceParser.parse("11,00")).toEqual 11.0 + + it "handle comma as decimal separator but not confusing with thousands separator", -> + expect(priceParser.parse("11,000")).toEqual 11000 + + it "handle point as decimal separator and comma as thousands separator", -> + expect(priceParser.parse("1,000,000.00")).toEqual 1000000 + + it "handle integer number", -> + expect(priceParser.parse("10")).toEqual 10 + + it "handle integer number with comma as thousands separator", -> + expect(priceParser.parse("1,000")).toEqual 1000 + + it "handle integer number with no thousands separator", -> + expect(priceParser.parse("1000")).toEqual 1000 + + describe "with comma as decimal separator and final point as thousands separator for I18n service", -> + + beforeEach -> + spyOn(I18n,'toCurrency').and.callFake (arg) -> + if (arg == 0.1) + return "0,1" + else if (arg == 1000) + return "1.000" + + it "handle comma as decimal separator", -> + expect(priceParser.parse("1,00")).toEqual 1.0 + + it "handle comma as decimal separator with one digit after the comma", -> + expect(priceParser.parse("11,0")).toEqual 11.0 + + it "handle comma as decimal separator with two digit after the comma", -> + expect(priceParser.parse("11,00")).toEqual 11.0 + + it "handle comma as decimal separator with three digit after the comma", -> + expect(priceParser.parse("11,000")).toEqual 11.0 + + it "also handle point as decimal separator", -> + expect(priceParser.parse("1.00")).toEqual 1.0 + + it "also handle point as decimal separator with integer part with two digits", -> + expect(priceParser.parse("11.00")).toEqual 11.0 + + it "handle point as decimal separator and final point as thousands separator", -> + expect(priceParser.parse("1.000.000,00")).toEqual 1000000 + + it "handle integer number", -> + expect(priceParser.parse("10")).toEqual 10 + + it "handle integer number with final point as thousands separator", -> + expect(priceParser.parse("1.000")).toEqual 1000 + + it "handle integer number with no thousands separator", -> + expect(priceParser.parse("1000")).toEqual 1000 + + describe "with comma as decimal separator and space as thousands separator for I18n service", -> + + beforeEach -> + spyOn(I18n,'toCurrency').and.callFake (arg) -> + if (arg == 0.1) + return "0,1" + else if (arg == 1000) + return "1 000" + + it "handle comma as decimal separator", -> + expect(priceParser.parse("1,00")).toEqual 1.0 + + it "handle comma as decimal separator with one digit after the comma", -> + expect(priceParser.parse("11,0")).toEqual 11.0 + + it "handle comma as decimal separator with two digit after the comma", -> + expect(priceParser.parse("11,00")).toEqual 11.0 + + it "handle comma as decimal separator with three digit after the comma", -> + expect(priceParser.parse("11,000")).toEqual 11.0 + + it "also handle final point as decimal separator", -> + expect(priceParser.parse("1.00")).toEqual 1.0 + + it "also handle final point as decimal separator with integer part with two digits", -> + expect(priceParser.parse("11.00")).toEqual 11.0 + + it "handle point as decimal separator and space as thousands separator", -> + expect(priceParser.parse("1 000 000,00")).toEqual 1000000 + + it "handle integer number", -> + expect(priceParser.parse("10")).toEqual 10 + + it "handle integer number with space as thousands separator", -> + expect(priceParser.parse("1 000")).toEqual 1000 + + it "handle integer number with no thousands separator", -> + expect(priceParser.parse("1000")).toEqual 1000 + + describe "handle null/undefined case", -> + it "null case", -> + expect(priceParser.parse(null)).toEqual null + + it "undefined case ", -> + expect(priceParser.parse(undefined)).toEqual null + + it "wtf case", -> + expect(priceParser.parse("wtf")).toEqual null +