Skip to content

Commit e7fefc7

Browse files
committed
ACP2E-687: Wrong price displayed on configurable PDP after quantity is changed
1 parent 44f6a52 commit e7fefc7

File tree

4 files changed

+165
-91
lines changed

4 files changed

+165
-91
lines changed

app/code/Magento/ConfigurableProduct/view/frontend/web/js/configurable.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ define([
4848
tierPriceBlockSelector: '[data-role="tier-price-block"]',
4949
tierPriceTemplate: '',
5050
selectorProduct: '.product-info-main',
51-
selectorProductPrice: '[data-role=priceBox]'
51+
selectorProductPrice: '[data-role=priceBox]',
52+
qtyInfo: '#qty'
5253
},
5354

5455
/**
@@ -75,6 +76,7 @@ define([
7576
this._configureForValues();
7677

7778
$(this.element).trigger('configurable.initialized');
79+
$(this.options.qtyInfo).on('input', this._reloadPrice.bind(this));
7880
},
7981

8082
/**

app/code/Magento/Swatches/view/base/web/js/swatch-renderer.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ define([
280280
// tier prise selectors end
281281

282282
// A price label selector
283-
normalPriceLabelSelector: '.product-info-main .normal-price .price-label'
283+
normalPriceLabelSelector: '.product-info-main .normal-price .price-label',
284+
qtyInfo: '#qty'
284285
},
285286

286287
/**
@@ -369,6 +370,7 @@ define([
369370

370371
this.productForm = this.element.parents(this.options.selectorProductTile).find('form:first');
371372
this.inProductList = this.productForm.length > 0;
373+
$(this.options.qtyInfo).on('input', this._onQtyChanged.bind(this));
372374
},
373375

374376
/**
@@ -1450,6 +1452,21 @@ define([
14501452

14511453
this.options.mediaCache[JSON.stringify(mediaCallData)] = this.options.jsonConfig.preSelectedGallery;
14521454
}
1455+
},
1456+
1457+
/**
1458+
* Callback for quantity change event.
1459+
*/
1460+
_onQtyChanged: function () {
1461+
var $price = this.element.parents(this.options.selectorProduct)
1462+
.find(this.options.selectorProductPrice);
1463+
1464+
$price.trigger(
1465+
'updatePrice',
1466+
{
1467+
'prices': this._getPrices(this._getNewPrices(), $price.priceBox('option').prices)
1468+
}
1469+
);
14531470
}
14541471
});
14551472

dev/tests/js/jasmine/tests/app/code/Magento/ConfigurableProduct/view/frontend/js/configurable.test.js

Lines changed: 104 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -11,92 +11,102 @@ define([
1111
'use strict';
1212

1313
var widget,
14-
option = '<select name=\'super_attribute[93]\'' +
15-
'data-selector=\'super_attribute[93]\'' +
16-
'data-validate=\'{required:true}\'' +
17-
'id=\'attribute93\'' +
18-
'class=\'super-attribute-select\'>' +
19-
'<option value=\'\'></option>' +
20-
'</select>',
21-
selectElement = $(option);
22-
23-
beforeEach(function () {
24-
widget = new Configurable();
25-
widget.options = {
26-
settings: [
27-
{
28-
selectedIndex: 0,
29-
options: [
30-
{
31-
label: 'Chose an Option...'
32-
},
33-
{
34-
label: 'red',
35-
config: {
36-
id: '4',
37-
label: 'red',
38-
products: [
39-
'4'
40-
],
41-
initialLabel: 'red',
42-
allowedProducts: ['4']
43-
}
44-
}
45-
]
46-
}
47-
],
48-
priceHolderSelector: 'testSelector',
49-
spConfig: {
50-
chooseText: 'Chose an Option...',
51-
optionPrices: {
52-
4: {
53-
testPrice1: {
54-
amount: 40
55-
},
56-
testPrice2: {
57-
amount: 30
58-
}
14+
options = {
15+
'spConfig': {
16+
'attributes': {
17+
'93': {
18+
'id': '93',
19+
'code': 'color',
20+
'label': 'Color',
21+
'options': [
22+
{'id': '14', 'label': 'brown', 'products': ['2']},
23+
{'id': '15', 'label': 'beige', 'products': ['3']}
24+
],
25+
'position': '0'
5926
}
6027
},
61-
attributes:
62-
{
63-
'size': {
64-
options: [
65-
{
66-
id: '2',
67-
value: '2'
68-
},
69-
{
70-
id: 3,
71-
value: 'red'
72-
73-
}
74-
]
75-
}
28+
'template': '$<%- data.price %>',
29+
'currencyFormat': '$%s',
30+
'optionPrices': {
31+
'2': {
32+
'baseOldPrice': {'amount': 12},
33+
'oldPrice': {'amount': 12},
34+
'basePrice': {'amount': 12},
35+
'finalPrice': {'amount': 12},
36+
'tierPrices': [{'qty': 4, 'price': 8.4, 'percentage': 30, 'excl_tax_price': 8.4}],
37+
'msrpPrice': {'amount': 0}
7638
},
77-
prices: {
78-
finalPrice: {
79-
amount: 12
39+
'3': {
40+
'baseOldPrice': {'amount': 10},
41+
'oldPrice': {'amount': 10},
42+
'basePrice': {'amount': 10},
43+
'finalPrice': {'amount': 10},
44+
'tierPrices': [],
45+
'msrpPrice': {'amount': 0}
8046
}
81-
}
82-
},
83-
values: {}
84-
};
85-
});
47+
},
48+
'priceFormat': {
49+
'pattern': '$%s',
50+
'precision': 2,
51+
'requiredPrecision': 2,
52+
'decimalSymbol': '.',
53+
'groupSymbol': ',',
54+
'groupLength': 3,
55+
'integerRequired': false
56+
},
57+
'prices': {
58+
'baseOldPrice': {'amount': 10},
59+
'oldPrice': {'amount': 10},
60+
'basePrice': {'amount': 10},
61+
'finalPrice': {'amount': 10}
62+
},
63+
'productId': '4',
64+
'chooseText': 'Choose an Option...',
65+
'images': [],
66+
'index': { '2': {'93': '14'}, '3': {'93': '15'}},
67+
'salable': []
68+
}
69+
},
70+
blockHtml = '<form id="cart"/>'
71+
+ '<select name=\'super_attribute[93]\'' +
72+
' data-selector=\'super_attribute[93]\'' +
73+
' data-validate=\'{required:true}\'' +
74+
' id=\'attribute93\'' +
75+
' class=\'super-attribute-select\'>' +
76+
'<option value=\'\'>Choose an Option...</option>' +
77+
'<option value=\'14\'>brown +$2.00</option>' +
78+
'<option value=\'15\'>beige</option>' +
79+
'</select>' +
80+
'<input id="qty"/>' +
81+
'</form>',
82+
selectElement,
83+
qtyElement,
84+
formElement;
8685

8786
describe('Magento_ConfigurableProduct/js/configurable', function () {
88-
87+
beforeEach(function () {
88+
$(blockHtml).appendTo('body');
89+
selectElement = $('#attribute93');
90+
qtyElement = $('#qty');
91+
formElement = $('#cart');
92+
widget = new Configurable($.extend(true, {}, options), formElement);
93+
$.fn.trigFunc = $.fn.trigger;
94+
});
95+
afterEach(function () {
96+
formElement.remove();
97+
$.fn.trigger = $.fn.trigFunc;
98+
delete $.fn.trigFunc;
99+
});
89100
it('check if attribute value is possible to be set as configurable option', function () {
90101
expect($.mage.configurable).toBeDefined();
91-
widget._parseQueryParams('size=2');
92-
expect(widget.options.values.size).toBe('2');
102+
widget._parseQueryParams('93=14');
103+
expect(widget.options.values['93']).toBe('14');
93104
});
94105

95106
it('check that attribute value is not set if provided option does not exists', function () {
96107
expect($.mage.configurable).toBeDefined();
97-
widget._parseQueryParams('size=10');
98-
widget._fillSelect(selectElement[0]);
99-
expect(widget.options.values.size).toBe(undefined);
108+
widget._parseQueryParams('93=10');
109+
expect(widget.options.values['93']).toBe(undefined);
100110
});
101111

102112
it('check if widget will return correct price values in case option is selected or not.', function () {
@@ -105,23 +115,32 @@ define([
105115
spyOn($.fn, 'priceBox').and.callFake(function () {
106116
return {
107117
prices: {
108-
testPrice1: {
109-
amount: 10
110-
},
111-
testPrice2: {
112-
amount: 20
113-
}
118+
'baseOldPrice': {'amount': 10},
119+
'oldPrice': {'amount': 10},
120+
'basePrice': {'amount': 10},
121+
'finalPrice': {'amount': 10},
122+
'msrpPrice': {'amount': 0}
114123
}
115124
};
116125
});
117126
result = widget._getPrices().prices;
118-
expect(result.testPrice1.amount).toBe(0);
119-
expect(result.testPrice2.amount).toBe(0);
127+
expect(result.baseOldPrice.amount).toBe(0);
128+
expect(result.oldPrice.amount).toBe(0);
129+
expect(result.basePrice.amount).toBe(0);
130+
expect(result.finalPrice.amount).toBe(0);
120131

121-
widget.options.settings[0].selectedIndex = 1;
132+
selectElement.val(14);
122133
result = widget._getPrices().prices;
123-
expect(result.testPrice1.amount).toBe(30);
124-
expect(result.testPrice2.amount).toBe(10);
134+
expect(result.baseOldPrice.amount).toBe(2);
135+
expect(result.oldPrice.amount).toBe(2);
136+
expect(result.basePrice.amount).toBe(2);
137+
expect(result.finalPrice.amount).toBe(2);
138+
});
139+
140+
it('check that price is reloaded on qty change', function () {
141+
spyOn($.fn, 'trigger');
142+
qtyElement.trigFunc('input');
143+
expect($.fn.trigger).toHaveBeenCalledWith('updatePrice', {});
125144
});
126145
});
127146
});

dev/tests/js/jasmine/tests/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.test.js

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ define([
99
], function ($, SwatchRenderer) {
1010
'use strict';
1111

12-
describe('Testing "_RenderSwatchOptions" method of SwatchRenderer Widget', function () {
12+
describe('Magento_Swatches/js/swatch-renderer.js', function () {
1313
var widget,
1414
html,
1515
optionConfig,
@@ -18,18 +18,26 @@ define([
1818
swathImageHeight = '60',
1919
swathImageWidth = '70',
2020
swathThumbImageHeight = '40',
21-
swathThumbImageWidth = '50';
21+
swathThumbImageWidth = '50',
22+
options,
23+
blockHtml = '<form id="cart"/>' +
24+
'<input id="qty"/>' +
25+
'</form>',
26+
qtyElement,
27+
formElement;
2228

2329
beforeEach(function () {
24-
widget = new SwatchRenderer();
30+
$(blockHtml).appendTo('body');
31+
qtyElement = $('#qty');
32+
formElement = $('#cart');
2533
attribute = {
2634
id: 1,
2735
options: [{
2836
id: optionId
2937
}]
3038
};
3139

32-
widget.options = {
40+
options = {
3341
classes: {
3442
optionClass: 'swatch-option'
3543
},
@@ -52,10 +60,16 @@ define([
5260
}
5361
};
5462

63+
widget = new SwatchRenderer(options);
64+
5565
optionConfig = widget.options.jsonSwatchConfig[attribute.id];
5666
html = $(widget._RenderSwatchOptions(attribute, 'option-label-control-id-1'))[0];
5767
});
5868

69+
afterEach(function () {
70+
formElement.remove();
71+
});
72+
5973
it('check if swatch config has attribute id', function () {
6074
expect(widget.options.jsonSwatchConfig.hasOwnProperty(attribute.id)).toEqual(true);
6175
});
@@ -130,5 +144,27 @@ define([
130144

131145
expect(widget._getSelectedOptionPriceIndex()).toBe('p');
132146
});
147+
148+
it('check that price is reloaded on qty change', function () {
149+
var priceBox = {
150+
hide: jasmine.createSpy(),
151+
priceBox: jasmine.createSpy().and.returnValue({ prices: {}}),
152+
trigger: jasmine.createSpy(),
153+
find: jasmine.createSpy().and.returnValue({
154+
toggleClass: jasmine.createSpy()
155+
})
156+
},
157+
productPriceMock = {
158+
find: jasmine.createSpy().and.returnValue(priceBox)
159+
};
160+
161+
widget.element = {
162+
parents: jasmine.createSpy().and.returnValue(productPriceMock)
163+
};
164+
widget._getNewPrices = jasmine.createSpy().and.returnValue({});
165+
widget._getPrices = jasmine.createSpy().and.returnValue({});
166+
qtyElement.trigger('input');
167+
expect(priceBox.trigger).toHaveBeenCalledWith('updatePrice', { prices: {}});
168+
});
133169
});
134170
});

0 commit comments

Comments
 (0)