Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 54 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# DirectBank

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

Библиотека берёт на себя HTTP-транспорт (аутентификация, сессия, заголовки протокола)
и даёт типизированные объекты для транспортного контейнера (`Packet`) и документов
Expand Down Expand Up @@ -30,15 +30,15 @@ composer require ttbooking/direct-bank

```php
use TTBooking\DirectBank\Client;
use TTBooking\DirectBank\Dictionary\DefaultValue;
use TTBooking\DirectBank\FormatVersion;

$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 — не передавать
'apiVersion' => null, // по умолчанию FormatVersion::getDefault(), '2.3.2'
'availableApiVersion' => FormatVersion::LATEST, // заголовок AvailableAPIVersion, null — не передавать
'userAgent' => null, // заголовок User-Agent, по умолчанию стандартный Guzzle
'sessionId' => null, // можно передать уже полученный SID
'verify' => true, // проверка SSL-сертификата
Expand All @@ -59,6 +59,22 @@ $client = new Client([
$client = new Client($settings, $logger); // Psr\Log\LoggerInterface
```

### Версия стандарта

По умолчанию клиент и все создаваемые документы используют версию `2.3.2`. Для банка,
который поддерживает только `2.2.x`, версия задаётся один раз:

```php
use TTBooking\DirectBank\FormatVersion;

FormatVersion::setDefault('2.2.2'); // APIVersion клиента и formatVersion новых документов
```

Разобранные документы сохраняют версию из XML. Элементы 2.3.x — письма, `SenderFootprint`,
`Letters` в настройках — в схемах `2.2.2` отсутствуют.

Транспортный контейнер отправляется с UTF-8 BOM, как требует стандарт с версии 2.3.x.

### Сессия

Явно вызывать `createSession()` не обязательно: при первом запросе, требующем
Expand Down Expand Up @@ -260,13 +276,40 @@ $client->sendPack($packet);
Исходящие документы собираются в XML через `TTBooking\DirectBank\Mapper\XmlMapper`: поля базовых
типов идут раньше полей наследников, как требует XSD.

### Письмо

Письмо (вид `40`) ходит в обе стороны. Размер и CRC32 вложений считаются по содержимому файла:

```php
use TTBooking\DirectBank\Objects\{BinaryFileType, Letter, LetterAttachmentType, LetterDataType, LinkedDocType};

$letter = (new Letter())
->setId((string) Uuid::uuid4())
->setCreationDate((new DateTimeImmutable())->format(DATE_ATOM))
->setSender((new ParticipantType())->setCustomer($customer))
->setRecipient((new ParticipantType())->setBank($bank))
->setData(
(new LetterDataType())
->setDocNum('7')
->setDocDate('2026-09-23')
->setLetterTypeCode('01') // типы писем банка — в настройках: Settings::getData()->getLetters()
->setTheme('Уточнение назначения платежа')
->setText('Прошу уточнить назначение платежа по поручению № 14.')
->addAttachment(new LetterAttachmentType(BinaryFileType::fromFile('/path/to/invoice.pdf')))
->setLinkedDoc(new LinkedDocType($payDocRu->getId(), DocKind::PAY_DOC_RU))
);
```

Вложения передаются как есть: BOM для текстовых файлов добавляет вызывающий код. У полученного
письма содержимое вложения — `getBinaryFile()->getContents()`, проверка размера и CRC32 — `isIntact()`.

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

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

$mapper = new XmlModelMapper();

Expand All @@ -281,6 +324,7 @@ foreach ($client->getPackList() ?? [] as $id) {
DocKind::STATUS_DOC_NOTICE => $mapper->map($xml, new StatusDocNotice()),
DocKind::SETTINGS => $mapper->map($xml, new Settings()),
DocKind::BANK_STATEMENT => $mapper->map($xml, new Statement()),
DocKind::LETTER => $mapper->map($xml, new Letter()),
default => null,
};

Expand Down Expand Up @@ -315,7 +359,9 @@ foreach ($client->getPackList() ?? [] as $id) {
Все исходящие документы принимают необязательный дайджест: `setDigest(new DigestType($data, $algorithmVersion))`.
Как его формировать, стандарт не описывает — это делает внешняя компонента банка.

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

IP- и MAC-адреса клиента передаются в контейнере: `$packet->setSenderFootprint(new SenderFootprintType(['192.168.1.10'], ['00-1A-2B-3C-4D-5E']))`.

## Справочники

Expand Down Expand Up @@ -355,10 +401,11 @@ foreach ($client->getPackList() ?? [] as $id) {
| `CHECK` | `25` | Денежный чек |
| `CURRENCY_TRANSFER_ORDER` | `30` | Поручение на перевод валюты |
| `CURRENCY_STATEMENT` | `35` | Выписка по валютному счёту |
| `LETTER` | `40` | Письмо |

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

XSD-схемы формата лежат в [`tests/Fixture/xsd`](tests/Fixture/xsd).
XSD-схемы формата лежат в [`tests/Fixture/xsd`](tests/Fixture/xsd) (версия 2.3.2), схемы 2.2.2 — в [`tests/Fixture/xsd/2.2.2`](tests/Fixture/xsd/2.2.2).

## Тесты

Expand Down
10 changes: 6 additions & 4 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ class Client implements ClientInterface

protected array $settings = [
'customerId' => null,
'apiVersion' => DefaultValue::FORMAT_VERSION,
// Максимальная версия API, которую поддерживает клиент (заголовок AvailableAPIVersion в Logon)
'availableApiVersion' => DefaultValue::FORMAT_VERSION,
// Версия API обмена данными, по умолчанию FormatVersion::getDefault()
'apiVersion' => null,
// Максимальная версия API, которую поддерживает клиент (заголовок AvailableAPIVersion)
'availableApiVersion' => FormatVersion::LATEST,
'userAgent' => null,
'sessionId' => null,
'login' => null,
Expand All @@ -43,6 +44,7 @@ class Client implements ClientInterface
public function __construct(array $settings, private ?LoggerInterface $logger = null)
{
$this->settings = array_replace($this->settings, $settings);
$this->settings['apiVersion'] ??= FormatVersion::getDefault();

$this->validateSettings($this->settings);
}
Expand Down Expand Up @@ -83,7 +85,7 @@ public function confirmOtp(string $sessionId, string $otp): string

public function sendPack(Packet $packet): string
{
$result = $this->invoke('POST', 'SendPack', (string) $packet);
$result = $this->invoke('POST', 'SendPack', DefaultValue::BOM . $packet);

$response = $result->getSuccess()->getSendPacketResponse()
?? throw new UnexpectedResponseException('Bank response to SendPack has no SendPacketResponse.');
Expand Down
5 changes: 4 additions & 1 deletion src/Dictionary/DefaultValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

class DefaultValue
{
const FORMAT_VERSION = '2.2.2';
const FORMAT_VERSION = '2.3.2';

//UTF-8 BOM: с версии 2.3.x транспортный контейнер и файлы вложений всегда передаются с ним
const BOM = "\xEF\xBB\xBF";

//Формат отметки времени в GetPackList: dd.MM.yyyy HH:mm:ss
const TIMESTAMP_FORMAT = 'd.m.Y H:i:s';
Expand Down
5 changes: 4 additions & 1 deletion src/Dictionary/DocKind.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Коды видов электронных документов
*
* @see https://github.com/1C-Company/DirectBank/blob/2.2.2/doc/common-section/tables.md#ed
* @see https://github.com/1C-Company/DirectBank/blob/2.3.2/doc/common-section/tables.md#ed
*/
class DocKind
{
Expand Down Expand Up @@ -65,6 +65,9 @@ class DocKind
//Выписка по валютному счету (1С <-- Банк)
const CURRENCY_STATEMENT = '35';

//Письмо (1С <--> Банк), с версии 2.3.1
const LETTER = '40';

//Обязательные виды электронных документов
const REQUIRED = [
self::STATUS_DOC_NOTICE,
Expand Down
4 changes: 2 additions & 2 deletions src/Dictionary/DocStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
/**
* Коды статусов электронных документов
*
* @see https://github.com/1C-Company/DirectBank/blob/2.2.2/doc/common-section/tables.md#status
* @see https://github.com/1C-Company/DirectBank/blob/2.3.2/doc/common-section/tables.md#status
*/
class DocStatus
{
//Принят: электронный документ прошел первичный контроль и поступил в обработку
const ACCEPTED = '01';
//Исполнен: платежный документ исполнен банком
const EXECUTED = '02';
//Отклонен банком: платеж не удалось исполнить
//Отклонен банком: платеж не удалось исполнить, запрос не удалось выполнить
const REJECTED = '03';
//Приостановлен: платежный документ отложен банком из-за недостатка средств на счете
const SUSPENDED = '04';
Expand Down
2 changes: 1 addition & 1 deletion src/Dictionary/ErrorCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Коды ошибок банковского сервиса
*
* @see https://github.com/1C-Company/DirectBank/blob/2.2.2/doc/common-section/tables.md#errors
* @see https://github.com/1C-Company/DirectBank/blob/2.3.2/doc/common-section/tables.md#errors
*/
class ErrorCode
{
Expand Down
2 changes: 1 addition & 1 deletion src/Dictionary/PacketStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Коды статусов транспортных контейнеров
*
* @see https://github.com/1C-Company/DirectBank/blob/2.2.2/doc/common-section/tables.md#packet
* @see https://github.com/1C-Company/DirectBank/blob/2.3.2/doc/common-section/tables.md#packet
*/
class PacketStatus
{
Expand Down
2 changes: 1 addition & 1 deletion src/Dictionary/StatementType.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/**
* Типы выписок банка
*
* @see https://github.com/1C-Company/DirectBank/blob/2.2.2/doc/common-section/tables.md#statementType
* @see https://github.com/1C-Company/DirectBank/blob/2.3.2/doc/common-section/tables.md#statementType
*/
class StatementType
{
Expand Down
40 changes: 40 additions & 0 deletions src/FormatVersion.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);

namespace TTBooking\DirectBank;


use TTBooking\DirectBank\Dictionary\DefaultValue;

/**
* Версия формата обмена по умолчанию: для заголовка APIVersion клиента и атрибута formatVersion
* создаваемых документов. Разобранные документы сохраняют версию из XML.
*
* Для банка, который поддерживает только 2.2.x: FormatVersion::setDefault('2.2.2').
*/
final class FormatVersion
{
//Последняя версия стандарта, которую поддерживает библиотека
const LATEST = DefaultValue::FORMAT_VERSION;

//Версии стандарта, которые поддерживает библиотека
const SUPPORTED = ['2.2.2', '2.3.2'];

private static string $default = self::LATEST;

public static function getDefault(): string
{
return self::$default;
}

public static function setDefault(string $version): void
{
if (! in_array($version, self::SUPPORTED, true)) {
throw new \InvalidArgumentException(sprintf(
'Unsupported format version "%s", supported: %s.', $version, implode(', ', self::SUPPORTED)
));
}

self::$default = $version;
}
}
Loading
Loading