Skip to content

Commit 0ccdb85

Browse files
authored
Merge pull request #1543 from magento-tsg/2.1-develop-pr32
[TSG] Backporting for 2.1 (pr32) (2.1.10)
2 parents 2a8b266 + fb4668f commit 0ccdb85

File tree

79 files changed

+3282
-441
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+3282
-441
lines changed

app/code/Magento/Bundle/Test/Unit/Pricing/Price/BundleSelectionPriceTest.php

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -306,58 +306,6 @@ public function testGetValueTypeFixedWithoutSelectionPriceType($useRegularPrice)
306306
$this->assertEquals($expectedPrice, $this->selectionPrice->getValue());
307307
}
308308

309-
/**
310-
* Test for method getValue with type Fixed and selectionPriceType is empty or zero.
311-
*
312-
* @param bool $useRegularPrice
313-
* @return void
314-
*
315-
* @dataProvider useRegularPriceDataProvider
316-
*/
317-
public function testFixedPriceWithMultipleQty($useRegularPrice)
318-
{
319-
$qty = 2;
320-
321-
$this->setupSelectionPrice($useRegularPrice, $qty);
322-
$regularPrice = 100.125;
323-
$discountedPrice = 70.453;
324-
$convertedValue = 100.247;
325-
$actualPrice = $useRegularPrice ? $convertedValue : $discountedPrice;
326-
$expectedPrice = $useRegularPrice ? round($convertedValue, 2) : round($discountedPrice, 2);
327-
328-
$this->bundleMock->expects($this->once())
329-
->method('getPriceType')
330-
->will($this->returnValue(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED));
331-
$this->productMock->expects($this->once())
332-
->method('getSelectionPriceType')
333-
->will($this->returnValue(false));
334-
$this->productMock->expects($this->any())
335-
->method('getSelectionPriceValue')
336-
->will($this->returnValue($regularPrice));
337-
338-
$this->priceCurrencyMock->expects($this->once())
339-
->method('convert')
340-
->with($regularPrice)
341-
->will($this->returnValue($convertedValue));
342-
343-
if (!$useRegularPrice) {
344-
$this->discountCalculatorMock->expects($this->once())
345-
->method('calculateDiscount')
346-
->with(
347-
$this->equalTo($this->bundleMock),
348-
$this->equalTo($convertedValue)
349-
)
350-
->will($this->returnValue($discountedPrice));
351-
}
352-
353-
$this->priceCurrencyMock->expects($this->once())
354-
->method('round')
355-
->with($actualPrice)
356-
->will($this->returnValue($expectedPrice));
357-
358-
$this->assertEquals($expectedPrice, $this->selectionPrice->getValue());
359-
}
360-
361309
public function useRegularPriceDataProvider()
362310
{
363311
return [
@@ -425,4 +373,56 @@ public function testGetAmount()
425373

426374
$this->assertEquals($amount, $this->selectionPrice->getAmount());
427375
}
376+
377+
/**
378+
* Test for method getValue with type Fixed and selectionPriceType is empty or zero.
379+
*
380+
* @param bool $useRegularPrice
381+
* @return void
382+
*
383+
* @dataProvider useRegularPriceDataProvider
384+
*/
385+
public function testFixedPriceWithMultipleQty($useRegularPrice)
386+
{
387+
$qty = 2;
388+
389+
$this->setupSelectionPrice($useRegularPrice, $qty);
390+
$regularPrice = 100.125;
391+
$discountedPrice = 70.453;
392+
$convertedValue = 100.247;
393+
$actualPrice = $useRegularPrice ? $convertedValue : $discountedPrice;
394+
$expectedPrice = $useRegularPrice ? round($convertedValue, 2) : round($discountedPrice, 2);
395+
396+
$this->bundleMock->expects($this->once())
397+
->method('getPriceType')
398+
->will($this->returnValue(\Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED));
399+
$this->productMock->expects($this->once())
400+
->method('getSelectionPriceType')
401+
->will($this->returnValue(false));
402+
$this->productMock->expects($this->any())
403+
->method('getSelectionPriceValue')
404+
->will($this->returnValue($regularPrice));
405+
406+
$this->priceCurrencyMock->expects($this->once())
407+
->method('convert')
408+
->with($regularPrice)
409+
->will($this->returnValue($convertedValue));
410+
411+
if (!$useRegularPrice) {
412+
$this->discountCalculatorMock->expects($this->once())
413+
->method('calculateDiscount')
414+
->with(
415+
$this->equalTo($this->bundleMock),
416+
$this->equalTo($convertedValue)
417+
)
418+
->will($this->returnValue($discountedPrice));
419+
}
420+
421+
$this->priceCurrencyMock->expects($this->once())
422+
->method('round')
423+
->with($actualPrice)
424+
->will($this->returnValue($expectedPrice));
425+
426+
$this->assertEquals($expectedPrice, $this->selectionPrice->getValue());
427+
}
428428
}

app/code/Magento/Bundle/view/base/web/js/price-bundle.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ define([
5555
this._setOption('priceFormat', priceBox.priceBox('option').priceConfig.priceFormat);
5656
priceBox.priceBox('setDefault', this.options.optionConfig.prices);
5757
}
58+
5859
this._applyOptionNodeFix(options);
5960

6061
options.on('change', this._onBundleOptionChanged.bind(this));

app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ public function __construct(
171171
*/
172172
protected function parseSelections($rowData, $entityId)
173173
{
174+
if (empty($rowData['bundle_values'])) {
175+
return [];
176+
}
177+
174178
$rowData['bundle_values'] = str_replace(
175179
self::BEFORE_OPTION_VALUE_DELIMITER,
176180
$this->_entityModel->getMultipleValueSeparator(),

app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,11 @@ public function testSaveDataProvider()
309309
'bunch' => ['bundle_values' => 'value1', 'sku' => 'sku', 'name' => 'name'],
310310
'allowImport' => false
311311
],
312+
'Import without bundle values' => [
313+
'skus' => ['newSku' => ['sku' => ['sku' => 'sku', 'entity_id' => 3, 'type_id' => 'bundle']]],
314+
'bunch' => ['sku' => 'sku', 'name' => 'name'],
315+
'allowImport' => true,
316+
],
312317
[
313318
'skus' => ['newSku' => [
314319
'sku' => ['sku' => 'sku', 'entity_id' => 3, 'type_id' => 'bundle'],

app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ class Helper
7474
* @var \Magento\Framework\Stdlib\DateTime\Filter\DateTime
7575
*/
7676
private $dateTimeFilter;
77+
78+
/**
79+
* @var \Magento\Catalog\Model\Product\LinkTypeProvider
80+
*/
81+
private $linkTypeProvider;
7782

7883
/**
7984
* Helper constructor.
@@ -83,21 +88,25 @@ class Helper
8388
* @param ProductLinks $productLinks
8489
* @param \Magento\Backend\Helper\Js $jsHelper
8590
* @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
91+
* @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
8692
*/
8793
public function __construct(
8894
\Magento\Framework\App\RequestInterface $request,
8995
\Magento\Store\Model\StoreManagerInterface $storeManager,
9096
StockDataFilter $stockFilter,
9197
\Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks $productLinks,
9298
\Magento\Backend\Helper\Js $jsHelper,
93-
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter
99+
\Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter,
100+
\Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider = null
94101
) {
95102
$this->request = $request;
96103
$this->storeManager = $storeManager;
97104
$this->stockFilter = $stockFilter;
98105
$this->productLinks = $productLinks;
99106
$this->jsHelper = $jsHelper;
100107
$this->dateFilter = $dateFilter;
108+
$this->linkTypeProvider = $linkTypeProvider ?: \Magento\Framework\App\ObjectManager::getInstance()
109+
->get(\Magento\Catalog\Model\Product\LinkTypeProvider::class);
101110
}
102111

103112
/**
@@ -199,14 +208,18 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra
199208
$customOptions = [];
200209
foreach ($options as $customOptionData) {
201210
if (empty($customOptionData['is_delete'])) {
211+
if (empty($customOptionData['option_id'])) {
212+
$customOptionData['option_id'] = null;
213+
}
214+
202215
if (isset($customOptionData['values'])) {
203216
$customOptionData['values'] = array_filter($customOptionData['values'], function ($valueData) {
204217
return empty($valueData['is_delete']);
205218
});
206219
}
220+
207221
$customOption = $this->getCustomOptionFactory()->create(['data' => $customOptionData]);
208222
$customOption->setProductSku($product->getSku());
209-
$customOption->setOptionId(null);
210223
$customOptions[] = $customOption;
211224
}
212225
}
@@ -247,11 +260,17 @@ protected function setProductLinks(\Magento\Catalog\Model\Product $product)
247260

248261
$product = $this->productLinks->initializeLinks($product, $links);
249262
$productLinks = $product->getProductLinks();
250-
$linkTypes = [
251-
'related' => $product->getRelatedReadonly(),
252-
'upsell' => $product->getUpsellReadonly(),
253-
'crosssell' => $product->getCrosssellReadonly()
254-
];
263+
$linkTypes = [];
264+
265+
/** @var \Magento\Catalog\Api\Data\ProductLinkTypeInterface $linkTypeObject */
266+
foreach ($this->linkTypeProvider->getItems() as $linkTypeObject) {
267+
$linkTypes[$linkTypeObject->getName()] = $product->getData($linkTypeObject->getName() . '_readonly');
268+
}
269+
270+
// skip linkTypes that were already processed on initializeLinks plugins
271+
foreach ($productLinks as $productLink) {
272+
unset($linkTypes[$productLink->getLinkType()]);
273+
}
255274

256275
foreach ($linkTypes as $linkType => $readonly) {
257276
if (isset($links[$linkType]) && !$readonly) {
@@ -315,21 +334,58 @@ public function mergeProductOptions($productOptions, $overwriteOptions)
315334
return $productOptions;
316335
}
317336

318-
foreach ($productOptions as $index => $option) {
337+
foreach ($productOptions as $optionIndex => $option) {
319338
$optionId = $option['option_id'];
339+
$option = $this->overwriteValue(
340+
$optionId,
341+
$option,
342+
$overwriteOptions
343+
);
320344

321-
if (!isset($overwriteOptions[$optionId])) {
322-
continue;
345+
if (isset($option['values']) && isset($overwriteOptions[$optionId]['values'])) {
346+
foreach ($option['values'] as $valueIndex => $value) {
347+
if (isset($value['option_type_id'])) {
348+
$valueId = $value['option_type_id'];
349+
$value = $this->overwriteValue(
350+
$valueId,
351+
$value,
352+
$overwriteOptions[$optionId]['values']
353+
);
354+
355+
$option['values'][$valueIndex] = $value;
356+
}
357+
}
323358
}
324359

360+
$productOptions[$optionIndex] = $option;
361+
}
362+
363+
return $productOptions;
364+
}
365+
366+
/**
367+
* Overwrite values of fields to default, if there are option id and field name in array overwriteOptions.
368+
*
369+
* @param int $optionId
370+
* @param array $option
371+
* @param array $overwriteOptions
372+
*
373+
* @return array
374+
*/
375+
private function overwriteValue($optionId, $option, $overwriteOptions)
376+
{
377+
if (isset($overwriteOptions[$optionId])) {
325378
foreach ($overwriteOptions[$optionId] as $fieldName => $overwrite) {
326379
if ($overwrite && isset($option[$fieldName]) && isset($option['default_' . $fieldName])) {
327-
$productOptions[$index][$fieldName] = $option['default_' . $fieldName];
380+
$option[$fieldName] = $option['default_' . $fieldName];
381+
if ('title' == $fieldName) {
382+
$option['is_delete_store_title'] = 1;
383+
}
328384
}
329385
}
330386
}
331387

332-
return $productOptions;
388+
return $option;
333389
}
334390

335391
/**
@@ -339,8 +395,9 @@ private function getCustomOptionFactory()
339395
{
340396
if (null === $this->customOptionFactory) {
341397
$this->customOptionFactory = \Magento\Framework\App\ObjectManager::getInstance()
342-
->get('Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory');
398+
->get(\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory::class);
343399
}
400+
344401
return $this->customOptionFactory;
345402
}
346403

@@ -351,8 +408,9 @@ private function getProductLinkFactory()
351408
{
352409
if (null === $this->productLinkFactory) {
353410
$this->productLinkFactory = \Magento\Framework\App\ObjectManager::getInstance()
354-
->get('Magento\Catalog\Api\Data\ProductLinkInterfaceFactory');
411+
->get(\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory::class);
355412
}
413+
356414
return $this->productLinkFactory;
357415
}
358416

@@ -363,8 +421,9 @@ private function getProductRepository()
363421
{
364422
if (null === $this->productRepository) {
365423
$this->productRepository = \Magento\Framework\App\ObjectManager::getInstance()
366-
->get('Magento\Catalog\Api\ProductRepositoryInterface\Proxy');
424+
->get(\Magento\Catalog\Api\ProductRepositoryInterface\Proxy::class);
367425
}
426+
368427
return $this->productRepository;
369428
}
370429

@@ -377,6 +436,7 @@ private function getLinkResolver()
377436
if (!is_object($this->linkResolver)) {
378437
$this->linkResolver = ObjectManager::getInstance()->get(LinkResolver::class);
379438
}
439+
380440
return $this->linkResolver;
381441
}
382442

@@ -391,6 +451,7 @@ private function getDateTimeFilter()
391451
$this->dateTimeFilter = \Magento\Framework\App\ObjectManager::getInstance()
392452
->get(\Magento\Framework\Stdlib\DateTime\Filter\DateTime::class);
393453
}
454+
394455
return $this->dateTimeFilter;
395456
}
396457
}

0 commit comments

Comments
 (0)