Skip to content

Commit 506d500

Browse files
Merge pull request #1838 from magento-engcom/2.2-develop-prs
[EngCom] Public Pull Requests - 2.2-develop - MAGETWO-85538: 5738: SearchCriteriaBuilder builds wrong criteria (ORDER BY part). - MAGETWO-85537: 2907: Integration Test Annotation magentoAppArea breaks with some valid values. - MAGETWO-85305: 12560: Back-End issue for multi-store website: when editing Order shipping/billing address - allowed countries are selected from wrong Store View - MAGETWO-85301: 10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". - MAGETWO-85291: 8601: Can bypass Minimum Order Amount Logic Fixed Issues: - #5738: SearchCriteriaBuilder builds wrong criteria (ORDER BY part) - #2907: Integration Test Annotation magentoAppArea breaks with some valid values - #12560: Back-End issue for multi-store website: when editing Order shipping/billing address - allowed countries are selected from wrong Store View - #10797: catalogProductTierPriceManagementV1 DELETE and POST operation wipes out media gallery selections when used on store code "all". - #8601: Can bypass Minimum Order Amount Logic
2 parents b9ab1ea + 3a2e103 commit 506d500

File tree

14 files changed

+502
-66
lines changed

14 files changed

+502
-66
lines changed

app/code/Magento/Catalog/Model/ProductRepository.php

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,7 @@ private function processLinks(\Magento\Catalog\Api\Data\ProductInterface $produc
493493
* @return $this
494494
* @throws InputException
495495
* @throws StateException
496+
* @throws LocalizedException
496497
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
497498
*/
498499
protected function processMediaGallery(ProductInterface $product, $mediaGalleryEntries)
@@ -502,16 +503,16 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
502503
$entriesById = [];
503504
if (!empty($existingMediaGallery)) {
504505
foreach ($mediaGalleryEntries as $entry) {
505-
if (isset($entry['value_id'])) {
506-
$entriesById[$entry['value_id']] = $entry;
506+
if (isset($entry['id'])) {
507+
$entriesById[$entry['id']] = $entry;
507508
} else {
508509
$newEntries[] = $entry;
509510
}
510511
}
511512
foreach ($existingMediaGallery as $key => &$existingEntry) {
512513
if (isset($entriesById[$existingEntry['value_id']])) {
513514
$updatedEntry = $entriesById[$existingEntry['value_id']];
514-
if ($updatedEntry['file'] === null) {
515+
if (array_key_exists('file', $updatedEntry) && $updatedEntry['file'] === null) {
515516
unset($updatedEntry['file']);
516517
}
517518
$existingMediaGallery[$key] = array_merge($existingEntry, $updatedEntry);
@@ -520,6 +521,7 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
520521
$existingEntry['removed'] = true;
521522
}
522523
}
524+
unset($existingEntry);
523525
$product->setData('media_gallery', ["images" => $existingMediaGallery]);
524526
} else {
525527
$newEntries = $mediaGalleryEntries;
@@ -534,26 +536,8 @@ protected function processMediaGallery(ProductInterface $product, $mediaGalleryE
534536
}
535537
}
536538
}
539+
$this->processEntries($product, $newEntries, $entriesById);
537540

538-
foreach ($newEntries as $newEntry) {
539-
if (!isset($newEntry['content'])) {
540-
throw new InputException(__('The image content is not valid.'));
541-
}
542-
/** @var ImageContentInterface $contentDataObject */
543-
$contentDataObject = $this->contentFactory->create()
544-
->setName($newEntry['content']['data'][ImageContentInterface::NAME])
545-
->setBase64EncodedData($newEntry['content']['data'][ImageContentInterface::BASE64_ENCODED_DATA])
546-
->setType($newEntry['content']['data'][ImageContentInterface::TYPE]);
547-
$newEntry['content'] = $contentDataObject;
548-
$this->processNewMediaGalleryEntry($product, $newEntry);
549-
550-
$finalGallery = $product->getData('media_gallery');
551-
$newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById));
552-
$newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]);
553-
$entriesById[$newEntryId] = $newEntry;
554-
$finalGallery['images'][$newEntryId] = $newEntry;
555-
$product->setData('media_gallery', $finalGallery);
556-
}
557541
return $this;
558542
}
559543

@@ -592,8 +576,8 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
592576
$product = $this->initializeProductData($productDataArray, empty($existingProduct));
593577

594578
$this->processLinks($product, $productLinks);
595-
if (isset($productDataArray['media_gallery'])) {
596-
$this->processMediaGallery($product, $productDataArray['media_gallery']['images']);
579+
if (isset($productDataArray['media_gallery_entries'])) {
580+
$this->processMediaGallery($product, $productDataArray['media_gallery_entries']);
597581
}
598582

599583
if (!$product->getOptionsReadonly()) {
@@ -791,4 +775,60 @@ private function getCollectionProcessor()
791775
}
792776
return $this->collectionProcessor;
793777
}
778+
779+
/**
780+
* Convert extension attribute for product media gallery.
781+
*
782+
* @param array $newEntry
783+
* @param array $extensionAttributes
784+
* @return void
785+
*/
786+
private function processExtensionAttributes(array &$newEntry, array $extensionAttributes)
787+
{
788+
foreach ($extensionAttributes as $code => $value) {
789+
if (is_array($value)) {
790+
$this->processExtensionAttributes($newEntry, $value);
791+
} else {
792+
$newEntry[$code] = $value;
793+
}
794+
}
795+
unset($newEntry['extension_attributes']);
796+
}
797+
798+
/**
799+
* Convert entries into product media gallery data and set to product.
800+
*
801+
* @param ProductInterface $product
802+
* @param array $newEntries
803+
* @param array $entriesById
804+
* @throws InputException
805+
* @throws LocalizedException
806+
* @throws StateException
807+
* @return void
808+
*/
809+
private function processEntries(ProductInterface $product, array $newEntries, array $entriesById)
810+
{
811+
foreach ($newEntries as $newEntry) {
812+
if (!isset($newEntry['content'])) {
813+
throw new InputException(__('The image content is not valid.'));
814+
}
815+
/** @var ImageContentInterface $contentDataObject */
816+
$contentDataObject = $this->contentFactory->create()
817+
->setName($newEntry['content'][ImageContentInterface::NAME])
818+
->setBase64EncodedData($newEntry['content'][ImageContentInterface::BASE64_ENCODED_DATA])
819+
->setType($newEntry['content'][ImageContentInterface::TYPE]);
820+
$newEntry['content'] = $contentDataObject;
821+
$this->processNewMediaGalleryEntry($product, $newEntry);
822+
823+
$finalGallery = $product->getData('media_gallery');
824+
$newEntryId = key(array_diff_key($product->getData('media_gallery')['images'], $entriesById));
825+
if (isset($newEntry['extension_attributes'])) {
826+
$this->processExtensionAttributes($newEntry, $newEntry['extension_attributes']);
827+
}
828+
$newEntry = array_replace_recursive($newEntry, $finalGallery['images'][$newEntryId]);
829+
$entriesById[$newEntryId] = $newEntry;
830+
$finalGallery['images'][$newEntryId] = $newEntry;
831+
$product->setData('media_gallery', $finalGallery);
832+
}
833+
}
794834
}

app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
namespace Magento\Catalog\Test\Unit\Model;
1111

12-
use Magento\Catalog\Api\Data\ProductAttributeInterface;
1312
use Magento\Framework\Api\Data\ImageContentInterface;
1413
use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface;
1514
use Magento\Framework\DB\Adapter\ConnectionException;
@@ -1178,7 +1177,21 @@ public function testSaveExistingWithNewMediaGalleryEntries()
11781177

11791178
$this->setupProductMocksForSave();
11801179
//media gallery data
1181-
$this->productData['media_gallery'] = $newEntriesData;
1180+
$this->productData['media_gallery_entries'] = [
1181+
[
1182+
'id' => null,
1183+
'label' => "label_text",
1184+
'position' => 10,
1185+
'disabled' => false,
1186+
'types' => ['image', 'small_image'],
1187+
'content' => [
1188+
ImageContentInterface::NAME => 'filename',
1189+
ImageContentInterface::TYPE => 'image/jpeg',
1190+
ImageContentInterface::BASE64_ENCODED_DATA => 'encoded_content',
1191+
],
1192+
'media_type' => 'media_type',
1193+
]
1194+
];
11821195
$this->extensibleDataObjectConverterMock
11831196
->expects($this->once())
11841197
->method('toNestedArray')
@@ -1288,7 +1301,7 @@ public function testSaveExistingWithMediaGalleryEntries()
12881301
//update one entry, delete one entry
12891302
$newEntries = [
12901303
[
1291-
'value_id' => 5,
1304+
'id' => 5,
12921305
"label" => "new_label_text",
12931306
'file' => 'filename1',
12941307
'position' => 10,
@@ -1316,7 +1329,7 @@ public function testSaveExistingWithMediaGalleryEntries()
13161329
$expectedResult = [
13171330
[
13181331
'value_id' => 5,
1319-
'value_id' => 5,
1332+
'id' => 5,
13201333
"label" => "new_label_text",
13211334
'file' => 'filename1',
13221335
'position' => 10,
@@ -1332,7 +1345,7 @@ public function testSaveExistingWithMediaGalleryEntries()
13321345

13331346
$this->setupProductMocksForSave();
13341347
//media gallery data
1335-
$this->productData['media_gallery']['images'] = $newEntries;
1348+
$this->productData['media_gallery_entries'] = $newEntries;
13361349
$this->extensibleDataObjectConverterMock
13371350
->expects($this->once())
13381351
->method('toNestedArray')

app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,21 @@ public function reset()
817817
*/
818818
public function validateMinimumAmount()
819819
{
820-
return !($this->_scopeConfig->isSetFlag(
820+
$minimumOrderActive = $this->_scopeConfig->isSetFlag(
821821
'sales/minimum_order/active',
822822
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
823-
) && $this->_scopeConfig->isSetFlag(
823+
);
824+
825+
if ($this->_scopeConfig->isSetFlag(
824826
'sales/minimum_order/multi_address',
825-
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
826-
) && !$this->getQuote()->validateMinimumAmount());
827+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE)
828+
) {
829+
$result = !($minimumOrderActive && !$this->getQuote()->validateMinimumAmount());
830+
} else {
831+
$result = !($minimumOrderActive && !$this->validateMinimumAmountForAddressItems());
832+
}
833+
834+
return $result;
827835
}
828836

829837
/**
@@ -1031,4 +1039,41 @@ private function getShippingAssignmentProcessor()
10311039
}
10321040
return $this->shippingAssignmentProcessor;
10331041
}
1042+
1043+
/**
1044+
* Validate minimum amount for "Checkout with Multiple Addresses" when
1045+
* "Validate Each Address Separately in Multi-address Checkout" is No.
1046+
*
1047+
* @return bool
1048+
*/
1049+
private function validateMinimumAmountForAddressItems()
1050+
{
1051+
$result = true;
1052+
$storeId = $this->getQuote()->getStoreId();
1053+
1054+
$minAmount = $this->_scopeConfig->getValue(
1055+
'sales/minimum_order/amount',
1056+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
1057+
$storeId
1058+
);
1059+
$taxInclude = $this->_scopeConfig->getValue(
1060+
'sales/minimum_order/tax_including',
1061+
\Magento\Store\Model\ScopeInterface::SCOPE_STORE,
1062+
$storeId
1063+
);
1064+
1065+
$addresses = $this->getQuote()->getAllAddresses();
1066+
1067+
$baseTotal = 0;
1068+
foreach ($addresses as $address) {
1069+
$taxes = $taxInclude ? $address->getBaseTaxAmount() : 0;
1070+
$baseTotal += $address->getBaseSubtotalWithDiscount() + $taxes;
1071+
}
1072+
1073+
if ($baseTotal < $minAmount) {
1074+
$result = false;
1075+
}
1076+
1077+
return $result;
1078+
}
10341079
}

app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,13 +118,18 @@ class MultishippingTest extends \PHPUnit\Framework\TestCase
118118
*/
119119
private $quoteRepositoryMock;
120120

121+
/**
122+
* @var PHPUnit_Framework_MockObject_MockObject
123+
*/
124+
private $scopeConfigMock;
125+
121126
protected function setUp()
122127
{
123128
$this->checkoutSessionMock = $this->createSimpleMock(Session::class);
124129
$this->customerSessionMock = $this->createSimpleMock(CustomerSession::class);
125130
$orderFactoryMock = $this->createSimpleMock(OrderFactory::class);
126131
$eventManagerMock = $this->createSimpleMock(ManagerInterface::class);
127-
$scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class);
132+
$this->scopeConfigMock = $this->createSimpleMock(ScopeConfigInterface::class);
128133
$sessionMock = $this->createSimpleMock(Generic::class);
129134
$addressFactoryMock = $this->createSimpleMock(AddressFactory::class);
130135
$toOrderMock = $this->createSimpleMock(ToOrder::class);
@@ -166,7 +171,7 @@ protected function setUp()
166171
$orderFactoryMock,
167172
$this->addressRepositoryMock,
168173
$eventManagerMock,
169-
$scopeConfigMock,
174+
$this->scopeConfigMock,
170175
$sessionMock,
171176
$addressFactoryMock,
172177
$toOrderMock,
@@ -497,4 +502,37 @@ private function createSimpleMock($className)
497502
->disableOriginalConstructor()
498503
->getMock();
499504
}
505+
506+
public function testValidateMinimumAmountMultiAddressTrue()
507+
{
508+
$this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive(
509+
['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
510+
['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
511+
)->willReturnOnConsecutiveCalls(true, true);
512+
513+
$this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock);
514+
$this->quoteMock->expects($this->once())->method('validateMinimumAmount')->willReturn(false);
515+
$this->assertFalse($this->model->validateMinimumAmount());
516+
}
517+
518+
public function testValidateMinimumAmountMultiAddressFalse()
519+
{
520+
$addressMock = $this->createMock(\Magento\Quote\Model\Quote\Address::class);
521+
$this->scopeConfigMock->expects($this->exactly(2))->method('isSetFlag')->withConsecutive(
522+
['sales/minimum_order/active', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
523+
['sales/minimum_order/multi_address', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
524+
)->willReturnOnConsecutiveCalls(true, false);
525+
526+
$this->scopeConfigMock->expects($this->exactly(2))->method('getValue')->withConsecutive(
527+
['sales/minimum_order/amount', \Magento\Store\Model\ScopeInterface::SCOPE_STORE],
528+
['sales/minimum_order/tax_including', \Magento\Store\Model\ScopeInterface::SCOPE_STORE]
529+
)->willReturnOnConsecutiveCalls(100, false);
530+
531+
$this->checkoutSessionMock->expects($this->atLeastOnce())->method('getQuote')->willReturn($this->quoteMock);
532+
$this->quoteMock->expects($this->once())->method('getStoreId')->willReturn(1);
533+
$this->quoteMock->expects($this->once())->method('getAllAddresses')->willReturn([$addressMock]);
534+
$addressMock->expects($this->once())->method('getBaseSubtotalWithDiscount')->willReturn(101);
535+
536+
$this->assertTrue($this->model->validateMinimumAmount());
537+
}
500538
}

app/code/Magento/Sales/Block/Adminhtml/Order/Address/Form.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,20 @@ public function getFormValues()
135135
{
136136
return $this->_getAddress()->getData();
137137
}
138+
139+
/**
140+
* @inheritdoc
141+
*/
142+
protected function processCountryOptions(
143+
\Magento\Framework\Data\Form\Element\AbstractElement $countryElement,
144+
$storeId = null
145+
) {
146+
/** @var \Magento\Sales\Model\Order\Address $address */
147+
$address = $this->_coreRegistry->registry('order_address');
148+
if ($address !== null) {
149+
$storeId = $address->getOrder()->getStoreId();
150+
}
151+
152+
parent::processCountryOptions($countryElement, $storeId);
153+
}
138154
}

app/code/Magento/Sales/Block/Adminhtml/Order/Create/Form/Address.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,17 @@ protected function _prepareForm()
293293

294294
/**
295295
* @param \Magento\Framework\Data\Form\Element\AbstractElement $countryElement
296+
* @param string|int $storeId
297+
*
296298
* @return void
297299
*/
298-
private function processCountryOptions(\Magento\Framework\Data\Form\Element\AbstractElement $countryElement)
299-
{
300-
$storeId = $this->getBackendQuoteSession()->getStoreId();
300+
protected function processCountryOptions(
301+
\Magento\Framework\Data\Form\Element\AbstractElement $countryElement,
302+
$storeId = null
303+
) {
304+
if ($storeId === null) {
305+
$storeId = $this->getBackendQuoteSession()->getStoreId();
306+
}
301307
$options = $this->getCountriesCollection()
302308
->loadByStore($storeId)
303309
->toOptionArray();

0 commit comments

Comments
 (0)