![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/app/code/Cnc/Catalog/Model/Indexer/Availability/ |
<?php /** * Copyright (c) 2020 Kaliop Digital Commerce (https://digitalcommerce.kaliop.com) All Rights Reserved. * https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) * Krzysztof Majkowski <[email protected]> <[email protected]> */ namespace Cnc\Catalog\Model\Indexer\Availability; use Cnc\Catalog\Model\Attribute\MsiAttributes; use Cnc\Checkout\Api\GetAssignedSourceCodesInterface; use Cnc\Checkout\Model\GetAssignedSourceCodes; use Ecombricks\InventoryInventorySales\Api\GetProductSalableQtyInterface; use Exception; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product\Action; use Magento\Catalog\Model\ResourceModel\Product as ResourceProduct; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\Eav\Model\Config; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\GroupedProduct\Model\Product\Type\Grouped; use Magento\Store\Api\StoreWebsiteRelationInterface; use Magento\Store\Model\StoreManagerInterface; abstract class AbstractAction { const ATTRIBUTE_CODE = 'cnc_availability'; const EAV_ATTRIBUTE_CODE = 'cnc_availability_icon'; /** * @var CollectionFactory */ private $collectionFactory; /** * @var ResourceProduct */ private $resourceProduct; /** * @var MsiAttributes */ private $msiAttributes; /** * @var GetAssignedSourceCodes */ private $getAssignedSourceCodes; /** * @var Config */ private $eavConfig; /** * @var GetProductSalableQtyInterface */ private $getProductSalableQty; /** * @var StoreManagerInterface */ private $storeManager; /** * @var Action */ private $productAction; /** * @var StoreWebsiteRelationInterface */ private $storeWebsiteRelation; /** * @var Grouped */ private $groupedType; /** * @var array */ private $cacheInstance = []; /** * @var array */ private $attributeValues = []; /** * @var array */ private $availabilityIconMapping = []; /** * @var array */ private $assignedSources = []; /** * @var bool */ private $isFullReindex = false; /** * @var array */ private $updateData = []; /** * @var array */ private $storesData = []; /** * AbstractAction constructor. * @param CollectionFactory $collectionFactory * @param ResourceProduct $resourceProduct * @param MsiAttributes $msiAttributes * @param GetAssignedSourceCodesInterface $getAssignedSourceCodes * @param GetProductSalableQtyInterface $getProductSalableQty * @param Action $productAction * @param Config $eavConfig * @param StoreManagerInterface $storeManager * @param StoreWebsiteRelationInterface $storeWebsiteRelation * @param Grouped $groupedType */ public function __construct( CollectionFactory $collectionFactory, ResourceProduct $resourceProduct, MsiAttributes $msiAttributes, GetAssignedSourceCodesInterface $getAssignedSourceCodes, GetProductSalableQtyInterface $getProductSalableQty, Action $productAction, Config $eavConfig, StoreManagerInterface $storeManager, StoreWebsiteRelationInterface $storeWebsiteRelation, Grouped $groupedType ) { $this->collectionFactory = $collectionFactory; $this->resourceProduct = $resourceProduct; $this->msiAttributes = $msiAttributes; $this->getAssignedSourceCodes = $getAssignedSourceCodes; $this->eavConfig = $eavConfig; $this->getProductSalableQty = $getProductSalableQty; $this->productAction = $productAction; $this->storeManager = $storeManager; $this->storeWebsiteRelation = $storeWebsiteRelation; $this->groupedType = $groupedType; } /** * @param array|null $ids * @throws Exception */ protected function _reindex(?array $ids) { $this->prepareWebsitesAndStores(); $this->updateData = []; $this->isFullReindex = ($ids == null || (is_array($ids) && count($ids) == 0)); if ($this->isFullReindex) { $this->prepareProductsData($this->getIds('simple')); $this->prepareProductsData($this->getIds('grouped')); } else { $this->prepareProductsData($ids); } foreach ($this->updateData as $storeId => $data) { foreach ($data as $attributeValue => $ids) { $this->productAction->updateAttributes( $ids, [self::EAV_ATTRIBUTE_CODE => $attributeValue], $storeId ); } } } /** * @param array|null $ids * @return bool * @throws Exception */ protected function prepareProductsData(?array $ids): bool { $groupedProducts = []; $collection = $this->collectionFactory->create(); if (is_array($ids) && count($ids)) { $collection->addFieldToFilter('entity_id', ['in' => $ids]); } /** @var Product $product */ foreach ($collection as $product) { if ($product->getTypeId() == 'simple') { $grouped = $this->prepareSimpleProduct($product); $groupedProducts = array_merge($groupedProducts, $grouped); } elseif ($product->getTypeId() == 'grouped') { $this->prepareGroupedProduct($product); } } if (!$this->isFullReindex && count($groupedProducts)) { $this->prepareProductsData(array_unique($groupedProducts)); } return true; } /** * Prepare index data for grouped product. * * @param Product $product */ protected function prepareGroupedProduct(Product $product) { $children = $this->groupedType->getAssociatedProductIds($product); $defaultAvailability = null; foreach ($this->storesData as $storeData) { $storeId = $storeData['store_id']; $minAvailability = null; foreach ($children as $childId) { $availability = $this->resourceProduct->getAttributeRawValue( $childId, self::EAV_ATTRIBUTE_CODE, $storeId ); if ($availability && $availability > 0) { if ($defaultAvailability == null) { $defaultAvailability = $availability; } elseif ($defaultAvailability > $availability) { $defaultAvailability = $availability; } if ($minAvailability == null) { $minAvailability = $availability; } elseif ($minAvailability > $availability) { $minAvailability = $availability; } } } if ($minAvailability !== null && $minAvailability > 0) { $this->addToUpdate($minAvailability, $product->getId(), $storeId); } } $this->addToUpdate($defaultAvailability, $product->getId(), 0); } /** * Prepare index data for simple product. * * @param Product $product * @return array * @throws LocalizedException * @throws NoSuchEntityException */ protected function prepareSimpleProduct(Product $product) { $groupedProducts = []; $assignedSources = $this->getAssignedSources(); $mapping = $this->getAvailabilityMapping(); $attributeId = $this->msiAttributes->getAttributeId(self::ATTRIBUTE_CODE); $defaultAvailability = null; foreach ($this->storesData as $storeData) { $storeId = $storeData['store_id']; $availabilityToSet = null; foreach ($assignedSources[$storeData['website_code']] as $source) { $availabilityValue = $this->getAvailabilityValue($product->getSku(), $attributeId, $source); try { $qty = $this->getQty($product->getSku(), $source); if ($availabilityValue && (!$availabilityToSet || $qty > 0)) { $availabilityToSet = $availabilityValue; } } catch (Exception $e) { // Nothing to do } } if ($availabilityToSet) { $this->addToUpdate($mapping[$availabilityToSet], $product->getId(), $storeId); if ($defaultAvailability == null || ($defaultAvailability > $mapping[$availabilityToSet])) { $defaultAvailability = $mapping[$availabilityToSet]; } } } if (!$this->isFullReindex) { $groupedProducts = $this->getParentIdsByChild($product->getId()); } $this->addToUpdate($defaultAvailability, $product->getId(), 0); return $groupedProducts; } /** * @param int|null $availability * @param int $productId * @param int $storeId */ private function addToUpdate(?int $availability, int $productId, int $storeId = 0) { if (!isset($this->updateData[$storeId])) { $this->updateData[$storeId] = []; } if ($availability) { if (!isset($this->updateData[$storeId][$availability])) { $this->updateData[$storeId][$availability] = []; } $this->updateData[$storeId][$availability] []= $productId; } } /** * Get option_id of product's cnc_availability. * * @param $sku * @param $attributeId * @param $sourceCode * @return mixed|null */ protected function getAvailabilityValue($sku, $attributeId, $sourceCode) { foreach ($this->getAttributeValues() as $customAttributeValues) { if ($customAttributeValues['sku'] == $sku && $customAttributeValues['attribute_id'] == $attributeId && $customAttributeValues['source_code'] == $sourceCode) { return $customAttributeValues['value']; } } return null; } /** * Get all values from msi_custom_attribute_value table. * * @return array */ protected function getAttributeValues(): array { if (!count($this->attributeValues)) { $attributeValues = $this->msiAttributes->getAttributeValues(); $attr = []; foreach ($attributeValues['items'] as $attributeValue) { $attr[$attributeValue['value_id']] = $attributeValue; $this->attributeValues = $attr; } } return $this->attributeValues; } /** * Get mapping from msi to eav attribute of cnc_availability attribute. * * @return array * @throws LocalizedException */ private function getAvailabilityMapping(): array { if (!count($this->availabilityIconMapping)) { $mapping = []; $attribute = $this->eavConfig->getAttribute(Product::ENTITY, self::EAV_ATTRIBUTE_CODE); $attribute->setStoreId(0); $eavOptions = $attribute->getSource()->getAllOptions(); $options = $this->msiAttributes->getDropdownOptions( $this->msiAttributes->getAttributeId(self::ATTRIBUTE_CODE) ); foreach ($eavOptions as $eavOption) { if (isset($options[$eavOption['label']])) { $mapping[$options[$eavOption['label']]] = $eavOption['value']; } } $this->availabilityIconMapping = $mapping; } return $this->availabilityIconMapping; } /** * Get assigned source per website. * * @return array * @throws NoSuchEntityException */ private function getAssignedSources(): array { if (!count($this->assignedSources)) { $websites = $this->storeManager->getWebsites(false); $assignedSources = []; foreach ($websites as $website) { $assignedSources[$website->getCode()] = $this->getAssignedSourceCodes->execute($website->getCode()); } $this->assignedSources = $assignedSources; } return $this->assignedSources; } /** * Get available quantity for product in source. * * @param string $sku * @param string $source * @return float|mixed * @throws LocalizedException * @throws InputException */ private function getQty(string $sku, string $source): float { $key = implode('-', ['qty', $sku, $source]); if (!isset($this->cacheInstance[$key])) { $this->cacheInstance[$key] = $this->getProductSalableQty->execute($sku, $source); } return $this->cacheInstance[$key]; } /** * Get parent ids by child id. * * @param int $childId * @return array */ private function getParentIdsByChild(int $childId): array { $key = implode('-', ['parent-ids-by-child', $childId]); if (!isset($this->cacheInstance[$key])) { $this->cacheInstance[$key] = $this->groupedType->getParentIdsByChild($childId); } return (is_array($this->cacheInstance[$key]) ? $this->cacheInstance[$key] : []); } /** * Prepare websites and stores data. */ private function prepareWebsitesAndStores() { $data = []; $websites = $this->storeManager->getWebsites(false); foreach ($websites as $website) { $stores = $this->storeWebsiteRelation->getStoreByWebsiteId($website->getId()); foreach ($stores as $storeId) { $data []= [ 'store_id' => $storeId, 'website_code' => $website->getCode() ]; } } $this->storesData = $data; } /** * Get ids of products by type id. * * @param string $typeId * @return array */ private function getIds(string $typeId): array { $collection = $this->collectionFactory->create(); $collection->addFieldToFilter('type_id', $typeId); return $collection->getAllIds(); } }