Spamworldpro Mini Shell
Spamworldpro


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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //home/corals/old/app/code/Cnc/Catalog/Model/Indexer/Availability/AbstractAction.php
<?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();
    }
}

Spamworldpro Mini