Search by

ttbooking / direct-bank

EgorGruzdev

1C Direct Bank Client

Package info

github.com/ttbooking/DirectBank

pkg:composer/ttbooking/direct-bank

Statistics

Installs: 151

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 9

0.1.0 2026-09-22 21:28 UTC

This package is auto-updated.

Last update: 2026-09-22 21:37:50 UTC


README

PHP-клиент для обмена с банком по протоколу 1С:DirectBank (формат обмена 2.2.2).

Библиотека берёт на себя HTTP-транспорт (аутентификация, сессия, заголовки протокола) и даёт типизированные объекты для транспортного контейнера (Packet) и документов внутри него: запрос выписки, выписка, извещение о состоянии обработки контейнера и др.

Tests Packagist License: GPL v3

Требования

Установка

composer require ttbooking/direct-bank

Быстрый старт

Создание клиента

use TTBooking\DirectBank\Client;
use TTBooking\DirectBank\Dictionary\DefaultValue;

$client = new Client([
    'url'        => 'https://bank.example.ru/API/v1/directbank/', // базовый URL сервиса банка
    'customerId' => '40702810000000000000',                      // идентификатор клиента в банке
    'login'      => 'user',
    'password'   => 'secret',
    'apiVersion' => DefaultValue::FORMAT_VERSION,                 // по умолчанию '2.2.2'
    'availableApiVersion' => DefaultValue::FORMAT_VERSION,        // заголовок AvailableAPIVersion в Logon, null — не передавать
    'userAgent'  => null,                                         // заголовок User-Agent, по умолчанию стандартный Guzzle
    'sessionId'  => null,                                         // можно передать уже полученный SID
    'verify'     => true,                                         // проверка SSL-сертификата
    'handler'    => null,                                         // свой Guzzle handler, например MockHandler в тестах
]);

Настройки проверяются в конструкторе: url, customerId, login, password и apiVersion должны быть непустыми строками, availableApiVersion, userAgent и sessionId — непустой строкой или null, verify — булевым значением или путём к CA-бандлу, handler — callable. Иначе выбрасывается TTBooking\DirectBank\Exceptions\InvalidSettingsException (наследник \InvalidArgumentException) с именем неверной настройки.

Вторым аргументом можно передать любой PSR-3 логгер — все HTTP-запросы и ответы будут записаны в формате MessageFormatter::DEBUG из Guzzle:

$client = new Client($settings, $logger); // Psr\Log\LoggerInterface

Сессия

Явно вызывать createSession() не обязательно: при первом запросе, требующем авторизации, клиент сам выполнит Logon и подставит полученный sid в заголовки. Если сессия истекла или стала недействительной (ошибки банка 1006 и 1007), клиент войдёт заново и повторит запрос один раз.

$sid = $client->createSession();

Логин и пароль передаются только в Logon, остальные запросы идут с SID.

Вход с одноразовым паролем

Если банк требует подтвердить вход одноразовым паролем (OTP), createSession() — и неявный вход перед первым запросом — выбрасывает TTBooking\DirectBank\Exceptions\OtpRequiredException. Банк в этот момент отправляет пароль клиенту, а вход подтверждается методом confirmOtp():

use TTBooking\DirectBank\Exceptions\OtpRequiredException;

try {
    $client->createSession();
} catch (OtpRequiredException $e) {
    $e->getPhoneMask();   // маска телефона, если банк её прислал, например '7916***6465'
    $e->getSessionCode(); // короткий код сессии для показа пользователю, если есть

    $client->confirmOtp($e->getSessionId(), $otpFromUser); // дальше запросы идут с авторизованным SID
}

Методы клиента

Метод Запрос DirectBank Результат
createSession(): string POST Logon идентификатор сессии (SID)
confirmOtp(string $sessionId, string $otp): string POST LogonOTP идентификатор авторизованной сессии
sendPack(Packet $packet): string POST SendPack идентификатор принятого контейнера
getPackList(?DateTimeInterface $date = null): ?array GET GetPackList список идентификаторов контейнеров, готовых к получению
getPackListResponse(DateTimeInterface|string|null $since = null) GET GetPackList список контейнеров и отметка времени последнего из них
getPack(string $id): Packet GET GetPack транспортный контейнер

Отметка времени для списка контейнеров задаётся по часам сервера банка и передаётся в формате dd.MM.yyyy HH:mm:ss. Чтобы получать только новые контейнеры, передавайте в следующий запрос TimeStampLastPacket из предыдущего ответа:

$list = $client->getPackListResponse($lastTimestamp); // null — все контейнеры

foreach ($list->getPacketID() as $id) {
    // $client->getPack($id) ...
}

$lastTimestamp = $list->getTimeStampLastPacket() ?? $lastTimestamp; // сохранить до следующего запроса

Ошибки

  • TTBooking\DirectBank\Exceptions\ClientException — банк вернул ошибку (ResultBank/Error), при любом HTTP-статусе. Код банка как есть — getBankCode() (строка, например '1201'), вся ошибка — getError(), описание — getMessage(), getCode() — код числом.
  • TTBooking\DirectBank\Exceptions\UnexpectedResponseException (наследник ClientException) — ответ не удалось разобрать или в нём нет ожидаемых данных. HTTP-ответ — getResponse(), getCode() — HTTP-статус.
  • TTBooking\DirectBank\Exceptions\OtpRequiredException (наследник ClientException) — банк требует подтвердить вход одноразовым паролем, см. выше.
  • Коды ошибок банка — константы TTBooking\DirectBank\Dictionary\ErrorCode.
  • Сетевые ошибки (нет соединения, таймаут) пробрасываются как исключения Guzzle.

Примеры

Запрос выписки

Документ внутри контейнера передаётся в base64 в Document/Data, а его вид указывается кодом из DocKind.

use Ramsey\Uuid\Uuid;
use TTBooking\DirectBank\Dictionary\DocKind;
use TTBooking\DirectBank\Objects\{
    BankPartyType, BankType, CustomerPartyType, DocumentType,
    Packet, ParticipantType, StatementRequest, StatementRequestData
};

$now       = new DateTimeImmutable();
$userAgent = 'My App';
$docId     = (string) Uuid::uuid4();

$customer = (new CustomerPartyType())->setId('40702810000000000000');
$bank     = (new BankPartyType())->setBic('044525593');

$request = (new StatementRequest())
    ->setId($docId)
    ->setCreationDate($now->format(DATE_ATOM))
    ->setUserAgent($userAgent)
    ->setSender($customer)
    ->setRecipient($bank)
    ->setData(
        (new StatementRequestData())
            ->setStatementType(0)
            ->setDateFrom('2021-01-01T00:00:00+03:00')
            ->setDateTo('2021-01-31T23:59:59+03:00')
            ->setAccount('40702810000000000000')
            ->setBank((new BankType())->setBic('044525593'))
    );

$packet = (new Packet())
    ->setId((string) Uuid::uuid4())
    ->setCreationDate($now->format(DATE_ATOM))
    ->setUserAgent($userAgent)
    ->setSender((new ParticipantType())->setCustomer($customer))
    ->setRecipient((new ParticipantType())->setBank($bank))
    ->setDocument(
        (new DocumentType())
            ->setId($docId)
            ->setDockind(DocKind::BANK_STATEMENT_REQUEST)
            ->setData(base64_encode((string) $request))
    );

$packetId = $client->sendPack($packet);

Получение ответов банка

use Mapper\XmlModelMapper;
use TTBooking\DirectBank\Dictionary\DocKind;
use TTBooking\DirectBank\Dictionary\DocStatus;
use TTBooking\DirectBank\Objects\{Settings, Statement, StatusDocNotice, StatusPacketNotice};

$mapper = new XmlModelMapper();

foreach ($client->getPackList() ?? [] as $id) {
    $pack = $client->getPack($id);

    foreach ($pack->getDocuments() as $packDocument) {
        $xml = base64_decode($packDocument->getData());

        $document = match ($packDocument->getDockind()) {
            DocKind::STATUS_PACKET_NOTICE => $mapper->map($xml, new StatusPacketNotice()),
            DocKind::STATUS_DOC_NOTICE => $mapper->map($xml, new StatusDocNotice()),
            DocKind::SETTINGS => $mapper->map($xml, new Settings()),
            DocKind::BANK_STATEMENT => $mapper->map($xml, new Statement()),
            default => null,
        };

        if ($document instanceof StatusDocNotice) {
            $document->getExtID();                              // документ, о котором извещение
            $document->getResult()->getStatus()?->getCode();    // DocStatus::EXECUTED и т.д.
            $document->getResult()->getError()?->getDescription(); // или ошибка обработки
        }

        if ($document instanceof Statement) {
            $data = $document->getData();
            $data->getClosingBalance();
            foreach ($data->getOperationInfo() as $operation) {
                // ...
            }
        }
    }
}

Служебные документы

Исходящие служебные документы собираются так же, как запрос выписки, и передаются в контейнере с соответствующим видом:

Документ Класс Вид ЭД
Запрос о состоянии электронного документа StatusRequest (setExtID() — ИД документа) DocKind::STATUS_REQUEST
Запрос-зонд Probe DocKind::PROBE

Входящие: StatusPacketNotice (01), StatusDocNotice (02), Settings (06), Statement (15).

Справочники

Классификаторы стандарта в пространстве имён TTBooking\DirectBank\Dictionary:

Класс Содержимое
DocKind коды видов электронных документов, DocKind::REQUIRED — обязательные
DocStatus коды статусов электронных документов
PacketStatus коды статусов транспортных контейнеров
StatementType типы выписок
ErrorCode коды ошибок банковского сервиса

Виды документов

Константы TTBooking\DirectBank\Dictionary\DocKind:

Константа Код Документ
STATUS_PACKET_NOTICE 01 Извещение о состоянии обработки транспортного контейнера
STATUS_DOC_NOTICE 02 Извещение о состоянии электронного документа *
STATUS_REQUEST 03 Запрос о состоянии электронного документа *
CANCELATION_REQUEST 04 Запрос об отзыве электронного документа
PROBE 05 Запрос-зонд *
SETTINGS 06 Настройки обмена с банком *
PAY_DOC_RU 10 Платёжное поручение
PAY_REQUEST 11 Платёжное требование
COLLECTION_ORDER 12 Инкассовое поручение
INNER_DOC 13 Внутренний банковский документ
BANK_STATEMENT_REQUEST 14 Запрос выписки
BANK_STATEMENT 15 Выписка банка
MEM_ORDER 16 Мемориальный ордер
PAYMENT_ORDER 17 Платёжный ордер
BANK_ORDER 18 Банковский ордер
WAGES_* 1923 Документы зарплатного проекта
CASH_CONTRIBUTION 24 Объявление на взнос наличными
CHECK 25 Денежный чек
CURRENCY_TRANSFER_ORDER 30 Поручение на перевод валюты
CURRENCY_STATEMENT 35 Выписка по валютному счёту

* обязательные по стандарту. SHIPPING_CONTAINER_HANDLING_STATUS_NOTIFICATION — прежнее имя STATUS_PACKET_NOTICE.

XSD-схемы формата лежат в tests/Fixture/xsd.

Тесты

composer install
vendor/bin/phpunit

По умолчанию запускаются офлайн-тесты: маппинг XML на примерах из описания стандарта 1С и работа Client с подменённым HTTP-обработчиком. Тесты против тестового стенда банка (tests/ClientTest.php) требуют сетевого доступа к нему и запускаются отдельно:

vendor/bin/phpunit --group bank-stand

История изменений

См. Releases.

Лицензия

GPL-3.0