diff --git a/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php b/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php index 8ad8dcb4812e4..189135776b68b 100644 --- a/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php +++ b/app/code/Magento/Catalog/Model/Product/Gallery/UpdateHandler.php @@ -16,7 +16,8 @@ class UpdateHandler extends \Magento\Catalog\Model\Product\Gallery\CreateHandler { /** - * {@inheritdoc} + * @inheritdoc + * * @since 101.0.0 */ protected function processDeletedImages($product, array &$images) @@ -31,7 +32,7 @@ protected function processDeletedImages($product, array &$images) foreach ($images as &$image) { if (!empty($image['removed'])) { - if (!empty($image['value_id']) && !isset($picturesInOtherStores[$image['file']])) { + if (!empty($image['value_id'])) { if (preg_match('/\.\.(\\\|\/)/', $image['file'])) { continue; } @@ -52,7 +53,8 @@ protected function processDeletedImages($product, array &$images) } /** - * {@inheritdoc} + * @inheritdoc + * * @since 101.0.0 */ protected function processNewImage($product, array &$image) @@ -79,6 +81,8 @@ protected function processNewImage($product, array &$image) } /** + * Retrieve store ids from product. + * * @param \Magento\Catalog\Model\Product $product * @return array * @since 101.0.0 @@ -97,6 +101,8 @@ protected function extractStoreIds($product) } /** + * Remove deleted images. + * * @param array $files * @return null * @since 101.0.0 diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductContentSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductContentSection.xml index a2ad155672a1a..784eff12a6c04 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductContentSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/AdminProductContentSection.xml @@ -13,5 +13,6 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml new file mode 100644 index 0000000000000..060720ab007eb --- /dev/null +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRemoveImageAffectsAllScopesTest.xml @@ -0,0 +1,129 @@ + + + + + + + + + + <description value="Product image should be deleted from all scopes"/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-94265"/> + <group value="Catalog"/> + </annotations> + <before> + <!--Create 2 websites (with stores, store views)--> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <createData entity="_defaultCategory" stepKey="category"/> + <createData entity="_defaultProduct" stepKey="product"> + <requiredEntity createDataKey="category"/> + </createData> + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createWebsite"> + <argument name="newWebsiteName" value="FirstWebSite"/> + <argument name="websiteCode" value="FirstWebSiteCode"/> + </actionGroup> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createNewStore" after="createWebsite"> + <argument name="website" value="FirstWebSite"/> + <argument name="storeGroupName" value="NewStore"/> + <argument name="storeGroupCode" value="Base1"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createCustomStoreView" after="createNewStore"> + <argument name="StoreGroup" value="staticFirstStoreGroup"/> + <argument name="customStore" value="staticStore"/> + </actionGroup> + + <actionGroup ref="AdminCreateWebsiteActionGroup" stepKey="createSecondWebsite" after="createCustomStoreView"> + <argument name="newWebsiteName" value="SecondWebSite"/> + <argument name="websiteCode" value="SecondWebSiteCode"/> + </actionGroup> + <actionGroup ref="AdminCreateNewStoreGroupActionGroup" stepKey="createSecondStore" after="createSecondWebsite"> + <argument name="website" value="SecondWebSite"/> + <argument name="storeGroupName" value="SecondStore"/> + <argument name="storeGroupCode" value="Base2"/> + </actionGroup> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createCustomStoreView2" after="createSecondStore"> + <argument name="StoreGroup" value="staticStoreGroup"/> + <argument name="customStore" value="staticSecondStore"/> + </actionGroup> + </before> + + <after> + <actionGroup ref="ResetWebUrlOptions" stepKey="resetUrlOption"/> + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteWebsite"> + <argument name="websiteName" value="FirstWebSite"/> + </actionGroup> + + <actionGroup ref="AdminDeleteWebsiteActionGroup" stepKey="deleteSecondWebsite"> + <argument name="websiteName" value="SecondWebSite"/> + </actionGroup> + <deleteData createDataKey="category" stepKey="deletePreReqCategory"/> + <deleteData createDataKey="product" stepKey="deleteFirstProduct"/> + <actionGroup ref="logout" stepKey="logout"/> + </after> + + <!--Create product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <waitForPageLoad stepKey="waitForProductIndexPage"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + + <!--Open created product--> + <click selector="{{AdminProductGridSection.productGridNameProduct($$product.name$$)}}" stepKey="createdProduct"/> + <waitForPageLoad stepKey="waitForOpenedCreatedProduct"/> + + <!-- Add image to product --> + <actionGroup ref="addProductImage" stepKey="addFirstImageForProduct"> + <argument name="image" value="TestImageNew"/> + </actionGroup> + + <!-- Add second image to product --> + <actionGroup ref="addProductImage" stepKey="addSecondImageForProduct"> + <argument name="image" value="MagentoLogo"/> + </actionGroup> + <!--"Product in Websites": select both Websites--> + <actionGroup ref="ProductSetWebsite" stepKey="ProductSetWebsite1"> + <argument name="website" value="FirstWebSite"/> + </actionGroup> + <actionGroup ref="ProductSetWebsite" stepKey="ProductSetWebsite2"> + <argument name="website" value="SecondWebSite"/> + </actionGroup> + + <!--Go to "Catalog" -> "Products". Open created product--> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductPage"/> + <waitForPageLoad stepKey="waitForProductPageLoaded"/> + <click selector="{{AdminProductGridSection.productGridNameProduct($$product.name$$)}}" stepKey="openCreatedProduct"/> + <waitForPageLoad stepKey="waitForCreatedProductOpened"/> + + <!--Delete Image 1--> + <actionGroup ref="removeProductImage" stepKey="removeProductImage"/> + + <!--Click "Save" in the upper right corner--> + <actionGroup ref="saveProductForm" stepKey="saveProductFormAfterRemove"/> + + <!--Switch to "Store view 1"--> + <actionGroup ref="SwitchToTheNewStoreView" stepKey="selectStoreView"> + <argument name="storeViewName" value="Store View"/> + </actionGroup> + + <!-- Assert product first image not in admin product form --> + <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInAdminProductPage"> + <argument name="image" value="TestImageNew"/> + </actionGroup> + + <!--Switch to "Store view 2"--> + <actionGroup ref="SwitchToTheNewStoreView" stepKey="selectSecondStoreView"> + <argument name="storeViewName" value="Second Store View"/> + </actionGroup> + + <!-- Verify that Image 1 is deleted from the Second Store View list --> + <actionGroup ref="assertProductImageNotInAdminProductPage" stepKey="assertProductImageNotInSecondStoreViewPage"> + <argument name="image" value="TestImageNew"/> + </actionGroup> + </test> +</tests> diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index b755d91e403ff..7c56c266a64ef 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -5,6 +5,7 @@ */ namespace Magento\CatalogImportExport\Model\Import; +use Magento\Catalog\Api\ProductRepositoryInterface; use Magento\Catalog\Model\Config as CatalogConfig; use Magento\Catalog\Model\Product\Visibility; use Magento\CatalogImportExport\Model\Import\Product\MediaGalleryProcessor; @@ -15,6 +16,7 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Filesystem; use Magento\Framework\Intl\DateTimeFactory; use Magento\Framework\Model\ResourceModel\Db\ObjectRelationProcessor; @@ -732,6 +734,11 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity */ private $dateTimeFactory; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @param \Magento\Framework\Json\Helper\Data $jsonHelper * @param \Magento\ImportExport\Helper\Data $importExportData @@ -776,7 +783,9 @@ class Product extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity * @param MediaGalleryProcessor $mediaProcessor * @param StockItemImporterInterface|null $stockItemImporter * @param DateTimeFactory $dateTimeFactory + * @param ProductRepositoryInterface|null $productRepository * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ public function __construct( \Magento\Framework\Json\Helper\Data $jsonHelper, @@ -821,7 +830,8 @@ public function __construct( ImageTypeProcessor $imageTypeProcessor = null, MediaGalleryProcessor $mediaProcessor = null, StockItemImporterInterface $stockItemImporter = null, - DateTimeFactory $dateTimeFactory = null + DateTimeFactory $dateTimeFactory = null, + ProductRepositoryInterface $productRepository = null ) { $this->_eventManager = $eventManager; $this->stockRegistry = $stockRegistry; @@ -875,6 +885,8 @@ public function __construct( ->initImagesArrayKeys(); $this->validator->init($this); $this->dateTimeFactory = $dateTimeFactory ?? ObjectManager::getInstance()->get(DateTimeFactory::class); + $this->productRepository = $productRepository ?? ObjectManager::getInstance() + ->get(ProductRepositoryInterface::class); } /** @@ -1698,6 +1710,14 @@ protected function _saveProducts() $websiteId = $this->storeResolver->getWebsiteCodeToId($websiteCode); $this->websitesCache[$rowSku][$websiteId] = true; } + } else { + $product = $this->retrieveProductBySku($rowSku); + if ($product) { + $websiteIds = $product->getWebsiteIds(); + foreach ($websiteIds as $websiteId) { + $this->websitesCache[$rowSku][$websiteId] = true; + } + } } // 3. Categories phase @@ -1996,6 +2016,11 @@ protected function processRowCategories($rowData) . ' ' . $error['exception']->getMessage() ); } + } else { + $product = $this->retrieveProductBySku($rowData['sku']); + if ($product) { + $categoryIds = $product->getCategoryIds(); + } } return $categoryIds; } @@ -2998,4 +3023,20 @@ private function formatStockDataForRow(array $rowData): array return $row; } + + /** + * Retrieve product by sku. + * + * @param string $sku + * @return \Magento\Catalog\Api\Data\ProductInterface|null + */ + private function retrieveProductBySku($sku) + { + try { + $product = $this->productRepository->get($sku); + } catch (NoSuchEntityException $e) { + return null; + } + return $product; + } } diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php index 9431973fdfe91..f7b487d37bfc6 100644 --- a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php +++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/CSV/RowParser.php @@ -9,6 +9,9 @@ use Magento\Framework\Phrase; use Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate\LocationDirectory; +/** + * Row parser. + */ class RowParser { /** @@ -26,6 +29,8 @@ public function __construct(LocationDirectory $locationDirectory) } /** + * Retrieve columns. + * * @return array */ public function getColumns() @@ -42,6 +47,8 @@ public function getColumns() } /** + * Parse provided row data. + * * @param array $rowData * @param int $rowNumber * @param int $websiteId @@ -71,23 +78,30 @@ public function parse( } $countryId = $this->getCountryId($rowData, $rowNumber, $columnResolver); - $regionId = $this->getRegionId($rowData, $rowNumber, $columnResolver, $countryId); + $regionIds = $this->getRegionIds($rowData, $rowNumber, $columnResolver, $countryId); $zipCode = $this->getZipCode($rowData, $columnResolver); $conditionValue = $this->getConditionValue($rowData, $rowNumber, $conditionFullName, $columnResolver); $price = $this->getPrice($rowData, $rowNumber, $columnResolver); - return [ - 'website_id' => $websiteId, - 'dest_country_id' => $countryId, - 'dest_region_id' => $regionId, - 'dest_zip' => $zipCode, - 'condition_name' => $conditionShortName, - 'condition_value' => $conditionValue, - 'price' => $price, - ]; + $rates = []; + foreach ($regionIds as $regionId) { + $rates[] = [ + 'website_id' => $websiteId, + 'dest_country_id' => $countryId, + 'dest_region_id' => $regionId, + 'dest_zip' => $zipCode, + 'condition_name' => $conditionShortName, + 'condition_value' => $conditionValue, + 'price' => $price, + ]; + } + + return $rates; } /** + * Get country id from provided row data. + * * @param array $rowData * @param int $rowNumber * @param ColumnResolver $columnResolver @@ -116,21 +130,23 @@ private function getCountryId(array $rowData, $rowNumber, ColumnResolver $column } /** + * Retrieve region id from provided row data. + * * @param array $rowData * @param int $rowNumber * @param ColumnResolver $columnResolver * @param int $countryId - * @return int|string + * @return array * @throws ColumnNotFoundException * @throws RowException */ - private function getRegionId(array $rowData, $rowNumber, ColumnResolver $columnResolver, $countryId) + private function getRegionIds(array $rowData, $rowNumber, ColumnResolver $columnResolver, $countryId) { $regionCode = $columnResolver->getColumnValue(ColumnResolver::COLUMN_REGION, $rowData); if ($countryId !== '0' && $this->locationDirectory->hasRegionId($countryId, $regionCode)) { - $regionId = $this->locationDirectory->getRegionId($countryId, $regionCode); + $regionIds = $this->locationDirectory->getRegionIds($countryId, $regionCode); } elseif ($regionCode === '*' || $regionCode === '') { - $regionId = 0; + $regionIds = [0]; } else { throw new RowException( __( @@ -141,10 +157,12 @@ private function getRegionId(array $rowData, $rowNumber, ColumnResolver $columnR ) ); } - return $regionId; + return $regionIds; } /** + * Retrieve zip code from provided row data. + * * @param array $rowData * @param ColumnResolver $columnResolver * @return float|int|null|string @@ -160,6 +178,8 @@ private function getZipCode(array $rowData, ColumnResolver $columnResolver) } /** + * Get condition value form provided row data. + * * @param array $rowData * @param int $rowNumber * @param string $conditionFullName @@ -187,6 +207,8 @@ private function getConditionValue(array $rowData, $rowNumber, $conditionFullNam } /** + * Retrieve price from provided row data. + * * @param array $rowData * @param int $rowNumber * @param ColumnResolver $columnResolver @@ -212,6 +234,7 @@ private function getPrice(array $rowData, $rowNumber, ColumnResolver $columnReso /** * Parse and validate positive decimal value + * * Return false if value is not decimal or is not positive * * @param string $value diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php index a5b0d7e87d2e1..7735f8ce8999c 100644 --- a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php +++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/Import.php @@ -17,6 +17,7 @@ use Magento\Store\Model\StoreManagerInterface; /** + * Import offline shipping. * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Import @@ -87,6 +88,8 @@ public function __construct( } /** + * Check if there are errors. + * * @return bool */ public function hasErrors() @@ -95,6 +98,8 @@ public function hasErrors() } /** + * Get errors. + * * @return array */ public function getErrors() @@ -103,6 +108,8 @@ public function getErrors() } /** + * Retrieve columns. + * * @return array */ public function getColumns() @@ -111,6 +118,8 @@ public function getColumns() } /** + * Get data from file. + * * @param ReadInterface $file * @param int $websiteId * @param string $conditionShortName @@ -135,7 +144,7 @@ public function getData(ReadInterface $file, $websiteId, $conditionShortName, $c if (empty($csvLine)) { continue; } - $rowData = $this->rowParser->parse( + $rowsData = $this->rowParser->parse( $csvLine, $rowNumber, $websiteId, @@ -144,20 +153,25 @@ public function getData(ReadInterface $file, $websiteId, $conditionShortName, $c $columnResolver ); - // protect from duplicate - $hash = $this->dataHashGenerator->getHash($rowData); - if (array_key_exists($hash, $this->uniqueHash)) { - throw new RowException( - __( - 'Duplicate Row #%1 (duplicates row #%2)', - $rowNumber, - $this->uniqueHash[$hash] - ) - ); + foreach ($rowsData as $rowData) { + // protect from duplicate + $hash = $this->dataHashGenerator->getHash($rowData); + if (array_key_exists($hash, $this->uniqueHash)) { + throw new RowException( + __( + 'Duplicate Row #%1 (duplicates row #%2)', + $rowNumber, + $this->uniqueHash[$hash] + ) + ); + } + $this->uniqueHash[$hash] = $rowNumber; + + $items[] = $rowData; + } + if (count($rowsData) > 1) { + $bunchSize += count($rowsData) - 1; } - $this->uniqueHash[$hash] = $rowNumber; - - $items[] = $rowData; if (count($items) === $bunchSize) { yield $items; $items = []; @@ -172,6 +186,8 @@ public function getData(ReadInterface $file, $websiteId, $conditionShortName, $c } /** + * Retrieve column headers. + * * @param ReadInterface $file * @return array|bool * @throws LocalizedException diff --git a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php index 1a311f3658a0a..e015f7b54637d 100644 --- a/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php +++ b/app/code/Magento/OfflineShipping/Model/ResourceModel/Carrier/Tablerate/LocationDirectory.php @@ -6,6 +6,9 @@ namespace Magento\OfflineShipping\Model\ResourceModel\Carrier\Tablerate; +/** + * Location directory. + */ class LocationDirectory { /** @@ -13,6 +16,11 @@ class LocationDirectory */ protected $regions; + /** + * @var array + */ + private $regionsByCode; + /** * @var array */ @@ -47,6 +55,8 @@ public function __construct( } /** + * Retrieve country id. + * * @param string $countryCode * @return null|string */ @@ -88,6 +98,8 @@ protected function loadCountries() } /** + * Check if there is country id with provided country code. + * * @param string $countryCode * @return bool */ @@ -98,6 +110,8 @@ public function hasCountryId($countryCode) } /** + * Check if there is region id with provided region code and country id. + * * @param string $countryId * @param string $regionCode * @return bool @@ -115,29 +129,50 @@ public function hasRegionId($countryId, $regionCode) */ protected function loadRegions() { - if ($this->regions !== null) { + if ($this->regions !== null && $this->regionsByCode !== null) { return $this; } $this->regions = []; + $this->regionsByCode = []; /** @var $collection \Magento\Directory\Model\ResourceModel\Region\Collection */ $collection = $this->_regionCollectionFactory->create(); foreach ($collection->getData() as $row) { $this->regions[$row['country_id']][$row['code']] = (int)$row['region_id']; + if (empty($this->regionsByCode[$row['country_id']][$row['code']])) { + $this->regionsByCode[$row['country_id']][$row['code']] = []; + } + $this->regionsByCode[$row['country_id']][$row['code']][] = (int)$row['region_id']; } return $this; } /** + * Retrieve region id. + * * @param int $countryId * @param string $regionCode * @return string + * @deprecated */ public function getRegionId($countryId, $regionCode) { $this->loadRegions(); return $this->regions[$countryId][$regionCode]; } + + /** + * Return region ids for country and region + * + * @param int $countryId + * @param string $regionCode + * @return array + */ + public function getRegionIds($countryId, $regionCode) + { + $this->loadRegions(); + return $this->regionsByCode[$countryId][$regionCode]; + } } diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php index 8c34e9a0d6510..683790c531265 100644 --- a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php +++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/CSV/RowParserTest.php @@ -37,7 +37,7 @@ class RowParserTest extends \PHPUnit\Framework\TestCase protected function setUp() { $this->locationDirectoryMock = $this->getMockBuilder(LocationDirectory::class) - ->setMethods(['hasCountryId', 'getCountryId', 'hasRegionId', 'getRegionId']) + ->setMethods(['hasCountryId', 'getCountryId', 'hasRegionId', 'getRegionIds']) ->disableOriginalConstructor() ->getMock(); $this->columnResolverMock = $this->getMockBuilder(ColumnResolver::class) @@ -92,7 +92,7 @@ public function testParse() $conditionShortName, $columnValueMap ); - $this->assertEquals($expectedResult, $result); + $this->assertEquals([$expectedResult], $result); } /** diff --git a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php index 4e433c380f753..722683decb4c2 100644 --- a/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php +++ b/app/code/Magento/OfflineShipping/Test/Unit/Model/ResourceModel/Carrier/Tablerate/ImportTest.php @@ -77,9 +77,6 @@ protected function setUp() ->getMock(); $this->dataHashGeneratorMock = $this->getMockBuilder(DataHashGenerator::class) ->getMock(); - $this->rowParserMock->expects($this->any()) - ->method('parse') - ->willReturnArgument(0); $this->dataHashGeneratorMock->expects($this->any()) ->method('getHash') ->willReturnCallback( @@ -124,6 +121,15 @@ public function testGetData() ['a4', 'b4', 'c4', 'd4', 'e4'], ['a5', 'b5', 'c5', 'd5', 'e5'], ]; + $this->rowParserMock->expects($this->any()) + ->method('parse') + ->willReturn( + [['a1', 'b1', 'c1', 'd1', 'e1']], + [['a2', 'b2', 'c2', 'd2', 'e2']], + [['a3', 'b3', 'c3', 'd3', 'e3']], + [['a4', 'b4', 'c4', 'd4', 'e4']], + [['a5', 'b5', 'c5', 'd5', 'e5']] + ); $file = $this->createFileMock($lines); $expectedResult = [ [ @@ -167,6 +173,13 @@ public function testGetDataWithDuplicatedLine() [], ['a2', 'b2', 'c2', 'd2', 'e2'], ]; + $this->rowParserMock->expects($this->any()) + ->method('parse') + ->willReturn( + [['a1', 'b1', 'c1', 'd1', 'e1']], + [['a1', 'b1', 'c1', 'd1', 'e1']], + [['a2', 'b2', 'c2', 'd2', 'e2']] + ); $file = $this->createFileMock($lines); $expectedResult = [ [ diff --git a/app/code/Magento/ProductVideo/i18n/de_DE.csv b/app/code/Magento/ProductVideo/i18n/de_DE.csv index 7047317396999..ca24668bb8d16 100644 --- a/app/code/Magento/ProductVideo/i18n/de_DE.csv +++ b/app/code/Magento/ProductVideo/i18n/de_DE.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" diff --git a/app/code/Magento/ProductVideo/i18n/en_US.csv b/app/code/Magento/ProductVideo/i18n/en_US.csv index 2d226c6daefa3..debcab151cc91 100644 --- a/app/code/Magento/ProductVideo/i18n/en_US.csv +++ b/app/code/Magento/ProductVideo/i18n/en_US.csv @@ -40,3 +40,4 @@ Delete,Delete "Autostart base video","Autostart base video" "Show related video","Show related video" "Auto restart video","Auto restart video" +"Delete image in all store views","Delete image in all store views" diff --git a/app/code/Magento/ProductVideo/i18n/es_ES.csv b/app/code/Magento/ProductVideo/i18n/es_ES.csv index 7047317396999..ca24668bb8d16 100644 --- a/app/code/Magento/ProductVideo/i18n/es_ES.csv +++ b/app/code/Magento/ProductVideo/i18n/es_ES.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" diff --git a/app/code/Magento/ProductVideo/i18n/fr_FR.csv b/app/code/Magento/ProductVideo/i18n/fr_FR.csv index 7047317396999..ca24668bb8d16 100644 --- a/app/code/Magento/ProductVideo/i18n/fr_FR.csv +++ b/app/code/Magento/ProductVideo/i18n/fr_FR.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" diff --git a/app/code/Magento/ProductVideo/i18n/nl_NL.csv b/app/code/Magento/ProductVideo/i18n/nl_NL.csv index 7047317396999..5ad8386573040 100644 --- a/app/code/Magento/ProductVideo/i18n/nl_NL.csv +++ b/app/code/Magento/ProductVideo/i18n/nl_NL.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" \ No newline at end of file diff --git a/app/code/Magento/ProductVideo/i18n/pt_BR.csv b/app/code/Magento/ProductVideo/i18n/pt_BR.csv index 7047317396999..5ad8386573040 100644 --- a/app/code/Magento/ProductVideo/i18n/pt_BR.csv +++ b/app/code/Magento/ProductVideo/i18n/pt_BR.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" \ No newline at end of file diff --git a/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv b/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv index 7047317396999..5ad8386573040 100644 --- a/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv +++ b/app/code/Magento/ProductVideo/i18n/zh_Hans_CN.csv @@ -7,3 +7,4 @@ "Preview Image","Preview Image" "Get Video Information","Get Video Information" "Youtube or Vimeo supported","Youtube or Vimeo supported" +"Delete image in all store views","Delete image in all store views" \ No newline at end of file diff --git a/app/code/Magento/ProductVideo/view/adminhtml/layout/catalog_product_new.xml b/app/code/Magento/ProductVideo/view/adminhtml/layout/catalog_product_new.xml index f5a22c50e6d0d..63bd5321ad30b 100644 --- a/app/code/Magento/ProductVideo/view/adminhtml/layout/catalog_product_new.xml +++ b/app/code/Magento/ProductVideo/view/adminhtml/layout/catalog_product_new.xml @@ -6,6 +6,9 @@ */ --> <page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd"> + <head> + <css src="Magento_ProductVideo::css/gallery-delete-tooltip.css"/> + </head> <body> <referenceContainer name="content"> diff --git a/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml b/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml index 8b0f7d8ed98df..6dff53211892f 100755 --- a/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml +++ b/app/code/Magento/ProductVideo/view/adminhtml/templates/helper/gallery.phtml @@ -140,30 +140,37 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to alt="<%- data.label %>"/> <div class="actions"> - <button type="button" - class="action-remove" - data-role="delete-button" - title="<% if (data.media_type == 'external-video') {%> + <div class="tooltip"> + <span class="delete-tooltiptext"> + <?= $block->escapeHtml( + __('Delete image in all store views') + ); ?> + </span> + <button type="button" + class="action-remove" + data-role="delete-button" + title="<% if (data.media_type == 'external-video') {%> + <?= $block->escapeHtml( + __('Delete video') + ); ?> + <%} else {%> + <?= $block->escapeHtml( + __('Delete image') + ); ?> + <%}%>"> + <span> + <% if (data.media_type == 'external-video') { %> <?= $block->escapeHtml( __('Delete video') ); ?> - <%} else {%> + <% } else {%> <?= $block->escapeHtml( __('Delete image') ); ?> - <%}%>"> - <span> - <% if (data.media_type == 'external-video') { %> - <?= $block->escapeHtml( - __('Delete video') - ); ?> - <% } else {%> - <?= $block->escapeHtml( - __('Delete image') - ); ?> - <%} %> - </span> - </button> + <%} %> + </span> + </button> + </div> <div class="draggable-handle"></div> </div> <div class="image-fade"><span><?= $block->escapeHtml( @@ -329,4 +336,4 @@ $elementToggleCode = $element->getToggleCode() ? $element->getToggleCode() : 'to </div> <script> jQuery('body').trigger('contentUpdated'); -</script> +</script> \ No newline at end of file diff --git a/app/code/Magento/ProductVideo/view/adminhtml/web/css/gallery-delete-tooltip.css b/app/code/Magento/ProductVideo/view/adminhtml/web/css/gallery-delete-tooltip.css new file mode 100644 index 0000000000000..ad779c3f29bf8 --- /dev/null +++ b/app/code/Magento/ProductVideo/view/adminhtml/web/css/gallery-delete-tooltip.css @@ -0,0 +1,20 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +.gallery .tooltip .delete-tooltiptext { + visibility: hidden; + width: 112px; + background-color: #373330; + color: #F7F3EB; + text-align: center; + padding: 5px 0; + position: absolute; + z-index: 1; + left: 30px; + top: 91px; +} + +.gallery .tooltip:hover .delete-tooltiptext { + visibility: visible; +} \ No newline at end of file diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml index 2bff20e05435a..8f859ff3cd6bc 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreData.xml @@ -41,12 +41,16 @@ </entity> <entity name="staticStore" type="store"> <!--data key="group_id">customStoreGroup.id</data--> - <data key="name" >Second Store View</data> - <data key="code" >store123</data> + <data key="name">Second Store View</data> + <data key="code">store123</data> <data key="is_active">1</data> <data key="store_id">null</data> <data key="store_action">add</data> <data key="store_type">store</data> <requiredEntity type="storeGroup">customStoreGroup</requiredEntity> </entity> + <entity name="staticSecondStore" extends="staticStore"> + <data key="name">Store View</data> + <data key="code">store2</data> + </entity> </entities> diff --git a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml index 83ca12875d099..7b31623f237e9 100644 --- a/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml +++ b/app/code/Magento/Store/Test/Mftf/Data/StoreGroupData.xml @@ -27,4 +27,8 @@ <data key="root_category_id">2</data> <data key="website_id">1</data> </entity> + <entity name="staticFirstStoreGroup" extends="staticStoreGroup"> + <data key="name">NewStore</data> + <data key="code">Base1</data> + </entity> </entities> diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 86d98181724cd..b8000640506f1 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -85,12 +85,10 @@ define([ var controls = this.controls, toggle = this.toggle; - this._on(controls.toggleBtn, { - 'click': toggle - }); - this._on(controls.swipeArea, { - 'swipeleft': toggle - }); + controls.toggleBtn.off('click'); + controls.toggleBtn.on('click', toggle.bind(this)); + controls.swipeArea.off('swipeleft'); + controls.swipeArea.on('swipeleft', toggle.bind(this)); }, /**