Skip to content

Commit

Permalink
BB-17102: Impossible to buy a product with fractional quantity for lo…
Browse files Browse the repository at this point in the history
…calizations that use comma as a decimal separator (#24762)

- change DecimalValidator to support float values
- improve UnitValueFormatter to format decimal value according to current localization
- change prices-helper to support localized decimal quantity
- format decimal quantity in views
- fix inventory level inline editing for localized decimal support
- change subscriber event to operate transformed quantity value
- fix precision of quantity field on frontend edit quote form
- fix QuoteFormSubscriber handling of empty price
- fix QuoteFormSubscriber handling of newly created offer
- fix number.js input widget to handle empty value
- introduct custom events in number input widget to guarantee that they are handled after input value normalization
- fix number formatting for quantity field
- fix QuoteFormSubscriber dependencies
- fix UnitValueFormatter dependencies
- fix product-with-fractional-quantity behat fixture
- change UnitValueFormatter to operate formatted value
- move logic from elements-helper.js into base-product-view.js
- fix decimal separator in quantity input issue on admin order and quote creation forms
- pass not formatted value into UnitValueFormatter
- fix base-product-view elementEvent naming
- revert price-helper.js changes
- improve behat test coverage
- fixes in setPrecision for loaded units data
- fixed update product quantity in shopping list.
- fixed prices displaying on Quick Order Form when quantity with fractional value used.
- fixed quote create in admin area
- fixed prices in RFQ on the frontend area
- fixed fractional quantity usage on Quote Create form
- fix excessive complexity
- remove not used functionality
- fix frontend quote type
- fix quick order prices
- fieed QOF EE behat test
  • Loading branch information
aalgogiver authored Sep 24, 2020
1 parent 4771360 commit eee9924
Show file tree
Hide file tree
Showing 85 changed files with 1,963 additions and 717 deletions.
5 changes: 5 additions & 0 deletions src/Oro/Bundle/ApplicationBundle/Tests/Behat/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ oro_behat_extension:
type: 'css'
locator: "input[name='product_qty']"

ShoppingListLineItemForm > Unit:
selector:
type: 'css'
locator: "input[name='product_unit']"

Shopping List Label:
selector:
locator: '//input[@type="text" and @name="value"]'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@
{% if oro_is_unit_code_visible(lineItem.productUnit.code) %}
{{ quantity ? quantity|oro_format_short_product_unit_value(lineItem.productUnit) : 'N/A'|trans }}
{% else %}
{{ quantity }}
{{ quantity|oro_format_decimal }}
{% endif %}
{% endblock %}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ app-modules:
- oroinventory/js/app/modules/validator-constraints-module
dynamic-imports:
oroinventory:
- oroinventory/js/app/views/decimals-number-editor-view
- oroinventory/js/app/views/quantity-editor-view
- oroinventory/js/datagrid/builder/inventory-status-builder
- oroinventory/js/datagrid/builder/level-quantity-builder
oroform-validate:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,13 @@ datagrids:
inline_editing:
enable: true
editor:
view: oroinventory/js/app/views/decimals-number-editor-view
view: oroinventory/js/app/views/quantity-editor-view
view_options:
decimalsField: inventoryLevelPrecision
validation_rules:
DecimalsNumber:
decimalsField: inventoryLevelPrecision
validation_groups: [Default]
unit:
label: oro.product.productunitprecision.unit.label
type: twig
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ define(function(require) {
'use strict';

const NumberEditorView = require('oroform/js/app/views/editor/number-editor-view');
/** @var QuantityHelper QuantityHelper **/
const QuantityHelper = require('oroproduct/js/app/quantity-helper');

const DecimalsNumberEditorView = NumberEditorView.extend(/** @lends DecimalsNumberEditorView.prototype */{
className: 'decimals-number-editor',
numberOfDecimals: null,

/**
* @inheritDoc
Expand All @@ -26,10 +29,32 @@ define(function(require) {
if (typeof decimalsNumberValidator.decimalsField !== 'undefined') {
const numberOfDecimals = parseInt(options.model.get(decimalsNumberValidator.decimalsField));
decimalsNumberValidator.decimals = numberOfDecimals;
this.numberOfDecimals = numberOfDecimals;
}
}

DecimalsNumberEditorView.__super__.initialize.call(this, options);
},
formatRawValue: function(value) {
return QuantityHelper.formatQuantity(value, this.numberOfDecimals, true, true);
},

parseRawValue: function(value) {
return QuantityHelper.getQuantityNumberOrDefaultValue(value, NaN);
},

getValue: function() {
const userInput = this.$('input[name=value]').val();
if (userInput === '') {
return 0;
}

const parsed = this.parseRawValue(userInput);
if (parsed === false) {
return NaN;
}

return parsed;
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Abstract Form type for order line item
*/
abstract class AbstractOrderLineItemType extends AbstractType
{
/**
Expand Down Expand Up @@ -77,7 +80,6 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'required' => true,
'label' => 'oro.order.orderlineitem.quantity.label',
'default_data' => 1,
'product_holder' => $builder->getData()
]
)
->add(
Expand Down
3 changes: 3 additions & 0 deletions src/Oro/Bundle/OrderBundle/Resources/config/oro/datagrids.yml
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ datagrids:
totalDiscountsAmount:
type: number
data_name: order1.totalDiscountsAmount
options:
data_type: Oro\Bundle\FilterBundle\Form\Type\Filter\NumberFilterType::DATA_DECIMAL
createdAt:
type: datetime
data_name: order1.createdAt
Expand Down Expand Up @@ -662,6 +664,7 @@ datagrids:
template: OroOrderBundle:Order:Datagrid/product.html.twig
quantity:
label: oro.order.orderlineitem.quantity.label
frontend_type: decimal
productUnitCode:
label: oro.order.orderlineitem.product_unit_code.label
price:
Expand Down
2 changes: 2 additions & 0 deletions src/Oro/Bundle/OrderBundle/Resources/config/validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ Oro\Bundle\OrderBundle\Entity\Order:
Oro\Bundle\OrderBundle\Entity\OrderLineItem:
constraints:
- Oro\Bundle\OrderBundle\Validator\Constraints\LineItemProduct: ~
- Oro\Bundle\ProductBundle\Validator\Constraints\QuantityUnitPrecision:
path: quantity
properties:
order:
- NotBlank: ~
Expand Down
3 changes: 3 additions & 0 deletions src/Oro/Bundle/OrderBundle/Tests/Behat/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ oro_behat_extension:
type: 'css'
locator: 'input[name^="oro_order_type_shipUntil"]'

Order Form Line Item 1 Offer 1:
selector: '[name="oro_order_type[lineItems][0][offers]"]'

First Product Quantity Field In Order:
selector:
locator: '//input[@name="oro_order_type[lineItems][0][quantity]"]'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Validator\Constraints\Valid;

/**
* Adds field 'prices' on product edit form and process changes of product prices
Expand Down Expand Up @@ -124,6 +125,8 @@ protected function addForm(FormInterface $form, Product $product = null, $allowA
'mapped' => false,
'constraints' => [
new UniqueProductPrices(['groups' => [ProductPriceCollectionType::VALIDATION_GROUP]]),
// Valid constraint added to allow cascade validation of the prices on the backend
new Valid(['groups' => [ProductPriceCollectionType::VALIDATION_GROUP]])
],
'entry_options' => [
'product' => $product,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* Form type for product price
*/
class PriceListProductPriceType extends AbstractType
{
const NAME = 'oro_pricing_price_list_product_price';
Expand Down Expand Up @@ -62,9 +65,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
QuantityType::class,
[
'required' => true,
'label' => 'oro.pricing.productprice.quantity.label',
'product_holder' => $data,
'product_unit_field' => 'unit'
'label' => 'oro.pricing.productprice.quantity.label'
]
)
->add(
Expand Down
4 changes: 1 addition & 3 deletions src/Oro/Bundle/PricingBundle/Form/Type/ProductPriceType.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'quantity',
QuantityType::class,
[
'label' => 'oro.pricing.quantity.label',
'product' => $options['product'],
'product_unit_field' => 'unit',
'label' => 'oro.pricing.quantity.label'
]
);

Expand Down
3 changes: 3 additions & 0 deletions src/Oro/Bundle/PricingBundle/Resources/config/validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ Oro\Bundle\PricingBundle\Entity\ProductPrice:
- Oro\Bundle\PricingBundle\Validator\Constraints\UniqueEntity:
groups: [Default]
fields: [ product, priceList, quantity, unit, currency ]
- Oro\Bundle\ProductBundle\Validator\Constraints\QuantityUnitPrecision:
path: quantity
groups: [Default, ProductPriceCollection]
properties:
product:
- NotBlank:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ define(function(require) {

let items = _.filter(this.items);
if (_.isEmpty(items)) {
items = this.noDataTemplate();
items = [this.noDataTemplate()];
}

this.$totals.html(items.join(''));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,10 @@ define(function(require) {
showSubtotalPlaceholder: data.item.unit !== data.item.unit_placeholder
});
} else {
const quantity = this.model.get('quantity') || this.options.defaultQuantity;

this.model.set({
quantity: this.model.get('quantity') || this.options.defaultQuantity,
quantity: quantity,
quantity_changed_manually: this.model.get('quantity'),
units: data.item.units,
product_units: data.item.units,
Expand All @@ -102,17 +104,13 @@ define(function(require) {
}
},

onUnitChange: function() {
this.setFoundPrice(true);
},

checkEl: function($el) {
return $el !== undefined &&
this.$el.closest('.quick-order-add__row').attr('id') ===
$el.closest('.quick-order-add__row').attr('id');
},

updateSubtotal: function() {
updateSubtotal: function(e) {
this.model.set('subtotal', this.getSubtotal());
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ProductWithPricesTest extends WebTestCase
const SECOND_UNIT_PRECISION = 3;

const FIRST_QUANTITY = 10;
const SECOND_QUANTITY = 5.555556;
const SECOND_QUANTITY = 5.556;
const EXPECTED_SECOND_QUANTITY = 5.556;

const FIRST_PRICE_VALUE = 10;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Validator\Constraints\Valid;

/**
* @SuppressWarnings(PHPMD.TooManyMethods)
Expand Down Expand Up @@ -411,7 +412,8 @@ public function testAddFormOnPreSetDataAndNewProduct()
'required' => false,
'mapped' => false,
'constraints' => [
new UniqueProductPrices(['groups' => ProductPriceCollectionType::VALIDATION_GROUP])
new UniqueProductPrices(['groups' => ProductPriceCollectionType::VALIDATION_GROUP]),
new Valid(['groups' => ProductPriceCollectionType::VALIDATION_GROUP])
],
'entry_options' => [
'product' => $product,
Expand Down Expand Up @@ -515,7 +517,8 @@ public function testAddFormOnPreSetDataAndFieldAddedAndUpdateProduct(
'required' => false,
'mapped' => false,
'constraints' => [
new UniqueProductPrices(['groups' => ProductPriceCollectionType::VALIDATION_GROUP])
new UniqueProductPrices(['groups' => ProductPriceCollectionType::VALIDATION_GROUP]),
new Valid(['groups' => ProductPriceCollectionType::VALIDATION_GROUP])
],
'entry_options' => [
'product' => $product,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,8 @@ protected function getExtensions()
public function testSubmit(
ProductPrice $defaultData,
array $submittedData,
ProductPrice $expectedData,
$rounding = false
ProductPrice $expectedData
) {
if ($rounding) {
$this->addRoundingServiceExpect();
}

$form = $this->factory->create(PriceListProductPriceType::class, $defaultData, []);

// unit placeholder must not be available for specific entity
Expand Down Expand Up @@ -181,7 +176,7 @@ public function submitProvider()

$expectedProductPrice2 = clone $expectedProductPrice;
$expectedProductPrice2
->setQuantity(123.556)
->setQuantity(123.5555)
->setPrice($expectedPrice2);

$defaultProductPrice = new ProductPrice();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ public function testSubmit(
$locale = 'en'
) {
\Locale::setDefault($locale);
$this->addRoundingServiceExpect();
$form = $this->factory->create(ProductPriceType::class, $defaultData, []);

$this->assertEquals($defaultData, $form->getData());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Oro\Bundle\ProductBundle\Form\DataTransformer;

use Oro\Bundle\LocaleBundle\Formatter\NumberFormatter;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

/**
* Specific transformer for product unit quantity. Helps to parse float in the correct localization.
* We could not reuse \Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer
* because it could not work normally with grouping symbols in 'es' locale
*/
class QuantityTransformer implements DataTransformerInterface
{
/**
* @var NumberFormatter
*/
private $numberFormatter;

/**
* @var bool
*/
private $skipTransformation;

/**
* @param NumberFormatter $formatter
* @param bool $skipTransformation
*/
public function __construct(NumberFormatter $formatter, bool $skipTransformation = false)
{
$this->numberFormatter = $formatter;
$this->skipTransformation = $skipTransformation;
}

/**
* {@inheritdoc}
*/
public function transform($value)
{
if ($this->skipTransformation) {
return $value;
}

$formattedValue = $this->numberFormatter->formatDecimal(
$value,
[
\NumberFormatter::GROUPING_USED => false
]
);

return $formattedValue;
}

/**
* {@inheritdoc}
*/
public function reverseTransform($value)
{
if ($value === '') {
return null;
}

$parsedValue = $this->numberFormatter->parseFormattedDecimal($value);
if ($parsedValue === false) {
throw new TransformationFailedException(
sprintf('Quantity %s is not a valid decimal number', $value)
);
}

return $parsedValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'attr' => [
'placeholder' => 'oro.product.lineitem.quantity.placeholder',
],
'product_holder' => $builder->getData(),
'product_unit_field' => 'unit',
'grouping' => true,
'useInputTypeNumberValueFormat' => true
]
);
}
Expand Down
Loading

0 comments on commit eee9924

Please sign in to comment.