Skip to content

Commit eff5524

Browse files
authored
Merge pull request #5855 from magento-tango/PR-03-07-2020
[tango] MC-35097: An invoiced order of a product with a Customizable Option (file) can not be reordered
2 parents c8f56e8 + b8c7b86 commit eff5524

File tree

26 files changed

+710
-98
lines changed

26 files changed

+710
-98
lines changed

app/code/Magento/Bundle/Test/Unit/Model/Product/TypeTest.php

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Bundle\Test\Unit\Model\Product;
77

88
use Magento\Bundle\Model\ResourceModel\Option\Collection;
9+
use Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor;
910
use Magento\Bundle\Model\ResourceModel\Selection\Collection as SelectionCollection;
1011
use Magento\Bundle\Model\Selection;
1112
use Magento\Catalog\Model\Product;
@@ -18,7 +19,7 @@
1819
use Magento\Framework\Stdlib\ArrayUtils;
1920

2021
/**
21-
* Class TypeTest
22+
* Test for bundle product type
2223
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
2324
*/
2425
class TypeTest extends \PHPUnit\Framework\TestCase
@@ -93,6 +94,11 @@ class TypeTest extends \PHPUnit\Framework\TestCase
9394
*/
9495
private $arrayUtility;
9596

97+
/**
98+
* @var |\PHPUnit_Framework_MockObject_MockObject
99+
*/
100+
private $catalogRuleProcessor;
101+
96102
/**
97103
* @return void
98104
*/
@@ -150,9 +156,7 @@ protected function setUp()
150156
->disableOriginalConstructor()
151157
->getMock();
152158

153-
$this->catalogRuleProcessor = $this->getMockBuilder(
154-
\Magento\CatalogRule\Model\ResourceModel\Product\CollectionProcessor::class
155-
)
159+
$this->catalogRuleProcessor = $this->getMockBuilder(CollectionProcessor::class)
156160
->disableOriginalConstructor()
157161
->getMock();
158162

@@ -1525,7 +1529,7 @@ public function testPrepareForCartAdvancedSpecifyProductOptions()
15251529

15261530
$this->parentClass($group, $option, $buyRequest, $product);
15271531

1528-
$product->expects($this->once())
1532+
$product->expects($this->any())
15291533
->method('getSkipCheckRequiredOption')
15301534
->willReturn(true);
15311535
$buyRequest->expects($this->once())
@@ -2404,9 +2408,6 @@ protected function parentClass($group, $option, $buyRequest, $product)
24042408
$group->expects($this->once())
24052409
->method('setProcessMode')
24062410
->willReturnSelf();
2407-
$group->expects($this->once())
2408-
->method('validateUserValue')
2409-
->willReturnSelf();
24102411
$group->expects($this->once())
24112412
->method('prepareForCart')
24122413
->willReturn('someString');

app/code/Magento/Catalog/Model/Indexer/Product/Price/AbstractAction.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,14 +368,20 @@ protected function _reindexRows($changedIds = [])
368368
$productsTypes = $this->getProductsTypes($changedIds);
369369
$parentProductsTypes = $this->getParentProductsTypes($changedIds);
370370

371-
$changedIds = array_merge($changedIds, ...array_values($parentProductsTypes));
371+
$changedIds = array_unique(array_merge($changedIds, ...array_values($parentProductsTypes)));
372372
$productsTypes = array_merge_recursive($productsTypes, $parentProductsTypes);
373373

374374
if ($changedIds) {
375375
$this->deleteIndexData($changedIds);
376376
}
377-
foreach ($productsTypes as $productType => $entityIds) {
378-
$indexer = $this->_getIndexer($productType);
377+
378+
$typeIndexers = $this->getTypeIndexers();
379+
foreach ($typeIndexers as $productType => $indexer) {
380+
$entityIds = $productsTypes[$productType] ?? [];
381+
if (empty($entityIds)) {
382+
continue;
383+
}
384+
379385
if ($indexer instanceof DimensionalIndexerInterface) {
380386
foreach ($this->dimensionCollectionFactory->create() as $dimensions) {
381387
$this->tableMaintainer->createMainTmpTable($dimensions);

app/code/Magento/Catalog/Model/Plugin/SetPageLayoutDefaultValue.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
namespace Magento\Catalog\Model\Plugin;
1212

1313
use Magento\Catalog\Model\Category\DataProvider;
14+
use Magento\Framework\App\Config\ScopeConfigInterface;
1415
use Magento\Framework\Exception\NoSuchEntityException;
16+
use Magento\Store\Model\ScopeInterface;
17+
use Magento\Store\Model\StoreManagerInterface;
1518

1619
/**
1720
* Sets the default value for Category Design Layout if provided
@@ -21,11 +24,28 @@ class SetPageLayoutDefaultValue
2124
private $defaultValue;
2225

2326
/**
27+
* @var StoreManagerInterface
28+
*/
29+
private $storeManager;
30+
31+
/**
32+
* @var ScopeConfigInterface
33+
*/
34+
private $scopeConfig;
35+
36+
/**
37+
* @param ScopeConfigInterface $scopeConfig
38+
* @param StoreManagerInterface $storeManager
2439
* @param string $defaultValue
2540
*/
26-
public function __construct(string $defaultValue = "")
27-
{
41+
public function __construct(
42+
ScopeConfigInterface $scopeConfig,
43+
StoreManagerInterface $storeManager,
44+
string $defaultValue = ""
45+
) {
2846
$this->defaultValue = $defaultValue;
47+
$this->scopeConfig = $scopeConfig;
48+
$this->storeManager = $storeManager;
2949
}
3050

3151
/**
@@ -42,7 +62,15 @@ public function afterGetDefaultMetaData(DataProvider $subject, array $result): a
4262
$currentCategory = $subject->getCurrentCategory();
4363

4464
if ($currentCategory && !$currentCategory->getId() && array_key_exists('page_layout', $result)) {
45-
$result['page_layout']['default'] = $this->defaultValue ?: null;
65+
$defaultAdminValue = $this->scopeConfig->getValue(
66+
'web/default_layouts/default_category_layout',
67+
ScopeInterface::SCOPE_STORE,
68+
$this->storeManager->getStore()->getId()
69+
);
70+
71+
$defaultValue = $defaultAdminValue ?: $this->defaultValue;
72+
73+
$result['page_layout']['default'] = $defaultValue ?: null;
4674
}
4775

4876
return $result;

app/code/Magento/Catalog/Model/Product/Option/Type/File.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
/**
1717
* Catalog product option file type
1818
*
19-
* @author Magento Core Team <core@magentocommerce.com>
19+
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
2020
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
21+
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
2122
*/
2223
class File extends \Magento\Catalog\Model\Product\Option\Type\DefaultType
2324
{
@@ -264,7 +265,6 @@ public function validateUserValue($values)
264265
. "Make sure the options are entered and try again."
265266
)
266267
);
267-
break;
268268
default:
269269
$this->setUserValue(null);
270270
break;
@@ -332,7 +332,11 @@ public function prepareForCart()
332332
public function getFormattedOptionValue($optionValue)
333333
{
334334
if ($this->_formattedOptionValue === null) {
335-
$value = $this->serializer->unserialize($optionValue);
335+
try {
336+
$value = $this->serializer->unserialize($optionValue);
337+
} catch (\InvalidArgumentException $e) {
338+
return $optionValue;
339+
}
336340
if ($value === null) {
337341
return $optionValue;
338342
}
@@ -478,13 +482,13 @@ public function copyQuoteToOrder()
478482
try {
479483
$value = $this->serializer->unserialize($quoteOption->getValue());
480484
if (!isset($value['quote_path'])) {
481-
throw new \Exception();
485+
return $this;
482486
}
483487
$quotePath = $value['quote_path'];
484488
$orderPath = $value['order_path'];
485489

486490
if (!$this->mediaDirectory->isFile($quotePath) || !$this->mediaDirectory->isReadable($quotePath)) {
487-
throw new \Exception();
491+
return $this;
488492
}
489493

490494
if ($this->_coreFileStorageDatabase->checkDbUsage()) {

app/code/Magento/Catalog/Model/Product/Type/AbstractType.php

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@
99
use Magento\Catalog\Api\ProductRepositoryInterface;
1010
use Magento\Framework\App\Filesystem\DirectoryList;
1111
use Magento\Framework\Exception\LocalizedException;
12+
use Magento\Framework\App\ObjectManager;
1213

1314
/**
14-
* @api
1515
* Abstract model for product type implementation
16+
*
17+
* phpcs:disable Magento2.Classes.AbstractApi
18+
* @api
19+
* @since 100.0.2
1620
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
1721
* @SuppressWarnings(PHPMD.TooManyFields)
1822
* @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
1923
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
20-
* @since 100.0.2
2124
*/
2225
abstract class AbstractType
2326
{
@@ -207,7 +210,7 @@ public function __construct(
207210
$this->_filesystem = $filesystem;
208211
$this->_logger = $logger;
209212
$this->productRepository = $productRepository;
210-
$this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance()
213+
$this->serializer = $serializer ?: ObjectManager::getInstance()
211214
->get(\Magento\Framework\Serialize\Serializer\Json::class);
212215
}
213216

@@ -478,6 +481,7 @@ public function prepareForCart(\Magento\Framework\DataObject $buyRequest, $produ
478481
* @throws \Magento\Framework\Exception\LocalizedException
479482
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
480483
* @SuppressWarnings(PHPMD.NPathComplexity)
484+
* phpcs:disable Generic.Metrics.NestingLevel
481485
*/
482486
public function processFileQueue()
483487
{
@@ -494,6 +498,7 @@ public function processFileQueue()
494498
/** @var $uploader \Zend_File_Transfer_Adapter_Http */
495499
$uploader = isset($queueOptions['uploader']) ? $queueOptions['uploader'] : null;
496500

501+
// phpcs:ignore Magento2.Functions.DiscouragedFunction
497502
$path = dirname($dst);
498503

499504
try {
@@ -531,6 +536,7 @@ public function processFileQueue()
531536

532537
return $this;
533538
}
539+
//phpcs:enable
534540

535541
/**
536542
* Add file to File Queue
@@ -575,6 +581,7 @@ public function getSpecifyOptionMessage()
575581
* @param string $processMode
576582
* @return array
577583
* @throws LocalizedException
584+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
578585
*/
579586
protected function _prepareOptions(\Magento\Framework\DataObject $buyRequest, $product, $processMode)
580587
{
@@ -586,15 +593,22 @@ protected function _prepareOptions(\Magento\Framework\DataObject $buyRequest, $p
586593
}
587594
if ($options !== null) {
588595
$results = [];
596+
$optionsFromRequest = $buyRequest->getOptions();
589597
foreach ($options as $option) {
590598
/* @var $option \Magento\Catalog\Model\Product\Option */
591599
try {
592600
$group = $option->groupFactory($option->getType())
593601
->setOption($option)
594602
->setProduct($product)
595603
->setRequest($buyRequest)
596-
->setProcessMode($processMode)
597-
->validateUserValue($buyRequest->getOptions());
604+
->setProcessMode($processMode);
605+
606+
if ($product->getSkipCheckRequiredOption() !== true) {
607+
$group->validateUserValue($optionsFromRequest);
608+
} elseif ($optionsFromRequest !== null && isset($optionsFromRequest[$option->getId()])) {
609+
$transport->options[$option->getId()] = $optionsFromRequest[$option->getId()];
610+
}
611+
598612
} catch (LocalizedException $e) {
599613
$results[] = $e->getMessage();
600614
continue;
@@ -646,8 +660,7 @@ public function checkProductBuyState($product)
646660
}
647661

648662
/**
649-
* Prepare additional options/information for order item which will be
650-
* created from this product
663+
* Prepare additional options/information for order item which will be created from this product
651664
*
652665
* @param \Magento\Catalog\Model\Product $product
653666
* @return array
@@ -903,7 +916,7 @@ public function getStoreFilter($product)
903916
/**
904917
* Set store filter for associated products
905918
*
906-
* @param $store int|\Magento\Store\Model\Store
919+
* @param int|\Magento\Store\Model\Store $store
907920
* @param \Magento\Catalog\Model\Product $product
908921
* @return $this
909922
*/
@@ -916,6 +929,7 @@ public function setStoreFilter($store, $product)
916929

917930
/**
918931
* Allow for updates of children qty's
932+
*
919933
* (applicable for complicated product types. As default returns false)
920934
*
921935
* @param \Magento\Catalog\Model\Product $product
@@ -943,6 +957,7 @@ public function prepareQuoteItemQty($qty, $product)
943957

944958
/**
945959
* Implementation of product specify logic of which product needs to be assigned to option.
960+
*
946961
* For example if product which was added to option already removed from catalog.
947962
*
948963
* @param \Magento\Catalog\Model\Product $optionProduct
@@ -982,6 +997,7 @@ public function setConfig($config)
982997

983998
/**
984999
* Retrieve additional searchable data from type instance
1000+
*
9851001
* Using based on product id and store_id data
9861002
*
9871003
* @param \Magento\Catalog\Model\Product $product
@@ -1002,6 +1018,7 @@ public function getSearchableData($product)
10021018

10031019
/**
10041020
* Retrieve products divided into groups required to purchase
1021+
*
10051022
* At least one product in each group has to be purchased
10061023
*
10071024
* @param \Magento\Catalog\Model\Product $product
@@ -1095,6 +1112,8 @@ public function getIdentities(\Magento\Catalog\Model\Product $product)
10951112
}
10961113

10971114
/**
1115+
* Get Associated Products
1116+
*
10981117
* @param \Magento\Catalog\Model\Product\Type\AbstractType $product
10991118
* @return array
11001119
* @SuppressWarnings(PHPMD.UnusedFormalParameter)

app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Type/FileTest.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
use Magento\Framework\Filesystem\DriverPool;
1313

1414
/**
15-
* Class FileTest.
15+
* Test file option type
1616
*
1717
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
1818
*/
@@ -136,6 +136,14 @@ protected function getFileObject()
136136
);
137137
}
138138

139+
public function testGetFormattedOptionValueWithUnserializedValue()
140+
{
141+
$fileObject = $this->getFileObject();
142+
143+
$value = 'some unserialized value, 1, 2.test';
144+
$this->assertEquals($value, $fileObject->getFormattedOptionValue($value));
145+
}
146+
139147
public function testGetCustomizedView()
140148
{
141149
$fileObject = $this->getFileObject();

app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@
471471
</imports>
472472
</settings>
473473
</field>
474-
<field name="page_layout" sortOrder="190" formElement="select" component="Magento_Catalog/js/components/use-parent-settings/select" class="Magento\Catalog\Ui\Component\Form\Field\Category\PageLayout">
474+
<field name="page_layout" sortOrder="190" formElement="select" component="Magento_Catalog/js/components/use-parent-settings/select">
475475
<settings>
476476
<dataType>string</dataType>
477477
<label translate="true">Layout</label>

0 commit comments

Comments
 (0)