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/Orders.php
<?php
namespace Wbs24\Exchange1c;

use Bitrix\Main\Type\DateTime;

class Orders implements Interfaces\Orders
{
    protected $wrappers;
    protected $Catalog;

    public const LIMIT = 50;

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

    public function getOrders(array $param = []): array
    {
        $orders = $this->getOrdersByParam($param);
        $convertedOrders = $this->convertOrders($orders);

        return $convertedOrders;
    }

    public function getOrdersByShippingDate(array $param = []): array
    {
        $orders = [];
        $from = $param['from'] ?? false;
        $to = $param['to'] ?? false;
        $shippingDatePropertyId = $param['shipping_date_property_id'] ?? false;

        if ($from && $to && $shippingDatePropertyId) {
            $ids = $this->getOrdersIdsByShippingDate($from, $to, $shippingDatePropertyId);
            if ($ids) {
                unset($param['from']);
                unset($param['to']);
                $param['orderIds'] = $ids;
                $orders = $this->getOrders($param);
                $orders = $this->validateOrders($orders);
            }
        }

        return $orders;
    }

    protected function getOrdersIdsByShippingDate(string $from, string $to, int $shippingDatePropertyId): array
    {
        $ids = [];

        $dateList = $this->getDateListByRange($from, $to);
        $ids = $this->getOrdersIdsByDateList($dateList, $shippingDatePropertyId);

        return $ids;
    }

    // дополнительная валидация заказов
    // не отправлять те, которые отменены до 8:00 даты отгрузки
    protected function validateOrders($orders)
    {
        $validatedOrders = [];
        foreach ($orders as $order) {
            $canceled = $order['canceled'] ?? false;
            $canceledTimestamp = $order['canceledTimestamp'] ?? false;
            $shipmentDate = $order['properties']['shipmentDate'] ?? false;

            if (
                $canceled == 'Y'
                && $canceledTimestamp
                && $shipmentDate
            ) {
                $shipmentDateTimestamp = strtotime($shipmentDate.' 08:00:00');
                if ($canceledTimestamp < $shipmentDateTimestamp) {
                    continue;
                }
            }

            $validatedOrders[] = $order;
        }

        return $validatedOrders;
    }

    protected function getDateListByRange(string $from, string $to): array
    {
        $list = [];
        $maxList = 31; // максимальное возможное кол-во дат на выходе не более 31 (искусственное ограничение для оптимизации нагрузки)
        $dateFormat = 'd.m.Y';

        if ($from && $to) {
            $currentTimestamp = $fromTimestamp = strtotime($from);
            $toTimestamp = strtotime($to);
            for ($i = 0; $i < $maxList; $i++) {
                $currentDate = date($dateFormat, $currentTimestamp);
                $list[] = $currentDate;
                if ($currentDate == date($dateFormat, $toTimestamp)) break;

                $currentTimestamp += 86400;
            }
        }

        return $list;
    }

    // прямой запрос к БД, т.к. через D7 нет возможности реализовать
    protected function getOrdersIdsByDateList(array $dateList, int $shippingDatePropertyId): array
    {
        $ids = [];

        $result = $this->Db->get(
            'b_sale_order_props_value',
            [
                'ORDER_PROPS_ID' => $shippingDatePropertyId,
                'VALUE' => $dateList,
            ]
        );
        foreach ($result as $item) {
            $id = $item['ORDER_ID'] ?? false;
            if ($id) $ids[] = $id;
        }

        return $ids;
    }

    protected function getOrdersByParam(array $param = []): array
    {
        $orders = [];
        $select = array_merge(['ID', 'XML_ID', 'STATUS_ID', 'USER_ID', 'DATE_CANCELED', 'CANCELED', 'DATE_STATUS', 'DATE_INSERT', 'PRICE_DELIVERY'], $param['select'] ?? []);
        $siteId = $param['siteId'] ?? false;
        $fromTime = $param['fromTime'] ?? time();
        $from = $param['from'] ?? false;
        $to = $param['to'] ?? false;
        $orderIds = $param['orderIds'] ?? false;
        $offset = $param['offset'] ?? 0;
        $limit = $param['limit'] ?? self::LIMIT;
        $notCheckPermissions = $param['not_check_permissions'] ?? false;
        $i = 0;
        $foundAllowedProducts = false;
        //$allowedProductIds = $this->Catalog->getAllowedProductIds(); // получить ids разрешенных товаров
        $filter = [];

        if ($siteId) {
            $filter['LID'] = $siteId;
        }

        if ($from || $to) {
            // режим получения данных по дате в формате дд.мм.гггг чч:мм:сс
            if ($from) $filter['>=DATE_INSERT'] = $from;
            if ($to) $filter['<=DATE_INSERT'] = $to;
        } elseif ($orderIds) {
            // режим получения заказов по списку ID
            $filter['ID'] = $orderIds;
        } else {
            // режим получения данных по timestamp
            $filter = [
                '>=DATE_INSERT' => DateTime::createFromTimestamp($fromTime),
            ];
        }

        if ($limit > 500) $limit = 500;

        $result = $this->wrappers->Order->getList([
            'select' => $select,
            'filter' => $filter,
            'order' => ['ID' => 'ASC'],
            'limit' => $limit,
            'offset' => $offset,
        ]);
        while ($orderFields = $result->fetch()) {
            $orderId = $orderFields['ID'];
            $i++;

            $orderFields['customer'] = $this->getCustomerInfo($orderId);
            $orderFields['customer']['customerId'] = $this->getCustomerId($orderFields['customer']);
            $orderFields['customer']['userId'] = $orderFields['USER_ID'] ?? '';

            $orderFields['properties'] = $this->getOrderInfo($orderId);

            $orderFields['source'] = $this->getSource($orderId);

            $products = $this->getProductsWithKitElementsByOrderId($orderId); // вместе с инфо о составе комплектов
            //$products = $this->getProductsByOrderId($orderId); // без инфо о комплектах

            $products = $this->addStocksInfoFromAvailableQuantity($products); // для работы с доступным кол-вом
            //$products = $this->addStocksInfo($products, $orderFields); // для даботы с складами

            // добавить доставку как товар, если есть
            $deliveryPrice = intval($orderFields['PRICE_DELIVERY']);
            if ($deliveryPrice) {
                $products[] = [
                    'ID' => NULL,
                    'PRODUCT_ID' => NULL,
                    'SET_PARENT_ID' => NULL,
                    'NAME' => 'Доставка',
                    'PRICE' => $deliveryPrice,
                    'QUANTITY' => '1',
                    'sku' => 'DELIVERY',
                    'stocks' => ['quantity' => 1],
                ];
            }

            $orderFields['products'] = $products;

            // var_export($orderFields); exit; // debug

            // для фильтрации заказов по разрешенным товарам
            /* if (
                !$notCheckPermissions
                && !$this->hasAllowedProducts($products, $allowedProductIds)
            ) continue; */

            $orders[] = $orderFields;
        }

        return $orders;
    }

    protected function getSource($orderId)
    {
        $order = $this->wrappers->Order->load($orderId);
        $code = 'site';
        $xmlId = $order->getField('XML_ID');

        if (substr($xmlId, 0, 9) == 'YAMARKET_') $code = 'yamarket_marketp_dbs';
        if (substr($xmlId, 0, 4) == 'OZON') $code = 'ozon_market';
        if (substr($xmlId, 0, 6) == 'SBERMM') $code = 'sbermm';
        if (substr($xmlId, 0, 2) == 'WB') $code = 'wildberries';

        return $code;
    }

    protected function getProductsByOrderId(int $orderId): array
    {
        $products = [];

        $result = $this->wrappers->Basket->getList([
            'select' => ['ID', 'PRODUCT_ID', 'NAME', 'PRICE', 'QUANTITY'],
            'filter' => [
                'ORDER_ID' => $orderId,
                'SET_PARENT_ID' => '',
            ],
        ]);
        while($productInBasket = $result->fetch()) {
            $products[] = $this->addProductMeta($productInBasket);
        }

        return $products;
    }

    protected function getProductsWithKitElementsByOrderId(int $orderId): array
    {
        $products = [];
        $subProducts = [];

        $result = $this->wrappers->Basket->getList([
            'select' => ['ID', 'PRODUCT_ID', 'SET_PARENT_ID', 'NAME', 'PRICE', 'QUANTITY'],
            'filter' => [
                'ORDER_ID' => $orderId,
            ],
        ]);
        while ($productInBasket = $result->fetch()) {
            $basketId = $productInBasket['ID'];
            $parentId = $productInBasket['SET_PARENT_ID'] ?? '';

            if ($parentId) {
                $subProducts[$basketId] = $this->addProductMeta($productInBasket);
            } else {
                $products[$basketId] = $this->addProductMeta($productInBasket);
            }
        }

        // переместить продукты из состава комплекта в комплект-родитель
        foreach ($subProducts as $basketId => $subProd) {
            $parentId = $subProd['SET_PARENT_ID'] ?? '';
            if (isset($products[$parentId])) {
                $products[$parentId]['kitElements'][$basketId] = $subProd;
            }
        }

        return $products;
    }

    protected function addProductMeta($productInBasket)
    {
        $productId = $productInBasket['PRODUCT_ID'];
        $productMeta = $this->Catalog->getProductMeta($productId);
        foreach ($productMeta as $key => $value) {
            if ($value) $productInBasket[$key] = $value;
        }

        return $productInBasket;
    }

    protected function addStocksInfoFromAvailableQuantity(array $products): array
    {
        $productsWithStocks = [];

        foreach ($products as $product) {
            $product['stocks'] = [
                'quantity' => intval($product['QUANTITY']),
            ];
            $productsWithStocks[] = $product;
        }

        return $productsWithStocks;
    }

    protected function addStocksInfo(array $products, array $orderFields): array
    {
        $warehouseInfo = $this->getWarehouseInfo($products, $orderFields);
        $productsWithStocks = [];

        foreach ($products as $product) {
            $product['stocks'] = [
                'stockId' => $warehouseInfo['warehouseId'] ?? 0,
                'stockName' => $warehouseInfo['warehouseName'] ?? '',
                'quantity' => intval($product['QUANTITY']),
            ];
            $productsWithStocks[] = $product;
        }

        return $productsWithStocks;
    }

    protected function getCustomerInfo(int $orderId): array
    {
        $propCodeToType = [
            'FIO' => 'name',
            'EMAIL' => 'email',
            'PHONE' => 'phone',
            'CITY' => 'city',
            'ADDRESS' => 'address',
        ];

        return $this->getProperties($orderId, $propCodeToType);
    }

    /*
    CREATE TABLE `wbs24_exchange1c_customers` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    `phone` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `name_phone` (`name`,`phone`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    */
    protected function getCustomerId(array $customerInfo): int
    {
        $table = 'wbs24_exchange1c_customers';
        $name = trim(mb_strtoupper($customerInfo['name'] ?? ''));
        $phone = str_replace(
            ['+', ' ', '(', ')', '-'],
            '',
            $customerInfo['phone'] ?? ''
        );
        if (!$name && !$phone) return false;
        $customerId = false;

        $foundCustomer = $this->Db->getSingle($table, [
            'name' => $name,
            'phone' => $phone,
        ]);
        if ($foundCustomer) {
            $customerId = $foundCustomer['id'];
        } else {
            $this->Db->set($table, [
                'name' => $name,
                'phone' => $phone,
            ]);

            $foundCustomer = $this->Db->getSingle($table, [
                'name' => $name,
                'phone' => $phone,
            ]);
            if ($foundCustomer) $customerId = $foundCustomer['id'];
        }

        return $customerId;
    }

    protected function getOrderInfo(int $orderId): array
    {
        $propCodeToType = [
            'EXTERNAL_ID' => 'orderExternalId', // символьный код свойства заказа - внешний номер заказа
            'SHIPPING_DATE' => 'shipmentDate', // символьный код свойства заказа - дата откгрузки
        ];

        return $this->getProperties($orderId, $propCodeToType);
    }

    protected function getProperties(int $orderId, array $propCodeToType): array
    {
        $info = [];

        $result = $this->wrappers->PropertyValueCollection->getList([
            'select' => ['CODE', 'VALUE'],
            'filter' => [
                '=ORDER_ID' => $orderId,
            ],
        ]);
        while ($prop = $result->fetch()) {
            $code = $prop['CODE'];
            $value = $prop['VALUE'];
            $type = $propCodeToType[$code] ?? false;

            if ($type && $value) {
                $info[$type] = $value;
            }
        }

        return $info;
    }

    protected function hasAllowedProducts(array $products, array $allowedProductIds): bool
    {
        $has = false;
        foreach ($products as $product) {
            $productId = $product['PRODUCT_ID'] ?? false;
            if (in_array($productId, $allowedProductIds)) {
                $has = true;
                break;
            }
        }

        return $has;
    }

    /**
     * Получение ID склада.
     * При добавлении складов, нужно добавить логику в эту функцию.
     */
    protected function getWarehouseInfo(array $products, array $orderFields): array
    {
        $xmlId = $orderFields['XML_ID'] ?? '';
        $warehousesInfo = $this->Catalog->getWarehousesInfo();

        // temp - для тестового режима (если разрешены склады 3 и 4)
        if (isset($warehousesInfo[3]) && isset($warehousesInfo[4])) {
            $warehousesInfo[1] = $warehousesInfo[3];
            $warehousesInfo[2] = $warehousesInfo[4];
        }

        $warehouseId = 2; // по умолчанию для маркетплейсов

        if (substr($xmlId, 0, 3) == 'bx_') $warehouseId = 1; // для заказов с сайта

        return [
            'warehouseId' => $warehousesInfo[$warehouseId]['XML_ID'] ?? '',
            'warehouseName' => $warehousesInfo[$warehouseId]['TITLE'] ?? '',
        ];
    }

    protected function convertOrders(array $orders): array
    {
        $convertedOrders = [];

        foreach ($orders as $order) {
            [
                'products' => $products,
                'orderSum' => $orderSum,
            ] = $this->convertProducts($order['products']);

            $convertedOrder = [
                'orderId' => $order['ID'],
                'xmlId' => $order['XML_ID'],
                'status' => $order['STATUS_ID'],
                'statusTimestamp' => $this->getStringFromDateTimeObject($order['DATE_STATUS'] ?? false),
                'canceled' => $order['CANCELED'],
                'canceledTimestamp' => $this->getStringFromDateTimeObject($order['DATE_CANCELED'] ?? false),
                'createdTimestamp' => $this->getStringFromDateTimeObject($order['DATE_INSERT'] ?? false),
                'orderSum' => $orderSum,
                'properties' => $order['properties'],
                'customer' => $order['customer'],
                'source' => $order['source'],
                'products' => $products,
            ];

            $convertedOrders[] = $convertedOrder;
        }

        return $convertedOrders;
    }

    protected function convertProducts(array $products, bool $useKitElements = false): array
    {
        $convertedProducts = [];
        $convertProductFields = [
            'productId' => 'PRODUCT_ID',
            'sku' => 'sku',
            //'color' => 'color',
            //'size' => 'size',
            //'barcode' => 'barcode',
            //'packageRatio' => 'packageRatio',
        ];
        if ($useKitElements) {
            $convertProductFields['price'] = 'PRICE';
        } else {
            $convertProductFields['salePrice'] = 'PRICE';
        }
        $orderSum = 0;

        foreach ($products as $product) {
            $setProduct = [];

            foreach ($convertProductFields as $setKey => $key) {
                $value = $product[$key] ?? '';
                //if ($setKey == 'salePrice') $value = intval($value);
                $setProduct[$setKey] = $value;
            }

            $setProduct['stocks']['quantity'] = intval($product['stocks']['quantity'] ?? $product['QUANTITY']);

            if (!$useKitElements) {
                $productSum = $setProduct['salePrice'] * $setProduct['stocks']['quantity'];
                $setProduct['salePriceSum'] = $productSum;
                $orderSum += $productSum;
            }

            // рекурсия для комплектов
            $kitElements = $product['kitElements'] ?? false;
            if ($kitElements) {
                $flagOfUseKitElements = true;
                [
                    'products' => $convertedKitElements,
                ] = $this->convertProducts($kitElements, $flagOfUseKitElements);
                $setProduct['kitElements'] = $convertedKitElements;
            }

            $convertedProducts[] = $setProduct;
        }

        return [
            'products' => $convertedProducts,
            'orderSum' => $orderSum,
        ];
    }

    protected function getTimestampFromDateTimeObject($obj)
    {
        $timestamp = '';
        if ($obj && $obj instanceof DateTime) {
            $timestamp = $obj->getTimestamp();
        }

        return $timestamp;
    }

    protected function getStringFromDateTimeObject($obj)
    {
        $timestamp = $this->getTimestampFromDateTimeObject($obj);

        return $timestamp ? date('d.m.Y H:i:s', $timestamp) : '';
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit