Інтеграція з АТОЛ Онлайн для 1С-Бітрікс

Наша компанія займається розробкою, підтримкою та обслуговуванням рішень на Бітрікс та Бітрікс24 будь-якої складності. Від простих односторінкових сайтів до складних інтернет-магазинів, CRM систем з інтеграцією 1С та телефонії. Досвід розробників підтверджено сертифікатами від вендора.
Пропоновані послуги
Показано 1 з 1 послугУсі 1626 послуг
Інтеграція з АТОЛ Онлайн для 1С-Бітрікс
Середня
~1-2 тижні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Розробка на базі Бітрікс, Бітрікс24, 1С для компанії Development of an Online
    585
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Розробка на базі 1С Підприємство для компанії МИРСАНБЕЛ
    751
  • image_crm_dolbimby_434_0.webp
    Розробка сайту на CRM Бітрікс24 для компанії DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Розробка на базі Бітрікс24 для компанії ТЕХНОТОРГКОМПЛЕКС
    989

Інтеграція з АТОЛ Онлайн для 1С-Бітрікс

Вимога 54-ФЗ про онлайн-касу поширюється на більшість інтернет-магазинів: кожна безготівкова оплата від фізичної особи повинна супроводжуватися фіскальним чеком, переданим до ОФД. АТОЛ Онлайн — один із найбільших провайдерів хмарної фіскалізації в Росії. Інтеграція з 1С-Бітрікс технічно нетривіальна: потрібно правильно сформувати позиції чека, коректно вказати ставки ПДВ, ознаки предмета та способу розрахунку, обробити асинхронний callback від АТОЛ і врахувати кейси з поверненнями.

Схема роботи АТОЛ Онлайн

АТОЛ Онлайн — не фізична каса, а хмарний сервіс: ваші дані про покупку надходять до API АТОЛ, АТОЛ передає їх на віртуальну касу, яка формує фіскальний документ і надсилає його до ОФД (оператор фіскальних даних), а покупцеві надходить електронний чек на email або телефон.

Схема взаємодії:

  1. Покупець оплатив замовлення → у callback-обробнику вашого еквайрингу платіж підтверджено
  2. Магазин надсилає запит до АТОЛ API (sell — чек приходу)
  3. АТОЛ повертає uuid задачі (асинхронно)
  4. Через кілька секунд АТОЛ надсилає webhook з результатом фіскалізації
  5. Магазин зберігає фіскальний документ (номер ФД, ФП) і позначає чек як «пробитий»

Реєстрація в АТОЛ і отримання credentials

Перед інтеграцією потрібні:

  • Договір з АТОЛ і зареєстрована віртуальна каса
  • login і password — для отримання токена API
  • group_code — код групи кас
  • inn — ІПН вашої організації (для чека)
  • payment_address — адреса розрахунків (URL сайту)

Отримання токена

class AtolOnlineClient
{
    private const API_URL = 'https://online.atol.ru/possystem/v5/';
    private string $token = '';

    public function auth(string $login, string $password): void
    {
        $response = $this->request('getToken', [
            'login'    => $login,
            'pass'     => $password,
        ], false);

        if (empty($response['token'])) {
            throw new \RuntimeException('АТОЛ: помилка авторизації — ' . ($response['error']['text'] ?? 'невідомо'));
        }

        $this->token = $response['token'];
        // Кешуємо токен на 24 години (термін дії — 24 години)
        \Bitrix\Main\Data\Cache::createInstance()->set('atol_token', $this->token, 86000);
    }

    private function request(string $endpoint, array $data, bool $withToken = true): array
    {
        $headers = ['Content-Type: application/json; charset=utf-8'];
        if ($withToken) {
            $headers[] = 'Token: ' . $this->token;
        }

        $ch = curl_init(self::API_URL . $endpoint);
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => json_encode($data, JSON_UNESCAPED_UNICODE),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_SSL_VERIFYPEER => true,
        ]);
        $result = json_decode(curl_exec($ch), true);
        curl_close($ch);
        return $result ?? [];
    }
}

Формування чека приходу

public function sell(string $groupCode, \Bitrix\Sale\Order $order, string $callbackUrl): array
{
    $basket  = $order->getBasket();
    $payment = $order->getPaymentCollection()->current();
    $buyer   = $order->getPropertyCollection();

    $items = [];
    foreach ($basket->getOrderableItems() as $item) {
        $items[] = [
            'name'           => mb_substr($item->getField('NAME'), 0, 128), // макс 128 символів
            'price'          => round($item->getBasePrice(), 2),
            'quantity'       => $item->getQuantity(),
            'sum'            => round($item->getFinalPrice(), 2),
            'measurement_unit' => 'шт',
            'payment_method' => 'full_payment',   // повна оплата
            'payment_object' => 'commodity',       // товар
            'vat'            => ['type' => 'none'], // без ПДВ; або 'vat10', 'vat20'
        ];
    }

    // Доставка як окрема позиція (обов'язково!)
    $deliveryPrice = $order->getDeliveryPrice();
    if ($deliveryPrice > 0) {
        $items[] = [
            'name'             => 'Доставка',
            'price'            => round($deliveryPrice, 2),
            'quantity'         => 1,
            'sum'              => round($deliveryPrice, 2),
            'measurement_unit' => 'посл',
            'payment_method'   => 'full_payment',
            'payment_object'   => 'service',
            'vat'              => ['type' => 'none'],
        ];
    }

    $receiptPayments = [];
    // Визначаємо тип оплати для чека
    $paySystemCode = $payment->getPaymentSystemId();
    if (isCashPayment($paySystemCode)) {
        $receiptPayments[] = ['type' => 0, 'sum' => $order->getPrice()]; // готівка
    } else {
        $receiptPayments[] = ['type' => 1, 'sum' => $order->getPrice()]; // безготівкові
    }

    $payload = [
        'external_id' => 'BX_' . $order->getId() . '_' . time(),
        'receipt'     => [
            'client'   => [
                'email' => $buyer->getItemByOrderPropertyCode('EMAIL')?->getValue(),
                'phone' => $buyer->getItemByOrderPropertyCode('PHONE')?->getValue(),
            ],
            'company'  => [
                'email'           => COMPANY_EMAIL,
                'inn'             => COMPANY_INN,
                'payment_address' => SITE_URL,
                'sno'             => 'usn_income',  // система оподаткування
            ],
            'items'    => $items,
            'payments' => $receiptPayments,
            'total'    => round($order->getPrice(), 2),
        ],
        'service'     => [
            'callback_url' => $callbackUrl,
        ],
        'timestamp'   => date('d.m.Y H:i:s'),
    ];

    return $this->request($groupCode . '/sell', $payload);
}

Типові помилки при формуванні чека

Розбіжність суми. receipt.total повинен точно збігатися із сумою payments[].sum. Дробові копійки при округленні — часта причина помилки invalid_total_amount.

Ознаки предмета розрахунку. payment_object = commodity для товарів, service для послуг (доставка, монтаж), payment для авансів. Неправильна ознака — адміністративна відповідальність.

Ознака способу розрахунку. payment_method = full_payment для повної оплати, prepayment для авансу, advance для передоплати. При двостадійному еквайрингу (холд + capture) перший чек з advance, другий — з full_payment.

Довжина найменування. АТОЛ обмежує name 128 символами. Довгі назви потрібно обрізати.

Обробка callback від АТОЛ

АТОЛ асинхронно надсилає POST на callback_url з результатом:

// /bitrix/tools/atol_callback.php
$body = file_get_contents('php://input');
$data = json_decode($body, true);

// Перевіряємо UUID задачі
$uuid     = $data['uuid'] ?? '';
$status   = $data['status'] ?? '';
$payload  = $data['payload'] ?? [];

// Знаходимо замовлення за uuid
$atolTask = AtolTaskTable::getList([
    'filter' => ['UUID' => $uuid],
])->fetch();

if (!$atolTask) {
    http_response_code(200);
    exit; // невідома задача — ігноруємо
}

if ($status === 'done' && !empty($payload['fiscal_document_number'])) {
    // Чек успішно пробитий
    AtolTaskTable::update($atolTask['ID'], [
        'STATUS'                  => 'DONE',
        'FISCAL_DOCUMENT_NUMBER'  => $payload['fiscal_document_number'],
        'FISCAL_DOCUMENT_ATTRIBUTE' => $payload['fiscal_document_attribute'],
        'FNS_SITE'                => $payload['fns_site'] ?? '',
        'FN_NUMBER'               => $payload['fn_number'] ?? '',
        'SHIFT_NUMBER'            => $payload['shift_number'] ?? '',
        'RECEIPT_DATETIME'        => $payload['receipt_datetime'] ?? '',
    ]);
} elseif ($status === 'fail') {
    AtolTaskTable::update($atolTask['ID'], [
        'STATUS'    => 'FAIL',
        'ERROR'     => $data['error']['text'] ?? 'Невідома помилка',
        'ERROR_CODE'=> $data['error']['code'] ?? 0,
    ]);
    // Алерт адміністратору — чек не пробитий
    notifyAdmin('Помилка АТОЛ', 'Замовлення ' . $atolTask['ORDER_ID'] . ': ' . $data['error']['text']);
}

http_response_code(200);
echo 'OK';

Чек повернення

При оформленні повернення покупцеві потрібно пробити чек повернення (sell_refund):

public function sellRefund(string $groupCode, \Bitrix\Sale\Order $order, float $refundAmount, array $refundItems): array
{
    $payload = [
        'external_id' => 'BX_REFUND_' . $order->getId() . '_' . time(),
        'receipt'     => [
            'client'   => ['email' => $buyerEmail],
            'company'  => ['inn' => COMPANY_INN, 'payment_address' => SITE_URL, 'sno' => 'usn_income'],
            'items'    => $refundItems,  // позиції з повернення
            'payments' => [['type' => 1, 'sum' => $refundAmount]],
            'total'    => $refundAmount,
        ],
        'service'     => ['callback_url' => ATOL_CALLBACK_URL],
        'timestamp'   => date('d.m.Y H:i:s'),
    ];

    return $this->request($groupCode . '/sell_refund', $payload);
}

Інтеграція з обробником платіжної системи

Виклик АТОЛ вбудовується в подію підтвердження оплати:

// В події OnSalePaymentEntitySaved або в обробнику callback еквайрингу
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'sale', 'OnSalePaymentEntitySaved',
    function(\Bitrix\Main\Event $event) {
        $payment = $event->getParameter('ENTITY');
        if ($payment->isPaid() && !$payment->isSystem()) {
            $order = $payment->getOrder();
            // Запускаємо фіскалізацію
            $atol = new AtolOnlineService();
            $atol->fiscalize($order);
        }
    }
);

Терміни

Завдання Термін
Базова інтеграція: чек приходу + callback 2–3 дні
Чек повернення + коректні ознаки предмета розрахунку 1–2 дні
Моніторинг: таблиця задач, алерти при помилках 1 день
Тестування на тестовому середовищі АТОЛ 1 день
Перемикання на бойове середовище та приймання 0.5 дня