diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php index f1943bc108878..0daa1dfb5c8eb 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/TierPrice/UpdateHandler.php @@ -96,12 +96,7 @@ public function execute($entity, $arguments = []) $productId = (int)$entity->getData($identifierField); // prepare original data to compare - $origPrices = []; - $originalId = $entity->getOrigData($identifierField); - if (empty($originalId) || $entity->getData($identifierField) == $originalId) { - $origPrices = $entity->getOrigData($attribute->getName()); - } - + $origPrices = $entity->getOrigData($attribute->getName()); $old = $this->prepareOldTierPriceToCompare($origPrices); // prepare data for save $new = $this->prepareNewDataForSave($priceRows, $isGlobal); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Backend/TierPrice/UpdateHandlerTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Backend/TierPrice/UpdateHandlerTest.php index cce00c50d37af..fde793d5c5f89 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Backend/TierPrice/UpdateHandlerTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Attribute/Backend/TierPrice/UpdateHandlerTest.php @@ -108,6 +108,7 @@ public function testExecute(): void ]; $linkField = 'entity_id'; $productId = 10; + $originalProductId = 11; /** @var \PHPUnit_Framework_MockObject_MockObject $product */ $product = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) @@ -124,7 +125,7 @@ public function testExecute(): void ->willReturnMap( [ ['tier_price', $originalTierPrices], - ['entity_id', $productId] + ['entity_id', $originalProductId] ] ); $product->expects($this->atLeastOnce())->method('getStoreId')->willReturn(0); diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 4c5f666805570..7fa674505461e 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -625,6 +625,7 @@ public function setShippingMethods($methods) $addressId = $address->getId(); if (isset($methods[$addressId])) { $address->setShippingMethod($methods[$addressId]); + $address->setCollectShippingRates(true); } elseif (!$address->getShippingMethod()) { throw new \Magento\Framework\Exception\LocalizedException( __('Set shipping methods for all addresses. Verify the shipping methods and try again.') diff --git a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php index 731365974c235..fba3245bec68d 100644 --- a/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php +++ b/app/code/Magento/Multishipping/Test/Unit/Model/Checkout/Type/MultishippingTest.php @@ -420,13 +420,16 @@ public function testSetShippingMethods() $methodsArray = [1 => 'flatrate_flatrate', 2 => 'tablerate_bestway']; $addressId = 1; $addressMock = $this->getMockBuilder(QuoteAddress::class) - ->setMethods(['getId', 'setShippingMethod']) + ->setMethods(['getId', 'setShippingMethod', 'setCollectShippingRates']) ->disableOriginalConstructor() ->getMock(); $addressMock->expects($this->once())->method('getId')->willReturn($addressId); $this->quoteMock->expects($this->once())->method('getAllShippingAddresses')->willReturn([$addressMock]); $addressMock->expects($this->once())->method('setShippingMethod')->with($methodsArray[$addressId]); + $addressMock->expects($this->once()) + ->method('setCollectShippingRates') + ->with(true); $this->quoteMock->expects($this->once()) ->method('__call') ->with('setTotalsCollectedFlag', [false]) diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php index d4c2e7b2d6854..95dace13d832f 100644 --- a/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php +++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Total/Tax.php @@ -41,7 +41,7 @@ public function collect(\Magento\Sales\Model\Order\Creditmemo $creditmemo) $baseOrderItemTax = (double)$orderItem->getBaseTaxInvoiced(); $orderItemQty = (double)$orderItem->getQtyInvoiced(); - if ($orderItemTax && $orderItemQty) { + if ($orderItemQty) { /** * Check item tax amount */ diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php index 565d51ff515a2..f32ce7aa4715b 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Creditmemo/Total/TaxTest.php @@ -100,16 +100,18 @@ public function testCollect($orderData, $creditmemoData, $expectedResults) } $this->creditmemo->expects($this->any()) ->method('roundPrice') - ->will($this->returnCallback( - function ($price, $type) use (&$roundingDelta) { - if (!isset($roundingDelta[$type])) { - $roundingDelta[$type] = 0; + ->will( + $this->returnCallback( + function ($price, $type) use (&$roundingDelta) { + if (!isset($roundingDelta[$type])) { + $roundingDelta[$type] = 0; + } + $roundedPrice = round($price + $roundingDelta[$type], 2); + $roundingDelta[$type] = $price - $roundedPrice; + return $roundedPrice; } - $roundedPrice = round($price + $roundingDelta[$type], 2); - $roundingDelta[$type] = $price - $roundedPrice; - return $roundedPrice; - } - )); + ) + ); $this->model->collect($this->creditmemo); @@ -610,6 +612,143 @@ public function collectDataProvider() ], ]; + // scenario 6: 2 items, 2 invoiced, price includes tax, full discount, free shipping + // partial credit memo, make sure that discount tax compensation (with 100 % discount) is calculated correctly + $result['collect_with_full_discount_product_price'] = [ + 'order_data' => [ + 'data_fields' => [ + 'discount_amount' => -200.00, + 'discount_invoiced' => -200.00, + 'subtotal' => 181.82, + 'subtotal_incl_tax' => 200, + 'base_subtotal' => 181.82, + 'base_subtotal_incl_tax' => 200, + 'subtotal_invoiced' => 181.82, + 'discount_tax_compensation_amount' => 18.18, + 'discount_tax_compensation_invoiced' => 18.18, + 'base_discount_tax_compensation_amount' => 18.18, + 'base_discount_tax_compensation_invoiced' => 18.18, + 'grand_total' => 0, + 'base_grand_total' => 0, + 'shipping_tax_amount' => 0, + 'base_shipping_tax_amount' => 0, + 'shipping_discount_tax_compensation_amount' => 0, + 'base_shipping_discount_tax_compensation_amount' => 0, + 'tax_amount' => 0, + 'base_tax_amount' => 0, + 'tax_invoiced' => 0, + 'base_tax_invoiced' => 0, + 'tax_refunded' => 0, + 'base_tax_refunded' => 0, + 'base_shipping_amount' => 0, + ], + ], + 'creditmemo_data' => [ + 'items' => [ + 'item_1' => [ + 'order_item' => [ + 'qty_invoiced' => 1, + 'tax_amount' => 0, + 'tax_invoiced' => 0, + 'tax_refunded' => null, + 'base_tax_amount' => 0, + 'base_tax_invoiced' => 0, + 'base_tax_refunded' => 0, + 'tax_percent' => 10, + 'qty_refunded' => 0, + 'discount_percent' => 100, + 'discount_amount' => 100, + 'base_discount_amount' => 100, + 'discount_invoiced' => 100, + 'base_discount_invoiced' => 100, + 'row_total' => 90.91, + 'base_row_total' => 90.91, + 'row_invoiced' => 90.91, + 'base_row_invoiced' => 90.91, + 'price_incl_tax' => 100, + 'base_price_incl_tax' => 100, + 'row_total_incl_tax' => 100, + 'base_row_total_incl_tax' => 100, + 'discount_tax_compensation_amount' => 9.09, + 'base_discount_tax_compensation_amount' => 9.09, + 'discount_tax_compensation_invoiced' => 9.09, + 'base_discount_tax_compensation_invoiced' => 9.09, + ], + 'is_last' => true, + 'qty' => 1, + ], + 'item_2' => [ + 'order_item' => [ + 'qty_invoiced' => 1, + 'tax_amount' => 0, + 'tax_invoiced' => 0, + 'tax_refunded' => null, + 'base_tax_amount' => 0, + 'base_tax_invoiced' => 0, + 'base_tax_refunded' => null, + 'tax_percent' => 10, + 'qty_refunded' => 0, + 'discount_percent' => 100, + 'discount_amount' => 100, + 'base_discount_amount' => 100, + 'discount_invoiced' => 100, + 'base_discount_invoiced' => 100, + 'row_total' => 90.91, + 'base_row_total' => 90.91, + 'row_invoiced' => 90.91, + 'base_row_invoiced' => 90.91, + 'price_incl_tax' => 100, + 'base_price_incl_tax' => 100, + 'row_total_incl_tax' => 100, + 'base_row_total_incl_tax' => 100, + 'discount_tax_compensation_amount' => 9.09, + 'base_discount_tax_compensation_amount' => 9.09, + 'discount_tax_compensation_invoiced' => 9.09, + 'base_discount_tax_compensation_invoiced' => 9.09, + ], + 'is_last' => false, + 'qty' => 0, + ], + ], + 'is_last' => false, + 'data_fields' => [ + 'grand_total' => -9.09, + 'base_grand_total' => -9.09, + 'base_shipping_amount' => 0, + 'tax_amount' => 0, + 'base_tax_amount' => 0, + 'invoice' => new MagentoObject( + [ + 'shipping_tax_amount' => 0, + 'base_shipping_tax_amount' => 0, + 'shipping_discount_tax_compensation_amount' => 0, + 'base_shipping_discount_tax_compensation_amount' => 0, + ] + ), + ], + ], + 'expected_results' => [ + 'creditmemo_items' => [ + 'item_1' => [ + 'tax_amount' => 0, + 'base_tax_amount' => 0, + ], + 'item_2' => [ + 'tax_amount' => 0, + 'base_tax_amount' => 0, + ], + ], + 'creditmemo_data' => [ + 'grand_total' => 0, + 'base_grand_total' => 0, + 'tax_amount' => 0, + 'base_tax_amount' => 0, + 'shipping_tax_amount' => 0, + 'base_shipping_tax_amount' => 0, + ], + ], + ]; + return $result; } diff --git a/app/code/Magento/Sitemap/Model/Sitemap.php b/app/code/Magento/Sitemap/Model/Sitemap.php index 0d69634ccfa5e..2baa6ff2c71a7 100644 --- a/app/code/Magento/Sitemap/Model/Sitemap.php +++ b/app/code/Magento/Sitemap/Model/Sitemap.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Filesystem; use Magento\Framework\UrlInterface; use Magento\Robots\Model\Config\Value; use Magento\Sitemap\Model\ItemProvider\ItemProviderInterface; @@ -191,6 +192,16 @@ class Sitemap extends \Magento\Framework\Model\AbstractModel implements \Magento */ private $lastModMinTsVal; + /** + * @var Filesystem + */ + private $filesystem; + + /** + * @var DocumentRoot + */ + private $documentRoot; + /** * Initialize dependencies. * @@ -238,8 +249,9 @@ public function __construct( ) { $this->_escaper = $escaper; $this->_sitemapData = $sitemapData; - $documentRoot = $documentRoot ?: ObjectManager::getInstance()->get(DocumentRoot::class); - $this->_directory = $filesystem->getDirectoryWrite($documentRoot->getPath()); + $this->documentRoot = $documentRoot ?: ObjectManager::getInstance()->get(DocumentRoot::class); + $this->filesystem = $filesystem; + $this->_directory = $filesystem->getDirectoryWrite($this->documentRoot->getPath()); $this->_categoryFactory = $categoryFactory; $this->_productFactory = $productFactory; $this->_cmsFactory = $cmsFactory; @@ -727,8 +739,8 @@ protected function _getFormattedLastmodDate($date) */ protected function _getDocumentRoot() { - // phpcs:ignore Magento2.Functions.DiscouragedFunction - return realpath($this->_request->getServer('DOCUMENT_ROOT')); + return $this->filesystem->getDirectoryRead($this->documentRoot->getPath()) + ->getAbsolutePath(); } /** diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AbstractAttributeTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AbstractAttributeTest.php new file mode 100644 index 0000000000000..d2ab4d69dc45c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AbstractAttributeTest.php @@ -0,0 +1,196 @@ +objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + $this->attributeRepository = $this->objectManager->create(AttributeRepositoryInterface::class); + } + + /** + * @dataProvider productProvider + * @param $productSku + * @return void + */ + public function testSaveAttribute(string $productSku): void + { + $product = $this->setAttributeValueAndValidate($productSku, $this->getDefaultAttributeValue()); + $product = $this->productRepository->save($product); + $this->assertEquals($this->getDefaultAttributeValue(), $product->getData($this->getAttributeCode())); + } + + /** + * @dataProvider productProvider + * @param string $productSku + * @return void + */ + public function testRequiredAttribute(string $productSku): void + { + $this->expectException(Exception::class); + $messageFormat = 'The "%s" attribute value is empty. Set the attribute and try again.'; + $this->expectExceptionMessage( + (string)__(sprintf($messageFormat, $this->getAttribute()->getDefaultFrontendLabel())) + ); + $this->prepareAttribute(['is_required' => true]); + $this->unsetAttributeValueAndValidate($productSku); + } + + /** + * @dataProvider productProvider + * @param string $productSku + * @return void + */ + public function testDefaultValue(string $productSku): void + { + $this->prepareAttribute(['default_value' => $this->getDefaultAttributeValue()]); + $product = $this->unsetAttributeValueAndValidate($productSku); + $product = $this->productRepository->save($product); + $this->assertEquals($this->getDefaultAttributeValue(), $product->getData($this->getAttributeCode())); + } + + /** + * @dataProvider uniqueAttributeValueProvider + * @param string $firstSku + * @param string $secondSku + * @return void + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + $this->expectException(Exception::class); + $messageFormat = 'The value of the "%s" attribute isn\'t unique. Set a unique value and try again.'; + $this->expectExceptionMessage( + (string)__(sprintf($messageFormat, $this->getAttribute()->getDefaultFrontendLabel())) + ); + $this->prepareAttribute(['is_unique' => 1]); + $product = $this->setAttributeValueAndValidate($firstSku, $this->getDefaultAttributeValue()); + $this->productRepository->save($product); + $this->setAttributeValueAndValidate($secondSku, $this->getDefaultAttributeValue()); + } + + /** + * Get attribute + * + * @return ProductAttributeInterface + */ + protected function getAttribute(): ProductAttributeInterface + { + if ($this->attribute === null) { + $this->attribute = $this->attributeRepository->get( + ProductAttributeInterface::ENTITY_TYPE_CODE, + $this->getAttributeCode() + ); + } + + return $this->attribute; + } + + /** + * Set attribute value to product and validate the product + * + * @param string $attributeValue + * @param string $productSku + * @return ProductInterface + */ + protected function setAttributeValueAndValidate(string $productSku, string $attributeValue): ProductInterface + { + $product = $this->productRepository->get($productSku); + $product->addData([$this->getAttributeCode() => $attributeValue]); + $product->validate(); + + return $product; + } + + /** + * Unset attribute value of the product and validate the product + * + * @param string $productSku + * @return ProductInterface + */ + private function unsetAttributeValueAndValidate(string $productSku): ProductInterface + { + $product = $this->productRepository->get($productSku); + $product->unsetData($this->getAttributeCode()); + $product->validate(); + + return $product; + } + + /** + * Prepare attribute to test + * + * @param array $data + * @return void + */ + private function prepareAttribute(array $data): void + { + $attribute = $this->getAttribute(); + $attribute->addData($data); + $this->attributeRepository->save($attribute); + } + + /** + * Returns attribute code for current test + * + * @return string + */ + abstract protected function getAttributeCode(): string; + + /** + * Get default value for current attribute + * + * @return string + */ + abstract protected function getDefaultAttributeValue(): string; + + /** + * Products provider for tests + * + * @return array + */ + abstract public function productProvider(): array; + + /** + * Provider for unique attribute tests + * + * @return array + */ + abstract public function uniqueAttributeValueProvider(): array; +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDateTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDateTest.php new file mode 100644 index 0000000000000..d30f32087c815 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDateTest.php @@ -0,0 +1,79 @@ +markTestSkipped('Test is blocked by issue MC-28950'); + } + + /** + * @inheritdoc + */ + protected function getAttributeCode(): string + { + return 'date_attribute'; + } + + /** + * @inheritdoc + */ + protected function getDefaultAttributeValue(): string + { + return $this->getAttribute()->getBackend()->formatDate('11/20/19'); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_date_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @dataProvider uniqueAttributeValueProvider + * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod + * @inheritdoc + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDropdownTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDropdownTest.php new file mode 100644 index 0000000000000..c1cdd0bab28aa --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeDropdownTest.php @@ -0,0 +1,70 @@ +getAttribute()->getSource()->getOptionId('Option 1'); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/dropdown_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @dataProvider uniqueAttributeValueProvider + * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod + * @inheritdoc + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeMultiSelectTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeMultiSelectTest.php new file mode 100644 index 0000000000000..4ee2b83010bdc --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeMultiSelectTest.php @@ -0,0 +1,79 @@ +getAttribute()->getSource()->getOptionId('Option 1'); + } + + /** + * @inheritdoc + * @dataProvider productProvider + */ + public function testDefaultValue(string $productSku): void + { + $this->markTestSkipped('Test is blocked by issue MC-29019'); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/multiselect_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @dataProvider uniqueAttributeValueProvider + * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod + * @inheritdoc + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributePriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributePriceTest.php new file mode 100644 index 0000000000000..5de9d30f71638 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributePriceTest.php @@ -0,0 +1,93 @@ +markTestSkipped('Test is blocked by issue MC-29018'); + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/product_decimal_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @return void + */ + public function testNegativeValue(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage((string)__('Please enter a number 0 or greater in this field.')); + $this->setAttributeValueAndValidate('simple2', '-1'); + } + + /** + * @dataProvider productProvider + * @param string $productSku + */ + public function testDefaultValue(string $productSku): void + { + // product price attribute does not support default value + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } + + /** + * @inheritdoc + */ + protected function getAttributeCode(): string + { + return 'decimal_attribute'; + } + + /** + * @inheritdoc + */ + protected function getDefaultAttributeValue(): string + { + return '100'; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextAreaTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextAreaTest.php new file mode 100644 index 0000000000000..61dbf78962c9e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextAreaTest.php @@ -0,0 +1,70 @@ + 'simple2', + ] + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextTest.php new file mode 100644 index 0000000000000..4da09bc1eca5a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeTextTest.php @@ -0,0 +1,70 @@ + 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeYesNoTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeYesNoTest.php new file mode 100644 index 0000000000000..7b966791c7b6e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Save/AttributeYesNoTest.php @@ -0,0 +1,70 @@ + 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php index 03455bb341cae..2277470e33b12 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php @@ -251,6 +251,32 @@ public function additionalGalleryFieldsProvider(): array ]; } + /** + * @magentoDataFixture Magento/Catalog/_files/product_image_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_image.php + * @return void + */ + public function testExecuteWithCustomMediaAttribute(): void + { + $data = [ + 'media_gallery' => ['images' => ['image' => ['file' => $this->fileName, 'label' => '']]], + 'image' => 'no_selection', + 'small_image' => 'no_selection', + 'swatch_image' => 'no_selection', + 'thumbnail' => 'no_selection', + 'image_attribute' => $this->fileName + ]; + $product = $this->initProduct($data); + $this->createHandler->execute($product); + $mediaAttributeValue = $this->productResource->getAttributeRawValue( + $product->getId(), + ['image_attribute'], + $product->getStoreId() + ); + $this->assertEquals($this->fileName, $mediaAttributeValue); + } + /** * Returns product for testing. * diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute.php new file mode 100644 index 0000000000000..ae0c1d3613380 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute.php @@ -0,0 +1,67 @@ +create(Attribute::class); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->create(ProductAttributeRepositoryInterface::class); +/** @var $installer CategorySetup */ +$installer = $objectManager->create(CategorySetup::class); +$entityTypeId = $installer->getEntityTypeId(ProductAttributeInterface::ENTITY_TYPE_CODE); + +if (!$attribute->loadByCode($entityTypeId, 'dropdown_attribute')->getId()) { + $attribute->setData( + [ + 'attribute_code' => 'dropdown_attribute', + 'entity_type_id' => $entityTypeId, + 'is_global' => 0, + 'is_user_defined' => 1, + 'frontend_input' => 'select', + 'is_unique' => 0, + 'is_required' => 0, + 'is_searchable' => 0, + 'is_visible_in_advanced_search' => 0, + 'is_comparable' => 0, + 'is_filterable' => 0, + 'is_filterable_in_search' => 0, + 'is_used_for_promo_rules' => 0, + 'is_html_allowed_on_front' => 1, + 'is_visible_on_front' => 1, + 'used_in_product_listing' => 1, + 'used_for_sort_by' => 0, + 'frontend_label' => ['Drop-Down Attribute'], + 'backend_type' => 'int', + 'option' => [ + 'value' => [ + 'option_1' => ['Option 1'], + 'option_2' => ['Option 2'], + 'option_3' => ['Option 3'], + ], + 'order' => [ + 'option_1' => 1, + 'option_2' => 2, + 'option_3' => 3, + ], + ], + ] + ); + $attributeRepository->save($attribute); + /* Assign attribute to attribute set */ + $installer->addAttributeToGroup( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'Default', + 'Attributes', + $attribute->getId() + ); +} diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute_rollback.php new file mode 100644 index 0000000000000..b48acc0ca0ac6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_dropdown_attribute_rollback.php @@ -0,0 +1,25 @@ +get(Registry::class); +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', true); +/** @var ProductAttributeRepositoryInterface $attributeRepository */ +$attributeRepository = $objectManager->create(ProductAttributeRepositoryInterface::class); + +try { + $attributeRepository->deleteById('dropdown_attribute'); +} catch (NoSuchEntityException $e) { +} +$registry->unregister('isSecureArea'); +$registry->register('isSecureArea', false); diff --git a/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/SelectFilterTest.php b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/SelectFilterTest.php index c0677bbc6b72b..76217e9683993 100644 --- a/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/SelectFilterTest.php +++ b/dev/tests/integration/testsuite/Magento/LayeredNavigation/Block/Navigation/Category/SelectFilterTest.php @@ -19,7 +19,7 @@ class SelectFilterTest extends AbstractFiltersTest { /** - * @magentoDataFixture Magento/Catalog/_files/dropdown_attribute.php + * @magentoDataFixture Magento/Catalog/_files/product_dropdown_attribute.php * @magentoDataFixture Magento/Catalog/_files/category_with_different_price_products.php * @dataProvider getFiltersWithCustomAttributeDataProvider * @param array $products diff --git a/dev/tests/integration/testsuite/Magento/Sitemap/Model/SitemapTest.php b/dev/tests/integration/testsuite/Magento/Sitemap/Model/SitemapTest.php new file mode 100644 index 0000000000000..73863e0915c66 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sitemap/Model/SitemapTest.php @@ -0,0 +1,70 @@ +objectManager = Bootstrap::getObjectManager(); + $this->model = $this->objectManager->get(Sitemap::class); + $this->filesystem = $this->objectManager->get(Filesystem::class); + } + + /** + * Test get sitemap URL from parent root directory path + * + * @return void + */ + public function testGetSitemapUrlFromParentRootDirectoryPath(): void + { + $rootDir = $this->filesystem->getDirectoryRead(DirectoryList::ROOT) + ->getAbsolutePath(); + $requestPath = dirname($rootDir); + + /** @var Request $request */ + $request = $this->objectManager->get(Request::class); + //imitation run script from parent root directory + $request->setServer(new Parameters(['DOCUMENT_ROOT' => $requestPath])); + + $sitemapUrl = $this->model->getSitemapUrl('/', 'sitemap.xml'); + + $this->assertEquals('http://localhost/sitemap.xml', $sitemapUrl); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeTextSwatchTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeTextSwatchTest.php new file mode 100644 index 0000000000000..067ca94e02371 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeTextSwatchTest.php @@ -0,0 +1,72 @@ +getAttribute()->getSource()->getOptionId('Option 2'); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/product_text_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @dataProvider uniqueAttributeValueProvider + * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod + * @inheritdoc + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeVisualSwatchTest.php b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeVisualSwatchTest.php new file mode 100644 index 0000000000000..ab9030f5ed8d9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Swatches/Model/AttributeVisualSwatchTest.php @@ -0,0 +1,72 @@ +getAttribute()->getSource()->getOptionId('option 2'); + } + + /** + * @magentoDataFixture Magento/Swatches/_files/product_visual_swatch_attribute.php + * @magentoDataFixture Magento/Catalog/_files/second_product_simple.php + * @magentoDataFixture Magento/Catalog/_files/product_simple_out_of_stock.php + * @dataProvider uniqueAttributeValueProvider + * phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod + * @inheritdoc + */ + public function testUniqueAttribute(string $firstSku, string $secondSku): void + { + parent::testUniqueAttribute($firstSku, $secondSku); + } + + /** + * @inheritdoc + */ + public function productProvider(): array + { + return [ + [ + 'product_sku' => 'simple2', + ], + ]; + } + + /** + * @inheritdoc + */ + public function uniqueAttributeValueProvider(): array + { + return [ + [ + 'first_product_sku' => 'simple2', + 'second_product_sku' => 'simple-out-of-stock', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Weee/Model/Product/Attribute/Save/AttributeFixedProductTaxTest.php b/dev/tests/integration/testsuite/Magento/Weee/Model/Product/Attribute/Save/AttributeFixedProductTaxTest.php new file mode 100644 index 0000000000000..c83a694b4fc1d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Weee/Model/Product/Attribute/Save/AttributeFixedProductTaxTest.php @@ -0,0 +1,134 @@ +objectManager = Bootstrap::getObjectManager(); + $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class); + $this->attributeCode = 'fixed_product_attribute'; + } + + /** + * @dataProvider fPTProvider + * @param array $data + * @param array $expectedData + * @return void + */ + public function testSaveProductWithFPTAttribute(array $data, array $expectedData): void + { + $product = $this->productRepository->get('simple2'); + $product->addData([$this->attributeCode => $data]); + $product = $this->productRepository->save($product); + $this->assertEquals($expectedData, $product->getData($this->attributeCode)); + } + + /** + * @return array + */ + public function fPTProvider(): array + { + return [ + [ + 'data' => [ + [ + 'region_id' => '0', + 'country' => 'GB', + 'val' => '', + 'value' => '15', + 'website_id' => '0', + 'state' => '', + ], + [ + 'region_id' => '1', + 'country' => 'US', + 'val' => '', + 'value' => '35', + 'website_id' => '0', + 'state' => '', + ], + ], + 'expected_data' => [ + [ + 'website_id' => '0', + 'country' => 'GB', + 'state' => '0', + 'value' => '15.000', + 'website_value' => 15.0, + ], + [ + 'website_id' => '0', + 'country' => 'US', + 'state' => '0', + 'value' => '35.000', + 'website_value' => 35.0 + ], + ], + ], + ]; + } + + /** + * @return void + */ + public function testSaveProductWithFPTAttributeWithDuplicates(): void + { + $attributeValues = [ + [ + 'region_id' => '0', + 'country' => 'GB', + 'val' => '', + 'value' => '15', + 'website_id' => '0', + 'state' => '', + ], + [ + 'region_id' => '0', + 'country' => 'GB', + 'val' => '', + 'value' => '15', + 'website_id' => '0', + 'state' => '', + ], + ]; + $this->expectException(Exception::class); + $message = 'Set unique country-state combinations within the same fixed product tax. ' + . 'Verify the combinations and try again.'; + $this->expectExceptionMessage((string)__($message)); + $product = $this->productRepository->get('simple2'); + $product->addData([$this->attributeCode => $attributeValues]); + $this->productRepository->save($product); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php b/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php index fb2b0e2c379f4..c1f4439d692a4 100644 --- a/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php @@ -6,9 +6,10 @@ namespace Magento\Framework\Setup\Patch; /** - * For backward compatibility with versioned style module installation. Deprecated since creation. + * For backward compatibility with versioned style module installation. + * The interface should be used for migration from the legacy installation approach to the declarative installation + * mechanism. The usage of this interface prohibited for the new data or schema patches. * - * @deprecated */ interface PatchVersionInterface { @@ -19,7 +20,6 @@ interface PatchVersionInterface * by old mechanism of UpgradeData.php script * * @return string - * @deprecated since appearance, required for backward compatibility */ public static function getVersion(); }