Skip to content

Commit 8f6eeb8

Browse files
🔃 [EngCom] Public Pull Requests - 2.3-develop
Accepted Public Pull Requests: - #19179: [Forwardport] Fixed tierprice discount not calculated correctly if has specialprice (by @torhoehn) - #19174: #18939: [Forwardport] fixed js translation. (by @p-bystritsky) - #19170: #5929: [Forwardport] Saving Product does not update URL rewrite. (by @p-bystritsky) - #18952: Magento 2.3 Fix Notice and Exception while adding image to product programmatically (by @progreg) - magento-engcom/magento2ce#2315: #12970: [Forwardport] Can't add grouped product, with out of stock sub product, to cart. (by @p-bystritsky) - #18958: #18956 Fixes for set root_category_id (by @larsroettig) - #19027: #18979 - API: Bundle Product Option Repository Delete method removes incorrect option (by @vasilii-b) - #18973: [Forwardport] Fix Authenticating a customer via REST API does not update the last logged in data (by @prakashpatel07) Fixed GitHub Issues: - #18652: Tierprice discount not calculated correctly if has specialprice. (reported by @Hoszi) has been fixed in #19179 by @torhoehn in 2.3-develop branch Related commits: 1. 8f463db 2. 63c9ea4 3. 77492c1 4. d0ba997 - #7849: M2.x.x Translation Missing in Checkout for Tax (reported by @quienti) has been fixed in #19174 by @p-bystritsky in 2.3-develop branch Related commits: 1. 0566957 - #18939: "Not yet calculated" for the tax in the summary section in the checkout is not translatable (reported by @progammer-rkt) has been fixed in #19174 by @p-bystritsky in 2.3-develop branch Related commits: 1. 0566957 - #5929: Saving Product does not update URL rewrite in Magento 2.1.0 (reported by @JacobDrummond) has been fixed in #19170 by @p-bystritsky in 2.3-develop branch Related commits: 1. 284daec - #18532: Module Catalog: product "Save and Duplicate" causes getting infinite loop (reported by @oleksii-lisovyi) has been fixed in #19170 by @p-bystritsky in 2.3-develop branch Related commits: 1. 284daec - #6803: Product::addImageToMediaGallery throws Exception (reported by @R4c00n) has been fixed in #18952 by @progreg in 2.3-develop branch Related commits: 1. 152b092 2. 7fd52e7 3. 71983df 4. 10e64f2 5. 15dc79b - #12970: Can't add grouped product, with out of stock sub product, to cart (reported by @kirillvidyuk) has been fixed in magento-engcom/magento2ce#2315 by @p-bystritsky in 2.3-develop branch Related commits: 1. f631c90 - #18956: Import of RootCategoryId should be possbile (Magento/Store/Model/Config/Importer/Processor/Create.php) (reported by @larsroettig) has been fixed in #18958 by @larsroettig in 2.3-develop branch Related commits: 1. 54f4802 2. 144ea18 3. 0f575bc 4. b490fb1 5. 803cdb1 - #18979: API: Bundle Product Option Repository Delete method removes incorrect option (reported by @nthurston) has been fixed in #19027 by @vasilii-b in 2.3-develop branch Related commits: 1. c720d97 2. 5fa6621 - #17488: Authenticating a customer via REST API does not update the last logged in data (reported by @paul-blundell) has been fixed in #18973 by @prakashpatel07 in 2.3-develop branch Related commits: 1. 97d5e9b 2. b888298 3. 876f50a 4. 80da4ea 5. a40eb48
2 parents 7c785cf + b54d9b8 commit 8f6eeb8

File tree

22 files changed

+671
-82
lines changed

22 files changed

+671
-82
lines changed

app/code/Magento/Bundle/Model/OptionRepository.php

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function __construct(
9090
}
9191

9292
/**
93-
* {@inheritdoc}
93+
* @inheritdoc
9494
*/
9595
public function get($sku, $optionId)
9696
{
@@ -106,23 +106,24 @@ public function get($sku, $optionId)
106106

107107
$productLinks = $this->linkManagement->getChildren($product->getSku(), $optionId);
108108

109-
/** @var \Magento\Bundle\Api\Data\OptionInterface $option */
109+
/** @var \Magento\Bundle\Api\Data\OptionInterface $optionDataObject */
110110
$optionDataObject = $this->optionFactory->create();
111111
$this->dataObjectHelper->populateWithArray(
112112
$optionDataObject,
113113
$option->getData(),
114114
\Magento\Bundle\Api\Data\OptionInterface::class
115115
);
116-
$optionDataObject->setOptionId($option->getId())
117-
->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle())
118-
->setSku($product->getSku())
119-
->setProductLinks($productLinks);
116+
117+
$optionDataObject->setOptionId($option->getId());
118+
$optionDataObject->setTitle($option->getTitle() === null ? $option->getDefaultTitle() : $option->getTitle());
119+
$optionDataObject->setSku($product->getSku());
120+
$optionDataObject->setProductLinks($productLinks);
120121

121122
return $optionDataObject;
122123
}
123124

124125
/**
125-
* {@inheritdoc}
126+
* @inheritdoc
126127
*/
127128
public function getList($sku)
128129
{
@@ -131,6 +132,8 @@ public function getList($sku)
131132
}
132133

133134
/**
135+
* Return list of product options
136+
*
134137
* @param ProductInterface $product
135138
* @return \Magento\Bundle\Api\Data\OptionInterface[]
136139
*/
@@ -140,7 +143,7 @@ public function getListByProduct(ProductInterface $product)
140143
}
141144

142145
/**
143-
* {@inheritdoc}
146+
* @inheritdoc
144147
*/
145148
public function delete(\Magento\Bundle\Api\Data\OptionInterface $option)
146149
{
@@ -156,20 +159,19 @@ public function delete(\Magento\Bundle\Api\Data\OptionInterface $option)
156159
}
157160

158161
/**
159-
* {@inheritdoc}
162+
* @inheritdoc
160163
*/
161164
public function deleteById($sku, $optionId)
162165
{
163-
$product = $this->getProduct($sku);
164-
$optionCollection = $this->type->getOptionsCollection($product);
165-
$optionCollection->setIdFilter($optionId);
166-
$hasBeenDeleted = $this->delete($optionCollection->getFirstItem());
166+
/** @var \Magento\Bundle\Api\Data\OptionInterface $option */
167+
$option = $this->get($sku, $optionId);
168+
$hasBeenDeleted = $this->delete($option);
167169

168170
return $hasBeenDeleted;
169171
}
170172

171173
/**
172-
* {@inheritdoc}
174+
* @inheritdoc
173175
*/
174176
public function save(
175177
\Magento\Catalog\Api\Data\ProductInterface $product,
@@ -189,6 +191,9 @@ public function save(
189191
* @param \Magento\Catalog\Api\Data\ProductInterface $product
190192
* @param \Magento\Bundle\Api\Data\OptionInterface $option
191193
* @return $this
194+
* @throws InputException
195+
* @throws NoSuchEntityException
196+
* @throws \Magento\Framework\Exception\CouldNotSaveException
192197
*/
193198
protected function updateOptionSelection(
194199
\Magento\Catalog\Api\Data\ProductInterface $product,
@@ -228,9 +233,12 @@ protected function updateOptionSelection(
228233
}
229234

230235
/**
236+
* Retrieve product by SKU
237+
*
231238
* @param string $sku
232239
* @return \Magento\Catalog\Api\Data\ProductInterface
233-
* @throws \Magento\Framework\Exception\InputException
240+
* @throws InputException
241+
* @throws NoSuchEntityException
234242
*/
235243
private function getProduct($sku)
236244
{

app/code/Magento/Bundle/Test/Unit/Model/OptionRepositoryTest.php

Lines changed: 68 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\Bundle\Test\Unit\Model;
99

1010
use Magento\Bundle\Model\OptionRepository;
11+
use Magento\Framework\Exception\NoSuchEntityException;
1112

1213
/**
1314
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -84,7 +85,7 @@ protected function setUp()
8485
->getMock();
8586
$this->optionResourceMock = $this->createPartialMock(
8687
\Magento\Bundle\Model\ResourceModel\Option::class,
87-
['delete', '__wakeup', 'save', 'removeOptionSelections']
88+
['get', 'delete', '__wakeup', 'save', 'removeOptionSelections']
8889
);
8990
$this->storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class);
9091
$this->linkManagementMock = $this->createMock(\Magento\Bundle\Api\ProductLinkManagementInterface::class);
@@ -227,32 +228,92 @@ public function testDeleteThrowsExceptionIfCannotDelete()
227228
$this->model->delete($optionMock);
228229
}
229230

231+
/**
232+
* Test successful delete action for given $optionId
233+
*/
230234
public function testDeleteById()
231235
{
232236
$productSku = 'sku';
233237
$optionId = 100;
234-
$productMock = $this->createMock(\Magento\Catalog\Api\Data\ProductInterface::class);
238+
239+
$optionMock = $this->createMock(\Magento\Bundle\Model\Option::class);
240+
$optionMock->expects($this->exactly(2))
241+
->method('getId')
242+
->willReturn($optionId);
243+
244+
$optionMock->expects($this->once())
245+
->method('getData')
246+
->willReturn([
247+
'title' => 'Option title',
248+
'option_id' => $optionId
249+
]);
250+
251+
$this->optionFactoryMock->expects($this->once())
252+
->method('create')
253+
->willReturn($optionMock);
254+
255+
$productMock = $this->createPartialMock(
256+
\Magento\Catalog\Model\Product::class,
257+
['getTypeId', 'getTypeInstance', 'getStoreId', 'getPriceType', '__wakeup', 'getSku']
258+
);
235259
$productMock->expects($this->once())
236260
->method('getTypeId')
237261
->willReturn(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE);
238-
$this->productRepositoryMock->expects($this->once())
262+
$productMock->expects($this->exactly(2))->method('getSku')->willReturn($productSku);
263+
264+
$this->productRepositoryMock
265+
->expects($this->once())
239266
->method('get')
240267
->with($productSku)
241268
->willReturn($productMock);
242269

270+
$optCollectionMock = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class);
271+
$optCollectionMock->expects($this->once())->method('getItemById')->with($optionId)->willReturn($optionMock);
272+
$this->typeMock->expects($this->once())
273+
->method('getOptionsCollection')
274+
->with($productMock)
275+
->willReturn($optCollectionMock);
276+
277+
$this->assertTrue($this->model->deleteById($productSku, $optionId));
278+
}
279+
280+
/**
281+
* Tests if NoSuchEntityException thrown when provided $optionId not found
282+
*/
283+
public function testDeleteByIdException()
284+
{
285+
$productSku = 'sku';
286+
$optionId = null;
287+
243288
$optionMock = $this->createMock(\Magento\Bundle\Model\Option::class);
289+
$optionMock->expects($this->exactly(1))
290+
->method('getId')
291+
->willReturn($optionId);
292+
293+
$productMock = $this->createPartialMock(
294+
\Magento\Catalog\Model\Product::class,
295+
['getTypeId', 'getTypeInstance', 'getStoreId', 'getPriceType', '__wakeup', 'getSku']
296+
);
297+
$productMock->expects($this->once())
298+
->method('getTypeId')
299+
->willReturn(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE);
300+
301+
$this->productRepositoryMock
302+
->expects($this->once())
303+
->method('get')
304+
->with($productSku)
305+
->willReturn($productMock);
244306

245307
$optCollectionMock = $this->createMock(\Magento\Bundle\Model\ResourceModel\Option\Collection::class);
308+
$optCollectionMock->expects($this->once())->method('getItemById')->with($optionId)->willReturn($optionMock);
246309
$this->typeMock->expects($this->once())
247310
->method('getOptionsCollection')
248311
->with($productMock)
249312
->willReturn($optCollectionMock);
250313

251-
$optCollectionMock->expects($this->once())->method('setIdFilter')->with($optionId)->willReturnSelf();
252-
$optCollectionMock->expects($this->once())->method('getFirstItem')->willReturn($optionMock);
314+
$this->expectException(NoSuchEntityException::class);
253315

254-
$this->optionResourceMock->expects($this->once())->method('delete')->with($optionMock)->willReturnSelf();
255-
$this->assertTrue($this->model->deleteById($productSku, $optionId));
316+
$this->model->deleteById($productSku, $optionId);
256317
}
257318

258319
/**

app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
use Magento\Catalog\Model\Attribute\ScopeOverriddenValue;
1515

16+
/**
17+
* Backend model for Tierprice attribute
18+
*/
1619
class Tierprice extends \Magento\Catalog\Model\Product\Attribute\Backend\GroupPrice\AbstractGroupPrice
1720
{
1821
/**
@@ -159,8 +162,22 @@ protected function validatePrice(array $priceRow)
159162
*/
160163
protected function modifyPriceData($object, $data)
161164
{
165+
/** @var \Magento\Catalog\Model\Product $object */
162166
$data = parent::modifyPriceData($object, $data);
163167
$price = $object->getPrice();
168+
169+
$specialPrice = $object->getSpecialPrice();
170+
$specialPriceFromDate = $object->getSpecialFromDate();
171+
$specialPriceToDate = $object->getSpecialToDate();
172+
$today = time();
173+
174+
if ($specialPrice && ($object->getPrice() > $object->getFinalPrice())) {
175+
if ($today >= strtotime($specialPriceFromDate) && $today <= strtotime($specialPriceToDate) ||
176+
$today >= strtotime($specialPriceFromDate) && $specialPriceToDate === null) {
177+
$price = $specialPrice;
178+
}
179+
}
180+
164181
foreach ($data as $key => $tierPrice) {
165182
$percentageValue = $this->getPercentage($tierPrice);
166183
if ($percentageValue) {
@@ -172,6 +189,10 @@ protected function modifyPriceData($object, $data)
172189
}
173190

174191
/**
192+
* Update Price values in DB
193+
*
194+
* Updates price values in DB from array comparing to old values. Returns bool if updated
195+
*
175196
* @param array $valuesToUpdate
176197
* @param array $oldValues
177198
* @return boolean

app/code/Magento/Catalog/Model/Product/Gallery/Processor.php

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
namespace Magento\Catalog\Model\Product\Gallery;
88

9+
use Magento\Framework\Api\Data\ImageContentInterface;
910
use Magento\Framework\App\Filesystem\DirectoryList;
1011
use Magento\Framework\Exception\LocalizedException;
11-
use Magento\Framework\Filesystem\DriverInterface;
12+
use Magento\Framework\App\ObjectManager;
1213

1314
/**
1415
* Catalog product Media Gallery attribute processor.
@@ -56,28 +57,39 @@ class Processor
5657
*/
5758
protected $resourceModel;
5859

60+
/**
61+
* @var \Magento\Framework\File\Mime
62+
*/
63+
private $mime;
64+
5965
/**
6066
* @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
6167
* @param \Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb
6268
* @param \Magento\Catalog\Model\Product\Media\Config $mediaConfig
6369
* @param \Magento\Framework\Filesystem $filesystem
6470
* @param \Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel
71+
* @param \Magento\Framework\File\Mime|null $mime
72+
* @throws \Magento\Framework\Exception\FileSystemException
6573
*/
6674
public function __construct(
6775
\Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
6876
\Magento\MediaStorage\Helper\File\Storage\Database $fileStorageDb,
6977
\Magento\Catalog\Model\Product\Media\Config $mediaConfig,
7078
\Magento\Framework\Filesystem $filesystem,
71-
\Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel
79+
\Magento\Catalog\Model\ResourceModel\Product\Gallery $resourceModel,
80+
\Magento\Framework\File\Mime $mime = null
7281
) {
7382
$this->attributeRepository = $attributeRepository;
7483
$this->fileStorageDb = $fileStorageDb;
7584
$this->mediaConfig = $mediaConfig;
7685
$this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
7786
$this->resourceModel = $resourceModel;
87+
$this->mime = $mime ?: ObjectManager::getInstance()->get(\Magento\Framework\File\Mime::class);
7888
}
7989

8090
/**
91+
* Return media_gallery attribute
92+
*
8193
* @return \Magento\Catalog\Api\Data\ProductAttributeInterface
8294
* @since 101.0.0
8395
*/
@@ -183,6 +195,13 @@ public function addImage(
183195
$attrCode = $this->getAttribute()->getAttributeCode();
184196
$mediaGalleryData = $product->getData($attrCode);
185197
$position = 0;
198+
199+
$absoluteFilePath = $this->mediaDirectory->getAbsolutePath($file);
200+
$imageMimeType = $this->mime->getMimeType($absoluteFilePath);
201+
$imageContent = $this->mediaDirectory->readFile($absoluteFilePath);
202+
$imageBase64 = base64_encode($imageContent);
203+
$imageName = $pathinfo['filename'];
204+
186205
if (!is_array($mediaGalleryData)) {
187206
$mediaGalleryData = ['images' => []];
188207
}
@@ -197,9 +216,17 @@ public function addImage(
197216
$mediaGalleryData['images'][] = [
198217
'file' => $fileName,
199218
'position' => $position,
200-
'media_type' => 'image',
201219
'label' => '',
202220
'disabled' => (int)$exclude,
221+
'media_type' => 'image',
222+
'types' => $mediaAttribute,
223+
'content' => [
224+
'data' => [
225+
ImageContentInterface::NAME => $imageName,
226+
ImageContentInterface::BASE64_ENCODED_DATA => $imageBase64,
227+
ImageContentInterface::TYPE => $imageMimeType,
228+
]
229+
]
203230
];
204231

205232
$product->setData($attrCode, $mediaGalleryData);
@@ -358,7 +385,8 @@ public function setMediaAttribute(\Magento\Catalog\Model\Product $product, $medi
358385
}
359386

360387
/**
361-
* get media attribute codes
388+
* Get media attribute codes
389+
*
362390
* @return array
363391
* @since 101.0.0
364392
*/
@@ -368,6 +396,8 @@ public function getMediaAttributeCodes()
368396
}
369397

370398
/**
399+
* Trim .tmp ending from filename
400+
*
371401
* @param string $file
372402
* @return string
373403
* @since 101.0.0
@@ -489,7 +519,6 @@ public function getAffectedFields($object)
489519
/**
490520
* Attribute value is not to be saved in a conventional way, separate table is used to store the complex value
491521
*
492-
* {@inheritdoc}
493522
* @since 101.0.0
494523
*/
495524
public function isScalar()

0 commit comments

Comments
 (0)