AdvancedPricing.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\AdvancedPricingImportExport\Model\Import;
  7. use Magento\CatalogImportExport\Model\Import\Product as ImportProduct;
  8. use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface as ValidatorInterface;
  9. use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface;
  10. /**
  11. * Class AdvancedPricing
  12. *
  13. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  14. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  15. * @SuppressWarnings(PHPMD.TooManyFields)
  16. */
  17. class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
  18. {
  19. const VALUE_ALL_GROUPS = 'ALL GROUPS';
  20. const VALUE_ALL_WEBSITES = 'All Websites';
  21. const COL_SKU = 'sku';
  22. const COL_TIER_PRICE_WEBSITE = 'tier_price_website';
  23. const COL_TIER_PRICE_CUSTOMER_GROUP = 'tier_price_customer_group';
  24. const COL_TIER_PRICE_QTY = 'tier_price_qty';
  25. const COL_TIER_PRICE = 'tier_price';
  26. const COL_TIER_PRICE_PERCENTAGE_VALUE = 'percentage_value';
  27. const COL_TIER_PRICE_TYPE = 'tier_price_value_type';
  28. const TIER_PRICE_TYPE_FIXED = 'Fixed';
  29. const TIER_PRICE_TYPE_PERCENT = 'Discount';
  30. const TABLE_TIER_PRICE = 'catalog_product_entity_tier_price';
  31. const DEFAULT_ALL_GROUPS_GROUPED_PRICE_VALUE = '0';
  32. const ENTITY_TYPE_CODE = 'advanced_pricing';
  33. const VALIDATOR_MAIN = 'validator';
  34. const VALIDATOR_WEBSITE = 'validator_website';
  35. const VALIDATOR_TEAR_PRICE = 'validator_tear_price';
  36. /**
  37. * Validation failure message template definitions.
  38. *
  39. * @var array
  40. */
  41. protected $_messageTemplates = [
  42. ValidatorInterface::ERROR_INVALID_WEBSITE => 'Invalid value in Website column (website does not exists?)',
  43. ValidatorInterface::ERROR_SKU_IS_EMPTY => 'SKU is empty',
  44. ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE => 'Product with specified SKU not found',
  45. ValidatorInterface::ERROR_INVALID_TIER_PRICE_QTY => 'Tier Price data price or quantity value is invalid',
  46. ValidatorInterface::ERROR_INVALID_TIER_PRICE_SITE => 'Tier Price data website is invalid',
  47. ValidatorInterface::ERROR_INVALID_TIER_PRICE_GROUP => 'Tier Price customer group is invalid',
  48. ValidatorInterface::ERROR_INVALID_TIER_PRICE_TYPE => 'Value for \'tier_price_value_type\' ' .
  49. 'attribute contains incorrect value, acceptable values are Fixed, Discount',
  50. ValidatorInterface::ERROR_TIER_DATA_INCOMPLETE => 'Tier Price data is incomplete',
  51. ValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL =>
  52. 'Value for \'%s\' attribute contains incorrect value, acceptable values are in decimal format',
  53. ];
  54. /**
  55. * If we should check column names
  56. *
  57. * @var bool
  58. */
  59. protected $needColumnCheck = true;
  60. /**
  61. * Valid column names.
  62. *
  63. * @array
  64. */
  65. protected $validColumnNames = [
  66. self::COL_SKU,
  67. self::COL_TIER_PRICE_WEBSITE,
  68. self::COL_TIER_PRICE_CUSTOMER_GROUP,
  69. self::COL_TIER_PRICE_QTY,
  70. self::COL_TIER_PRICE,
  71. self::COL_TIER_PRICE_TYPE
  72. ];
  73. /**
  74. * Need to log in import history
  75. *
  76. * @var bool
  77. */
  78. protected $logInHistory = true;
  79. /**
  80. * @var \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory
  81. */
  82. protected $_resourceFactory;
  83. /**
  84. * @var \Magento\Catalog\Helper\Data
  85. */
  86. protected $_catalogData;
  87. /**
  88. * @var \Magento\Catalog\Model\Product
  89. */
  90. protected $_productModel;
  91. /**
  92. * @var \Magento\CatalogImportExport\Model\Import\Product\StoreResolver
  93. */
  94. protected $_storeResolver;
  95. /**
  96. * @var ImportProduct
  97. */
  98. protected $_importProduct;
  99. /**
  100. * @var array
  101. */
  102. protected $_validators = [];
  103. /**
  104. * @var array
  105. */
  106. protected $_cachedSkuToDelete;
  107. /**
  108. * @var array
  109. */
  110. protected $_oldSkus = null;
  111. /**
  112. * Permanent entity columns.
  113. *
  114. * @var string[]
  115. */
  116. protected $_permanentAttributes = [self::COL_SKU];
  117. /**
  118. * Catalog product entity
  119. *
  120. * @var string
  121. */
  122. protected $_catalogProductEntity;
  123. /**
  124. * @var \Magento\Framework\Stdlib\DateTime\DateTime
  125. */
  126. protected $dateTime;
  127. /**
  128. * Product entity link field
  129. *
  130. * @var string
  131. */
  132. private $productEntityLinkField;
  133. /**
  134. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  135. * @param \Magento\Framework\Json\Helper\Data $jsonHelper
  136. * @param \Magento\ImportExport\Helper\Data $importExportData
  137. * @param \Magento\ImportExport\Model\ResourceModel\Import\Data $importData
  138. * @param \Magento\Eav\Model\Config $config
  139. * @param \Magento\Framework\App\ResourceConnection $resource
  140. * @param \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper
  141. * @param \Magento\Framework\Stdlib\StringUtils $string
  142. * @param ProcessingErrorAggregatorInterface $errorAggregator
  143. * @param \Magento\Framework\Stdlib\DateTime\DateTime $dateTime
  144. * @param \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory $resourceFactory
  145. * @param \Magento\Catalog\Model\Product $productModel
  146. * @param \Magento\Catalog\Helper\Data $catalogData
  147. * @param ImportProduct\StoreResolver $storeResolver
  148. * @param ImportProduct $importProduct
  149. * @param AdvancedPricing\Validator $validator
  150. * @param AdvancedPricing\Validator\Website $websiteValidator
  151. * @param AdvancedPricing\Validator\TierPrice $tierPriceValidator
  152. * @SuppressWarnings(PHPMD.UnusedFormalParameter)
  153. */
  154. public function __construct(
  155. \Magento\Framework\Json\Helper\Data $jsonHelper,
  156. \Magento\ImportExport\Helper\Data $importExportData,
  157. \Magento\ImportExport\Model\ResourceModel\Import\Data $importData,
  158. \Magento\Eav\Model\Config $config,
  159. \Magento\Framework\App\ResourceConnection $resource,
  160. \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper,
  161. \Magento\Framework\Stdlib\StringUtils $string,
  162. ProcessingErrorAggregatorInterface $errorAggregator,
  163. \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
  164. \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory $resourceFactory,
  165. \Magento\Catalog\Model\Product $productModel,
  166. \Magento\Catalog\Helper\Data $catalogData,
  167. \Magento\CatalogImportExport\Model\Import\Product\StoreResolver $storeResolver,
  168. ImportProduct $importProduct,
  169. AdvancedPricing\Validator $validator,
  170. AdvancedPricing\Validator\Website $websiteValidator,
  171. AdvancedPricing\Validator\TierPrice $tierPriceValidator
  172. ) {
  173. $this->dateTime = $dateTime;
  174. $this->jsonHelper = $jsonHelper;
  175. $this->_importExportData = $importExportData;
  176. $this->_resourceHelper = $resourceHelper;
  177. $this->_dataSourceModel = $importData;
  178. $this->_connection = $resource->getConnection('write');
  179. $this->_resourceFactory = $resourceFactory;
  180. $this->_productModel = $productModel;
  181. $this->_catalogData = $catalogData;
  182. $this->_storeResolver = $storeResolver;
  183. $this->_importProduct = $importProduct;
  184. $this->_validators[self::VALIDATOR_MAIN] = $validator->init($this);
  185. $this->_catalogProductEntity = $this->_resourceFactory->create()->getTable('catalog_product_entity');
  186. $this->_oldSkus = $this->retrieveOldSkus();
  187. $this->_validators[self::VALIDATOR_WEBSITE] = $websiteValidator;
  188. $this->_validators[self::VALIDATOR_TEAR_PRICE] = $tierPriceValidator;
  189. $this->errorAggregator = $errorAggregator;
  190. foreach (array_merge($this->errorMessageTemplates, $this->_messageTemplates) as $errorCode => $message) {
  191. $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
  192. }
  193. }
  194. /**
  195. * Validator object getter.
  196. *
  197. * @param string $type
  198. * @return AdvancedPricing\Validator|AdvancedPricing\Validator\Website
  199. */
  200. protected function _getValidator($type)
  201. {
  202. return $this->_validators[$type];
  203. }
  204. /**
  205. * Entity type code getter.
  206. *
  207. * @return string
  208. */
  209. public function getEntityTypeCode()
  210. {
  211. return 'advanced_pricing';
  212. }
  213. /**
  214. * Row validation.
  215. *
  216. * @param array $rowData
  217. * @param int $rowNum
  218. * @return bool
  219. */
  220. public function validateRow(array $rowData, $rowNum)
  221. {
  222. $sku = false;
  223. if (isset($this->_validatedRows[$rowNum])) {
  224. return !$this->getErrorAggregator()->isRowInvalid($rowNum);
  225. }
  226. $this->_validatedRows[$rowNum] = true;
  227. // BEHAVIOR_DELETE use specific validation logic
  228. if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) {
  229. if (!isset($rowData[self::COL_SKU])) {
  230. $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum);
  231. return false;
  232. }
  233. return true;
  234. }
  235. if (!$this->_getValidator(self::VALIDATOR_MAIN)->isValid($rowData)) {
  236. foreach ($this->_getValidator(self::VALIDATOR_MAIN)->getMessages() as $message) {
  237. $this->addRowError($message, $rowNum);
  238. }
  239. }
  240. if (isset($rowData[self::COL_SKU])) {
  241. $sku = $rowData[self::COL_SKU];
  242. }
  243. if (false === $sku) {
  244. $this->addRowError(ValidatorInterface::ERROR_ROW_IS_ORPHAN, $rowNum);
  245. }
  246. return !$this->getErrorAggregator()->isRowInvalid($rowNum);
  247. }
  248. /**
  249. * Create Advanced price data from raw data.
  250. *
  251. * @throws \Exception
  252. * @return bool Result of operation.
  253. */
  254. protected function _importData()
  255. {
  256. if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) {
  257. $this->deleteAdvancedPricing();
  258. } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $this->getBehavior()) {
  259. $this->replaceAdvancedPricing();
  260. } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $this->getBehavior()) {
  261. $this->saveAdvancedPricing();
  262. }
  263. return true;
  264. }
  265. /**
  266. * Save advanced pricing
  267. *
  268. * @return $this
  269. */
  270. public function saveAdvancedPricing()
  271. {
  272. $this->saveAndReplaceAdvancedPrices();
  273. return $this;
  274. }
  275. /**
  276. * Deletes Advanced price data from raw data.
  277. *
  278. * @return $this
  279. */
  280. public function deleteAdvancedPricing()
  281. {
  282. $this->_cachedSkuToDelete = null;
  283. $listSku = [];
  284. while ($bunch = $this->_dataSourceModel->getNextBunch()) {
  285. foreach ($bunch as $rowNum => $rowData) {
  286. $this->validateRow($rowData, $rowNum);
  287. if (!$this->getErrorAggregator()->isRowInvalid($rowNum)) {
  288. $rowSku = $rowData[self::COL_SKU];
  289. $listSku[] = $rowSku;
  290. }
  291. if ($this->getErrorAggregator()->hasToBeTerminated()) {
  292. $this->getErrorAggregator()->addRowToSkip($rowNum);
  293. }
  294. }
  295. }
  296. if ($listSku) {
  297. $this->deleteProductTierPrices(array_unique($listSku), self::TABLE_TIER_PRICE);
  298. $this->setUpdatedAt($listSku);
  299. }
  300. return $this;
  301. }
  302. /**
  303. * Replace advanced pricing
  304. *
  305. * @return $this
  306. */
  307. public function replaceAdvancedPricing()
  308. {
  309. $this->saveAndReplaceAdvancedPrices();
  310. return $this;
  311. }
  312. /**
  313. * Save and replace advanced prices
  314. *
  315. * @return $this
  316. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  317. * @SuppressWarnings(PHPMD.NPathComplexity)
  318. */
  319. protected function saveAndReplaceAdvancedPrices()
  320. {
  321. $behavior = $this->getBehavior();
  322. if (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $behavior) {
  323. $this->_cachedSkuToDelete = null;
  324. }
  325. $listSku = [];
  326. while ($bunch = $this->_dataSourceModel->getNextBunch()) {
  327. $tierPrices = [];
  328. foreach ($bunch as $rowNum => $rowData) {
  329. if (!$this->validateRow($rowData, $rowNum)) {
  330. $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum);
  331. continue;
  332. }
  333. if ($this->getErrorAggregator()->hasToBeTerminated()) {
  334. $this->getErrorAggregator()->addRowToSkip($rowNum);
  335. continue;
  336. }
  337. $rowSku = $rowData[self::COL_SKU];
  338. $listSku[] = $rowSku;
  339. if (!empty($rowData[self::COL_TIER_PRICE_WEBSITE])) {
  340. $tierPrices[$rowSku][] = [
  341. 'all_groups' => $rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS,
  342. 'customer_group_id' => $this->getCustomerGroupId(
  343. $rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP]
  344. ),
  345. 'qty' => $rowData[self::COL_TIER_PRICE_QTY],
  346. 'value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_FIXED
  347. ? $rowData[self::COL_TIER_PRICE] : 0,
  348. 'percentage_value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_PERCENT
  349. ? $rowData[self::COL_TIER_PRICE] : null,
  350. 'website_id' => $this->getWebSiteId($rowData[self::COL_TIER_PRICE_WEBSITE])
  351. ];
  352. }
  353. }
  354. if (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $behavior) {
  355. if ($listSku) {
  356. $this->processCountNewPrices($tierPrices);
  357. if ($this->deleteProductTierPrices(array_unique($listSku), self::TABLE_TIER_PRICE)) {
  358. $this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE);
  359. $this->setUpdatedAt($listSku);
  360. }
  361. }
  362. } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $behavior) {
  363. $this->processCountExistingPrices($tierPrices, self::TABLE_TIER_PRICE)
  364. ->processCountNewPrices($tierPrices);
  365. $this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE);
  366. if ($listSku) {
  367. $this->setUpdatedAt($listSku);
  368. }
  369. }
  370. }
  371. return $this;
  372. }
  373. /**
  374. * Save product prices.
  375. *
  376. * @param array $priceData
  377. * @param string $table
  378. * @return $this
  379. */
  380. protected function saveProductPrices(array $priceData, $table)
  381. {
  382. if ($priceData) {
  383. $tableName = $this->_resourceFactory->create()->getTable($table);
  384. $priceIn = [];
  385. $entityIds = [];
  386. $oldSkus = $this->retrieveOldSkus();
  387. foreach ($priceData as $sku => $priceRows) {
  388. if (isset($oldSkus[$sku])) {
  389. $productId = $oldSkus[$sku];
  390. foreach ($priceRows as $row) {
  391. $row[$this->getProductEntityLinkField()] = $productId;
  392. $priceIn[] = $row;
  393. $entityIds[] = $productId;
  394. }
  395. }
  396. }
  397. if ($priceIn) {
  398. $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value', 'percentage_value']);
  399. }
  400. }
  401. return $this;
  402. }
  403. /**
  404. * Deletes tier prices prices.
  405. *
  406. * @param array $listSku
  407. * @param string $table
  408. * @return boolean
  409. */
  410. protected function deleteProductTierPrices(array $listSku, $table)
  411. {
  412. $tableName = $this->_resourceFactory->create()->getTable($table);
  413. $productEntityLinkField = $this->getProductEntityLinkField();
  414. if ($tableName && $listSku) {
  415. if (!$this->_cachedSkuToDelete) {
  416. $this->_cachedSkuToDelete = $this->_connection->fetchCol(
  417. $this->_connection->select()
  418. ->from($this->_catalogProductEntity, $productEntityLinkField)
  419. ->where('sku IN (?)', $listSku)
  420. );
  421. }
  422. if ($this->_cachedSkuToDelete) {
  423. try {
  424. $this->countItemsDeleted += $this->_connection->delete(
  425. $tableName,
  426. $this->_connection->quoteInto($productEntityLinkField . ' IN (?)', $this->_cachedSkuToDelete)
  427. );
  428. return true;
  429. } catch (\Exception $e) {
  430. return false;
  431. }
  432. } else {
  433. $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, 0);
  434. return false;
  435. }
  436. }
  437. return false;
  438. }
  439. /**
  440. * Set updated_at for product
  441. *
  442. * @param array $listSku
  443. * @return $this
  444. */
  445. protected function setUpdatedAt(array $listSku)
  446. {
  447. $updatedAt = $this->dateTime->gmtDate('Y-m-d H:i:s');
  448. $this->_connection->update(
  449. $this->_catalogProductEntity,
  450. [\Magento\Catalog\Model\Category::KEY_UPDATED_AT => $updatedAt],
  451. $this->_connection->quoteInto('sku IN (?)', array_unique($listSku))
  452. );
  453. return $this;
  454. }
  455. /**
  456. * Get website id by code
  457. *
  458. * @param string $websiteCode
  459. * @return array|int|string
  460. */
  461. protected function getWebSiteId($websiteCode)
  462. {
  463. $result = $websiteCode == $this->_getValidator(self::VALIDATOR_WEBSITE)->getAllWebsitesValue() ||
  464. $this->_catalogData->isPriceGlobal() ? 0 : $this->_storeResolver->getWebsiteCodeToId($websiteCode);
  465. return $result;
  466. }
  467. /**
  468. * Get customer group id
  469. *
  470. * @param string $customerGroup
  471. * @return int
  472. */
  473. protected function getCustomerGroupId($customerGroup)
  474. {
  475. $customerGroups = $this->_getValidator(self::VALIDATOR_TEAR_PRICE)->getCustomerGroups();
  476. return $customerGroup == self::VALUE_ALL_GROUPS ? 0 : $customerGroups[$customerGroup];
  477. }
  478. /**
  479. * Retrieve product skus
  480. *
  481. * @return array
  482. */
  483. protected function retrieveOldSkus()
  484. {
  485. if ($this->_oldSkus === null) {
  486. $this->_oldSkus = $this->_connection->fetchPairs(
  487. $this->_connection->select()->from(
  488. $this->_catalogProductEntity,
  489. ['sku', $this->getProductEntityLinkField()]
  490. )
  491. );
  492. }
  493. return $this->_oldSkus;
  494. }
  495. /**
  496. * Count existing prices
  497. *
  498. * @param array $prices
  499. * @param string $table
  500. * @return $this
  501. */
  502. protected function processCountExistingPrices($prices, $table)
  503. {
  504. $oldSkus = $this->retrieveOldSkus();
  505. $existProductIds = array_intersect_key($oldSkus, $prices);
  506. if (!count($existProductIds)) {
  507. return $this;
  508. }
  509. $tableName = $this->_resourceFactory->create()->getTable($table);
  510. $productEntityLinkField = $this->getProductEntityLinkField();
  511. $existingPrices = $this->_connection->fetchAssoc(
  512. $this->_connection->select()->from(
  513. $tableName,
  514. ['value_id', $productEntityLinkField, 'all_groups', 'customer_group_id']
  515. )->where($productEntityLinkField . ' IN (?)', $existProductIds)
  516. );
  517. foreach ($existingPrices as $existingPrice) {
  518. foreach ($prices as $sku => $skuPrices) {
  519. if (isset($oldSkus[$sku]) && $existingPrice[$productEntityLinkField] == $oldSkus[$sku]) {
  520. $this->incrementCounterUpdated($skuPrices, $existingPrice);
  521. }
  522. }
  523. }
  524. return $this;
  525. }
  526. /**
  527. * Increment counter of updated items
  528. *
  529. * @param array $prices
  530. * @param array $existingPrice
  531. * @return void
  532. */
  533. protected function incrementCounterUpdated($prices, $existingPrice)
  534. {
  535. foreach ($prices as $price) {
  536. if ($existingPrice['all_groups'] == $price['all_groups']
  537. && $existingPrice['customer_group_id'] == $price['customer_group_id']
  538. ) {
  539. $this->countItemsUpdated++;
  540. }
  541. }
  542. }
  543. /**
  544. * Count new prices
  545. *
  546. * @param array $tierPrices
  547. * @return $this
  548. */
  549. protected function processCountNewPrices(array $tierPrices)
  550. {
  551. foreach ($tierPrices as $productPrices) {
  552. $this->countItemsCreated += count($productPrices);
  553. }
  554. $this->countItemsCreated -= $this->countItemsUpdated;
  555. return $this;
  556. }
  557. /**
  558. * Get product entity link field
  559. *
  560. * @return string
  561. * @throws \Exception
  562. */
  563. private function getProductEntityLinkField()
  564. {
  565. if (!$this->productEntityLinkField) {
  566. $this->productEntityLinkField = $this->getMetadataPool()
  567. ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
  568. ->getLinkField();
  569. }
  570. return $this->productEntityLinkField;
  571. }
  572. }