Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
AdvancedPricing.php
Go to the documentation of this file.
1 <?php
7 
11 
19 class AdvancedPricing extends \Magento\ImportExport\Model\Import\Entity\AbstractEntity
20 {
21  const VALUE_ALL_GROUPS = 'ALL GROUPS';
22 
23  const VALUE_ALL_WEBSITES = 'All Websites';
24 
25  const COL_SKU = 'sku';
26 
27  const COL_TIER_PRICE_WEBSITE = 'tier_price_website';
28 
29  const COL_TIER_PRICE_CUSTOMER_GROUP = 'tier_price_customer_group';
30 
31  const COL_TIER_PRICE_QTY = 'tier_price_qty';
32 
33  const COL_TIER_PRICE = 'tier_price';
34 
35  const COL_TIER_PRICE_PERCENTAGE_VALUE = 'percentage_value';
36 
37  const COL_TIER_PRICE_TYPE = 'tier_price_value_type';
38 
39  const TIER_PRICE_TYPE_FIXED = 'Fixed';
40 
41  const TIER_PRICE_TYPE_PERCENT = 'Discount';
42 
43  const TABLE_TIER_PRICE = 'catalog_product_entity_tier_price';
44 
46 
47  const ENTITY_TYPE_CODE = 'advanced_pricing';
48 
49  const VALIDATOR_MAIN = 'validator';
50 
51  const VALIDATOR_WEBSITE = 'validator_website';
52 
53  const VALIDATOR_TEAR_PRICE = 'validator_tear_price';
54 
60  protected $_messageTemplates = [
61  ValidatorInterface::ERROR_INVALID_WEBSITE => 'Invalid value in Website column (website does not exists?)',
62  ValidatorInterface::ERROR_SKU_IS_EMPTY => 'SKU is empty',
63  ValidatorInterface::ERROR_SKU_NOT_FOUND_FOR_DELETE => 'Product with specified SKU not found',
64  ValidatorInterface::ERROR_INVALID_TIER_PRICE_QTY => 'Tier Price data price or quantity value is invalid',
65  ValidatorInterface::ERROR_INVALID_TIER_PRICE_SITE => 'Tier Price data website is invalid',
66  ValidatorInterface::ERROR_INVALID_TIER_PRICE_GROUP => 'Tier Price customer group is invalid',
67  ValidatorInterface::ERROR_INVALID_TIER_PRICE_TYPE => 'Value for \'tier_price_value_type\' ' .
68  'attribute contains incorrect value, acceptable values are Fixed, Discount',
69  ValidatorInterface::ERROR_TIER_DATA_INCOMPLETE => 'Tier Price data is incomplete',
70  ValidatorInterface::ERROR_INVALID_ATTRIBUTE_DECIMAL =>
71  'Value for \'%s\' attribute contains incorrect value, acceptable values are in decimal format',
72  ];
73 
79  protected $needColumnCheck = true;
80 
86  protected $validColumnNames = [
93  ];
94 
100  protected $logInHistory = true;
101 
105  protected $_resourceFactory;
106 
110  protected $_catalogData;
111 
115  protected $_productModel;
116 
120  protected $_storeResolver;
121 
125  protected $_importProduct;
126 
130  protected $_validators = [];
131 
136 
140  protected $_oldSkus = null;
141 
148 
155 
159  protected $dateTime;
160 
166  private $productEntityLinkField;
167 
189  public function __construct(
190  \Magento\Framework\Json\Helper\Data $jsonHelper,
191  \Magento\ImportExport\Helper\Data $importExportData,
192  \Magento\ImportExport\Model\ResourceModel\Import\Data $importData,
193  \Magento\Eav\Model\Config $config,
195  \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper,
196  \Magento\Framework\Stdlib\StringUtils $string,
198  \Magento\Framework\Stdlib\DateTime\DateTime $dateTime,
199  \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory $resourceFactory,
200  \Magento\Catalog\Model\Product $productModel,
201  \Magento\Catalog\Helper\Data $catalogData,
202  \Magento\CatalogImportExport\Model\Import\Product\StoreResolver $storeResolver,
203  ImportProduct $importProduct,
204  AdvancedPricing\Validator $validator,
205  AdvancedPricing\Validator\Website $websiteValidator,
206  AdvancedPricing\Validator\TierPrice $tierPriceValidator
207  ) {
208  $this->dateTime = $dateTime;
209  $this->jsonHelper = $jsonHelper;
210  $this->_importExportData = $importExportData;
211  $this->_resourceHelper = $resourceHelper;
212  $this->_dataSourceModel = $importData;
213  $this->_connection = $resource->getConnection('write');
214  $this->_resourceFactory = $resourceFactory;
215  $this->_productModel = $productModel;
216  $this->_catalogData = $catalogData;
217  $this->_storeResolver = $storeResolver;
218  $this->_importProduct = $importProduct;
219  $this->_validators[self::VALIDATOR_MAIN] = $validator->init($this);
220  $this->_catalogProductEntity = $this->_resourceFactory->create()->getTable('catalog_product_entity');
221  $this->_oldSkus = $this->retrieveOldSkus();
222  $this->_validators[self::VALIDATOR_WEBSITE] = $websiteValidator;
223  $this->_validators[self::VALIDATOR_TEAR_PRICE] = $tierPriceValidator;
224  $this->errorAggregator = $errorAggregator;
225 
226  foreach (array_merge($this->errorMessageTemplates, $this->_messageTemplates) as $errorCode => $message) {
227  $this->getErrorAggregator()->addErrorMessageTemplate($errorCode, $message);
228  }
229  }
230 
237  protected function _getValidator($type)
238  {
239  return $this->_validators[$type];
240  }
241 
247  public function getEntityTypeCode()
248  {
249  return 'advanced_pricing';
250  }
251 
259  public function validateRow(array $rowData, $rowNum)
260  {
261  $sku = false;
262  if (isset($this->_validatedRows[$rowNum])) {
263  return !$this->getErrorAggregator()->isRowInvalid($rowNum);
264  }
265  $this->_validatedRows[$rowNum] = true;
266  // BEHAVIOR_DELETE use specific validation logic
267  if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) {
268  if (!isset($rowData[self::COL_SKU])) {
269  $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum);
270  return false;
271  }
272  return true;
273  }
274  if (!$this->_getValidator(self::VALIDATOR_MAIN)->isValid($rowData)) {
275  foreach ($this->_getValidator(self::VALIDATOR_MAIN)->getMessages() as $message) {
276  $this->addRowError($message, $rowNum);
277  }
278  }
279  if (isset($rowData[self::COL_SKU])) {
280  $sku = $rowData[self::COL_SKU];
281  }
282  if (false === $sku) {
283  $this->addRowError(ValidatorInterface::ERROR_ROW_IS_ORPHAN, $rowNum);
284  }
285  return !$this->getErrorAggregator()->isRowInvalid($rowNum);
286  }
287 
294  protected function _importData()
295  {
296  if (\Magento\ImportExport\Model\Import::BEHAVIOR_DELETE == $this->getBehavior()) {
297  $this->deleteAdvancedPricing();
299  $this->replaceAdvancedPricing();
301  $this->saveAdvancedPricing();
302  }
303 
304  return true;
305  }
306 
312  public function saveAdvancedPricing()
313  {
315  return $this;
316  }
317 
323  public function deleteAdvancedPricing()
324  {
325  $this->_cachedSkuToDelete = null;
326  $listSku = [];
327  while ($bunch = $this->_dataSourceModel->getNextBunch()) {
328  foreach ($bunch as $rowNum => $rowData) {
329  $this->validateRow($rowData, $rowNum);
330  if (!$this->getErrorAggregator()->isRowInvalid($rowNum)) {
331  $rowSku = $rowData[self::COL_SKU];
332  $listSku[] = $rowSku;
333  }
334  if ($this->getErrorAggregator()->hasToBeTerminated()) {
335  $this->getErrorAggregator()->addRowToSkip($rowNum);
336  }
337  }
338  }
339  if ($listSku) {
340  $this->deleteProductTierPrices(array_unique($listSku), self::TABLE_TIER_PRICE);
341  $this->setUpdatedAt($listSku);
342  }
343  return $this;
344  }
345 
351  public function replaceAdvancedPricing()
352  {
354  return $this;
355  }
356 
364  protected function saveAndReplaceAdvancedPrices()
365  {
366  $behavior = $this->getBehavior();
367  if (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $behavior) {
368  $this->_cachedSkuToDelete = null;
369  }
370  $listSku = [];
371  while ($bunch = $this->_dataSourceModel->getNextBunch()) {
372  $tierPrices = [];
373  foreach ($bunch as $rowNum => $rowData) {
374  if (!$this->validateRow($rowData, $rowNum)) {
375  $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, $rowNum);
376  continue;
377  }
378  if ($this->getErrorAggregator()->hasToBeTerminated()) {
379  $this->getErrorAggregator()->addRowToSkip($rowNum);
380  continue;
381  }
382 
383  $rowSku = $rowData[self::COL_SKU];
384  $listSku[] = $rowSku;
385  if (!empty($rowData[self::COL_TIER_PRICE_WEBSITE])) {
386  $tierPrices[$rowSku][] = [
387  'all_groups' => $rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP] == self::VALUE_ALL_GROUPS,
388  'customer_group_id' => $this->getCustomerGroupId(
389  $rowData[self::COL_TIER_PRICE_CUSTOMER_GROUP]
390  ),
391  'qty' => $rowData[self::COL_TIER_PRICE_QTY],
392  'value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_FIXED
393  ? $rowData[self::COL_TIER_PRICE] : 0,
394  'percentage_value' => $rowData[self::COL_TIER_PRICE_TYPE] === self::TIER_PRICE_TYPE_PERCENT
395  ? $rowData[self::COL_TIER_PRICE] : null,
396  'website_id' => $this->getWebSiteId($rowData[self::COL_TIER_PRICE_WEBSITE])
397  ];
398  }
399  }
400  if (\Magento\ImportExport\Model\Import::BEHAVIOR_REPLACE == $behavior) {
401  if ($listSku) {
403  if ($this->deleteProductTierPrices(array_unique($listSku), self::TABLE_TIER_PRICE)) {
404  $this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE);
405  $this->setUpdatedAt($listSku);
406  }
407  }
408  } elseif (\Magento\ImportExport\Model\Import::BEHAVIOR_APPEND == $behavior) {
409  $this->processCountExistingPrices($tierPrices, self::TABLE_TIER_PRICE)
410  ->processCountNewPrices($tierPrices);
411  $this->saveProductPrices($tierPrices, self::TABLE_TIER_PRICE);
412  if ($listSku) {
413  $this->setUpdatedAt($listSku);
414  }
415  }
416  }
417  return $this;
418  }
419 
427  protected function saveProductPrices(array $priceData, $table)
428  {
429  if ($priceData) {
430  $tableName = $this->_resourceFactory->create()->getTable($table);
431  $priceIn = [];
432  $entityIds = [];
433  $oldSkus = $this->retrieveOldSkus();
434  foreach ($priceData as $sku => $priceRows) {
435  if (isset($oldSkus[$sku])) {
436  $productId = $oldSkus[$sku];
437  foreach ($priceRows as $row) {
438  $row[$this->getProductEntityLinkField()] = $productId;
439  $priceIn[] = $row;
440  $entityIds[] = $productId;
441  }
442  }
443  }
444  if ($priceIn) {
445  $this->_connection->insertOnDuplicate($tableName, $priceIn, ['value', 'percentage_value']);
446  }
447  }
448  return $this;
449  }
450 
458  protected function deleteProductTierPrices(array $listSku, $table)
459  {
460  $tableName = $this->_resourceFactory->create()->getTable($table);
461  $productEntityLinkField = $this->getProductEntityLinkField();
462  if ($tableName && $listSku) {
463  if (!$this->_cachedSkuToDelete) {
464  $this->_cachedSkuToDelete = $this->_connection->fetchCol(
465  $this->_connection->select()
466  ->from($this->_catalogProductEntity, $productEntityLinkField)
467  ->where('sku IN (?)', $listSku)
468  );
469  }
470  if ($this->_cachedSkuToDelete) {
471  try {
472  $this->countItemsDeleted += $this->_connection->delete(
473  $tableName,
474  $this->_connection->quoteInto($productEntityLinkField . ' IN (?)', $this->_cachedSkuToDelete)
475  );
476  return true;
477  } catch (\Exception $e) {
478  return false;
479  }
480  } else {
481  $this->addRowError(ValidatorInterface::ERROR_SKU_IS_EMPTY, 0);
482  return false;
483  }
484  }
485  return false;
486  }
487 
494  protected function setUpdatedAt(array $listSku)
495  {
496  $updatedAt = $this->dateTime->gmtDate('Y-m-d H:i:s');
497  $this->_connection->update(
498  $this->_catalogProductEntity,
499  [\Magento\Catalog\Model\Category::KEY_UPDATED_AT => $updatedAt],
500  $this->_connection->quoteInto('sku IN (?)', array_unique($listSku))
501  );
502  return $this;
503  }
504 
511  protected function getWebSiteId($websiteCode)
512  {
513  $result = $websiteCode == $this->_getValidator(self::VALIDATOR_WEBSITE)->getAllWebsitesValue() ||
514  $this->_catalogData->isPriceGlobal() ? 0 : $this->_storeResolver->getWebsiteCodeToId($websiteCode);
515  return $result;
516  }
517 
524  protected function getCustomerGroupId($customerGroup)
525  {
526  $customerGroups = $this->_getValidator(self::VALIDATOR_TEAR_PRICE)->getCustomerGroups();
527  return $customerGroup == self::VALUE_ALL_GROUPS ? 0 : $customerGroups[$customerGroup];
528  }
529 
535  protected function retrieveOldSkus()
536  {
537  if ($this->_oldSkus === null) {
538  $this->_oldSkus = $this->_connection->fetchPairs(
539  $this->_connection->select()->from(
540  $this->_catalogProductEntity,
541  ['sku', $this->getProductEntityLinkField()]
542  )
543  );
544  }
545  return $this->_oldSkus;
546  }
547 
556  {
557  $oldSkus = $this->retrieveOldSkus();
558  $existProductIds = array_intersect_key($oldSkus, $prices);
559  if (!count($existProductIds)) {
560  return $this;
561  }
562 
563  $tableName = $this->_resourceFactory->create()->getTable($table);
564  $productEntityLinkField = $this->getProductEntityLinkField();
565  $existingPrices = $this->_connection->fetchAssoc(
566  $this->_connection->select()->from(
567  $tableName,
568  ['value_id', $productEntityLinkField, 'all_groups', 'customer_group_id']
569  )->where($productEntityLinkField . ' IN (?)', $existProductIds)
570  );
571  foreach ($existingPrices as $existingPrice) {
572  foreach ($prices as $sku => $skuPrices) {
573  if (isset($oldSkus[$sku]) && $existingPrice[$productEntityLinkField] == $oldSkus[$sku]) {
574  $this->incrementCounterUpdated($skuPrices, $existingPrice);
575  }
576  }
577  }
578 
579  return $this;
580  }
581 
589  protected function incrementCounterUpdated($prices, $existingPrice)
590  {
591  foreach ($prices as $price) {
592  if ($existingPrice['all_groups'] == $price['all_groups']
593  && $existingPrice['customer_group_id'] == $price['customer_group_id']
594  ) {
595  $this->countItemsUpdated++;
596  }
597  }
598  }
599 
606  protected function processCountNewPrices(array $tierPrices)
607  {
608  foreach ($tierPrices as $productPrices) {
609  $this->countItemsCreated += count($productPrices);
610  }
611  $this->countItemsCreated -= $this->countItemsUpdated;
612 
613  return $this;
614  }
615 
622  private function getProductEntityLinkField()
623  {
624  if (!$this->productEntityLinkField) {
625  $this->productEntityLinkField = $this->getMetadataPool()
626  ->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class)
627  ->getLinkField();
628  }
629  return $this->productEntityLinkField;
630  }
631 }
$tableName
Definition: trigger.php:13
elseif(isset( $params[ 'redirect_parent']))
Definition: iframe.phtml:17
$config
Definition: fraud_order.php:17
$resource
Definition: bulk.php:12
$price
$message
$type
Definition: item.phtml:13
addRowError( $errorCode, $errorRowNum, $colName=null, $errorMessage=null, $errorLevel=ProcessingError::ERROR_LEVEL_CRITICAL, $errorDescription=null)
__construct(\Magento\Framework\Json\Helper\Data $jsonHelper, \Magento\ImportExport\Helper\Data $importExportData, \Magento\ImportExport\Model\ResourceModel\Import\Data $importData, \Magento\Eav\Model\Config $config, \Magento\Framework\App\ResourceConnection $resource, \Magento\ImportExport\Model\ResourceModel\Helper $resourceHelper, \Magento\Framework\Stdlib\StringUtils $string, ProcessingErrorAggregatorInterface $errorAggregator, \Magento\Framework\Stdlib\DateTime\DateTime $dateTime, \Magento\CatalogImportExport\Model\Import\Proxy\Product\ResourceModelFactory $resourceFactory, \Magento\Catalog\Model\Product $productModel, \Magento\Catalog\Helper\Data $catalogData, \Magento\CatalogImportExport\Model\Import\Product\StoreResolver $storeResolver, ImportProduct $importProduct, AdvancedPricing\Validator $validator, AdvancedPricing\Validator\Website $websiteValidator, AdvancedPricing\Validator\TierPrice $tierPriceValidator)
$productModel
$table
Definition: trigger.php:14
if(!isset($_GET['website_code'])) $websiteCode
Definition: website.php:11