Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/classes/general/
Upload File :
Current File : /var/www/homesaver/www/bitrix/classes/general/CMainOfdFerma.php

<?php

CModule::IncludeModule(CMainOfdFerma::$MODULE_ID);

class CMainOfdFerma
{
    public static $MODULE_ID = 'ofdferma';

    /**
     * @param \CAdminSaleList|\CAdminList $list
     */
    public static function onAdminListDisplay($list)
    {
        /** @var \CMain $APPLICATION */
        global $APPLICATION;

        if ($APPLICATION->GetCurPage() === '/bitrix/admin/sale_order.php') {
            $APPLICATION->AddHeadScript('/bitrix/js/ofdferma/ofdferma_receipts.js');

            foreach ($list->aRows as $row) {
                $actions = $row->aActions;

                $newActions = [
                    [
                        'ICON' => 'edit',
                        'TEXT' => 'Сформировать чек прихода',
                        'ACTION' => 'window.ofdferma.openOrderReceiptPanel("' . $row->id . '");',
                    ], [
                        'ICON' => 'edit',
                        'TEXT' => 'Сформировать чек возврата',
                        'ACTION' => 'window.ofdferma.openOrderRefundPanel("' . $row->id . '");',
                    ],
                ];

                array_splice($actions, -2, 0, $newActions);

                $row->AddActions($actions);
            }
        }
    }

    public static function onAdminContextMenuShow(&$items)
    {
        /** @var \CMain $APPLICATION */
        global $APPLICATION;

        if ($APPLICATION->GetCurPage() === '/bitrix/admin/sale_order_view.php') {
            $APPLICATION->AddHeadScript('/bitrix/js/ofdferma/ofdferma_receipts.js');

            $orderId = (int)$_GET['ID'];

            $newItems = [
                [
                    'TEXT' => 'Сформировать чек',
                    'TITLE' => 'Сформировать чек прихода',
                    'MENU' => [
                        [
                            'TEXT' => 'Чек прихода',
                            'TITLE' => 'Сформировать чек прихода',
                            'ACTION' => 'window.ofdferma.openOrderReceiptPanel("' . $orderId . '");',
                        ], [
                            'TEXT' => 'Чек возврата',
                            'TITLE' => 'Сформировать чек возврата',
                            'ACTION' => 'window.ofdferma.openOrderRefundPanel("' . $orderId . '");',
                        ],
                    ],
                ],
            ];

            array_splice($items, -2, 0, $newItems);
        }
    }

    public static function onSalePayOrder($orderId, $state)
    {
        $enabled = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_agent_auto_create', 'Y');

        if ($enabled !== 'Y') {
            return null;
        }

        if (empty($orderId)) {
            CMainOfdFerma::log(
                'Отправка фискального чека', null,
                'Фискальный чек не отправлен, поскольку не указан номер заказа.', 'WARNING'
            );

            return null;
        }

        if ($state !== 'Y') {
            return null;
        }

        $order = CSaleOrder::GetByID($orderId);

        if (!$order) {
            CMainOfdFerma::log(
                'Отправка фискального чека', 'Заказ №' . $orderId,
                'Фискальный чек не отправлен, поскольку заказ не найден в базе.', 'WARNING'
            );

            return null;
        }

        $user = CUser::GetByID($order['USER_ID'])->NavNext();

        $items = [];

        $itemsResult = CSaleBasket::GetList([], [
            'ORDER_ID' => $orderId,
        ]);

        while ($item = $itemsResult->NavNext()) {
            $items[] = $item;
        }

        try {
            $fermaApiClient = CMainOfdFerma::getApiClient();
        } catch (\RuntimeException $e) {
            CMainOfdFerma::log(
                'Отправка фискального чека', 'Заказ №' . $orderId,
                'Фискальный чек не отправлен, поскольку не указаны параметры подключения к ферме.', 'WARNING'
            );

            return null;
        }

        $receiptData = $fermaApiClient->prepareElectronReceipt('Income', $order, $items);

        CAgent::AddAgent(
            'CMainOfdFerma::sendReceiptAgent(' . json_encode($orderId) . ', "' . addslashes(json_encode($receiptData)) . '");',
            CMainOfdFerma::$MODULE_ID,
            'Y', 30
        );

        return true;
    }

    public static function onSalePayCancelOrder($orderId, $state)
    {
        $enabled = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_agent_auto_create', 'Y');

        if ($enabled !== 'Y') {
            return null;
        }

        if (empty($orderId)) {
            CMainOfdFerma::log(
                'Отправка фискального чека возврата', null,
                'Фискальный чек возврата не отправлен, поскольку не указан номер заказа.', 'WARNING'
            );

            return null;
        }

        if ($state !== 'N') {
            return null;
        }

        $order = CSaleOrder::GetByID($orderId);

        if (!$order) {
            CMainOfdFerma::log(
                'Отправка фискального чека возврата', 'Заказ №' . $orderId,
                'Фискальный чек возврата не отправлен, поскольку заказ не найден в базе.', 'WARNING'
            );

            return null;
        }

        $user = CUser::GetByID($order['USER_ID'])->NavNext();

        $items = [];

        $itemsResult = CSaleBasket::GetList([], [
            'ORDER_ID' => $orderId,
        ]);

        while ($item = $itemsResult->NavNext()) {
            $items[] = $item;
        }

        try {
            $fermaApiClient = CMainOfdFerma::getApiClient();
        } catch (\RuntimeException $e) {
            CMainOfdFerma::log(
                'Отправка фискального чека возврата', 'Заказ №' . $orderId,
                'Фискальный чек возврата не отправлен, поскольку не указаны параметры подключения к ферме.', 'WARNING'
            );

            return null;
        }

        $receiptData = $fermaApiClient->prepareElectronReceipt('IncomeReturn', $order, $items);

        CAgent::AddAgent(
            'CMainOfdFerma::sendReceiptAgent(' . json_encode($orderId) . ', "' . addslashes(json_encode($receiptData)) . '");',
            CMainOfdFerma::$MODULE_ID,
            'Y', 30
        );

        return true;
    }

    public static function sendReceiptAgent($orderId, $receiptData)
    {
        $receiptData = json_decode($receiptData, true);

        try {
            CMainOfdFerma::sendReceiptData($orderId, $receiptData);
        } catch (\RuntimeException $e) {
            CMainOfdFerma::log(
                'Отправка фискального чека', 'Заказ №' . $orderId,
                $e->getMessage(), 'WARNING'
            );

            // чек уже есть в базе
            if ($e->getCode() === 1019) {
                return false;
            }

            return 'CMainOfdFerma::sendReceiptAgent(' . json_encode($orderId) . ', "' . addslashes(json_encode($receiptData)) . '");';
        }

        CMainOfdFerma::log(
            'Отправка фискального чека', 'Заказ №' . $orderId,
            'Фискальный чек успешно отправлен в ферму.', 'INFO'
        );

        return false;
    }

    public static function checkReceiptStatusAgent($receiptId)
    {
        $receipt = COfdFermaReceipt::GetByID($receiptId);

        if (empty($receipt)) {
            CMainOfdFerma::log(
                'Проверка фискального чека', 'Чек №' . $receiptId,
                'Проверка фискального чека не удалась, поскольку чек не найден.', 'WARNING'
            );

            return false;
        }

        try {
            $fermaApiClient = CMainOfdFerma::getApiClient();
        } catch (\RuntimeException $e) {
            CMainOfdFerma::log(
                'Проверка фискального чека', 'Чек №' . $receiptId,
                'Проверка фискального чека не удалась, поскольку не указаны параметры подключения к ферме.', 'WARNING'
            );

            return false;
        }

        try {
            $response = $fermaApiClient->getElectronReceiptStatus($receipt['RECEIPT_ID']);
        } catch (CFermaApiException $e) {
            return 'CMainOfdFerma::checkReceiptStatusAgent(' . json_encode($receipt['ID']) . ');';
        }

        if ($response['Status'] === 'Failed') {
            if (isset($response['Error']['Message'])) {
                CMainOfdFerma::log(
                    'Проверка фискального чека', 'Чек №' . $receiptId,
                    sprintf('Проверка фискального чека не удалась: %s.', $response['Error']['Message']), 'WARNING'
                );
            } else {
                CMainOfdFerma::log(
                    'Проверка фискального чека', 'Чек №' . $receiptId,
                    sprintf('Проверка фискального чека не удалась по неизвестной причине.'), 'WARNING'
                );
            }

            return false;
        }

        $data = $response['Data'];

        COfdFermaReceipt::Update($receipt['ID'], [
            'STATUS_ID' => $data['StatusCode'],
            'STATUS_NAME' => $data['StatusName'],
            'STATUS_MESSAGE' => $data['StatusMessage'],
            'DEVICE_ID' => $data['Device']['DeviceId'],
            'RNM' => $data['Device']['RNM'],
            'ZN' => $data['Device']['ZN'],
            'FN' => $data['Device']['FN'],
            'FDN' => $data['Device']['FDN'],
            'FPD' => $data['Device']['FPD'],
        ]);

        CMainOfdFerma::log(
            'Проверка фискального чека', 'Чек №' . $receiptId,
            'Статус фискального чека успешно проверен.', 'INFO'
        );

        if ($data['StatusCode'] < 2) {
            return 'CMainOfdFerma::checkReceiptStatusAgent(' . json_encode($receipt['ID']) . ');';
        }

        // возвращаем false при успешной операции для того, чтобы агент не перезапускался
        return false;
    }

    public static function sendReceiptData($orderId, $receiptData)
    {
        global $DB;

        try {
            $fermaApiClient = CMainOfdFerma::getApiClient();
        } catch (\RuntimeException $e) {
            throw new \RuntimeException('Фискальный чек не отправлен, поскольку не указаны параметры подключения к ферме.');
        }

        try {
            $response = $fermaApiClient->sendElectronReceipt($receiptData);
        } catch (CFermaApiException $e) {
            throw new \RuntimeException(sprintf('Фискальный чек не отправлен: %s.', $e->getMessage()));
        }

        if (empty($response)) {
            throw new \RuntimeException('Фискальный чек не отправлен, поскольку ферма вернула пустой результат.');
        }

        if ($response['Status'] === 'Failed') {
            if (!isset($response['Error']['Message'])) {
                throw new \RuntimeException('Фискальный чек не отправлен по неизвестной причине.');
            }

            throw new \RuntimeException(sprintf('Фискальный чек не отправлен: %s.', $response['Error']['Message']), $response['Error']['Code']);
        }

        $total = 0;

        foreach ($receiptData['CustomerReceipt']['Items'] as $item) {
            $total += $item['Amount'];
        }

        $id = COfdFermaReceipt::Add([
            'SITE_ID' => SITE_ID,
            'RECEIPT_ID' => $response['Data']['ReceiptId'],
            'ORDER_ID' => $orderId,
            'CONTENT' => json_encode($receiptData),
            'TYPE' => $receiptData['Type'],
            'TOTAL_PRICE' => $total,
            '=DATE_CREATE' => $DB->GetNowFunction(),
            '=DATE_UPDATE' => $DB->GetNowFunction(),
        ]);

        CAgent::AddAgent(
            'CMainOfdFerma::checkReceiptStatusAgent(' . json_encode($id) . ');',
            CMainOfdFerma::$MODULE_ID,
            'Y', 10
        );

        return true;
    }

    /**
     * @var \CFermaApiService
     */
    private static $client;

    public static function getApiClient()
    {
        if (null === CMainOfdFerma::$client) {
            $fermaApiHost = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_api_host', 'https://ferma.ofd.ru');
            $fermaApiLogin = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_api_login');
            $fermaApiPassword = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_api_password');
            $agentInn = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_agent_inn');
            $agentTaxation = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_agent_taxation_system');
            $errorsEmail = COption::GetOptionString(CMainOfdFerma::$MODULE_ID, CMainOfdFerma::$MODULE_ID . '_errors_email');

            if (empty($fermaApiHost) || empty($fermaApiLogin) || empty($fermaApiPassword)
                || empty($agentInn) || empty($agentTaxation)) {
                throw new \RuntimeException('Не указаны параметры подключения к ферме.');
            }

            CMainOfdFerma::$client = CFermaApiService::instance(
                $fermaApiHost, $fermaApiLogin, $fermaApiPassword,
                $agentInn, $agentTaxation, $errorsEmail
            );
        }

        return CMainOfdFerma::$client;
    }

    public static function log($operation, $entity, $message, $level)
    {
        if (class_exists('CEventLog')) {
            CEventLog::Add([
                'SEVERITY' => $level,
                'AUDIT_TYPE_ID' => $operation,
                'MODULE_ID' => CMainOfdFerma::$MODULE_ID,
                'ITEM_ID' => $entity,
                'DESCRIPTION' => $message,
            ]);
        }
    }
}