Банковские выписки и PHP — это просто

в 13:18, , рубрики: , php

В «1С Бухгалтерия» предусмотрен фомат обмена текстовой информацией с Банковскими системами. Именно в таком формате Банки предоставляют выписки по счетам Организаций.

Не так давно на одном из проектов возникла потребность «парсить» такие выписки и обрабатывать их. Тогда после поисков в интернете я обнаружил что: или я плохо ищу или люди не хотят делиться готовыми решениями.

Зайдя на сайт 1С я увидел, что формат вполне себе простой и понятный даже программисту без особого опыта.

Файл выписки представляет из себя простой текстовый документ.

Пример файла

1CClientBankExchange
ВерсияФормата=1.02
Кодировка=Windows
Отправитель=Cистема Солнышко Интернет-Банк
Получатель=Бухгалтерский учет, редакция 4.4
ДатаНачала=27.11.2013
ДатаКонца=27.11.2014
РасчСчет=12345678901234567890
СекцияРасчСчет
ДатаНачала=27.11.2013
ДатаКонца=27.11.2014
РасчСчет=12345678901234567890
НачальныйОстаток=0
ВсегоПоступило=68770
ВсегоСписано=68770
КонечныйОстаток=0
КонецРасчСчет
СекцияДокумент=Банковский ордер
Номер=1
Дата=26.12.2013
Сумма=1000
ДатаСписано=26.12.2013
ДатаПоступило=
ПлательщикСчет=12345678901234567890
Плательщик=ИНН 778899001122 Иванов Иван Иванович (ИП)
ПлательщикИНН= 778899001122
Плательщик1=Иванов Иван Иванович (ИП)
ПлательщикРасчСчет=12345678901234567890
ПлательщикБанк1=ОАО АКБ "Солнышко"
ПлательщикБанк2=г. МОСКВА
ПлательщикБИК=044525201
ПлательщикКорсчет=98765432198765432100
ПлательщикКорсчет=98765432198765432100
ПолучательСчет=89765456787654345678
Получатель=ИНН 7765434566775001001 ОАО АКБ "Солнышко"
ПолучательИНН=7765434566
Получатель1=ОАО АКБ "Солнышко"
ПолучательРасчСчет=89765456787654345678
ПолучательБанк1=ОАО АКБ "Солнышко"
ПолучательБанк2=г. МОСКВА
ПолучательБИК=044525201
ПолучательКорсчет=98765432198765432100
ВидОплаты=17
НазначениеПлатежа=Комиссия за открытие счета согласно тарифам ОАО АКБ "Солнышко"
КонецДокумента
СекцияДокумент=Платежное поручение
Номер=176
Дата=26.12.2013
Сумма=4770
ДатаСписано=
Плательщик=ИНН 7725747515772501001 ООО "ВИОСН"
ПлательщикИНН=7725747515
ПлательщикСчет=40702810822000034869
Плательщик1=ООО "ВИОСН"
ПлательщикРасчСчет=40702810822000034869
ПлательщикБанк1=АКБ "АБСОЛЮТ БАНК" (ОАО)
ПлательщикБанк2=г. МОСКВА
ПлательщикБИК=044525976
ПлательщикКорсчет=30101810500000000976
ДатаПоступило=26.12.2013
Получатель=ИНН 778899001122 ИП Иванов Иван Иванович
ПолучательИНН=778899001122
ПолучательСчет=12345678901234567890
Получатель1=ИП Иванов Иван Иванович
ПолучательРасчСчет=12345678901234567890
ПолучательБанк1=ОАО АКБ "Солнышко"
ПолучательБанк2=г. МОСКВА
ПолучательБИК=044525201
ПолучательКорсчет=98765432198765432100
ВидОплаты=01
СрокПлатежа=26.12.2013
Очередность=5
НазначениеПлатежа=Оплата по счету №1 от 26 декабря (за услуги по обслуживанию сайта ) НДС не облагается.
КонецДокумента
СекцияДокумент=Банковский ордер
Номер=1
Дата=10.01.2014
Сумма=20
ДатаСписано=10.01.2014
ДатаПоступило=
ПлательщикСчет=12345678901234567890
Плательщик=ИНН 778899001122 Иванов Иван Иванович (ИП)
ПлательщикИНН=778899001122
Плательщик1=Иванов Иван Иванович (ИП)
ПлательщикРасчСчет=12345678901234567890
ПлательщикБанк1=ОАО АКБ "Солнышко"
ПлательщикБанк2=г. МОСКВА
ПлательщикБИК=044525201
ПлательщикКорсчет=98765432198765432100
ПолучательСчет=70601810200021210220
Получатель=ИНН 7765434566775001001 ОАО АКБ "Солнышко"
ПолучательИНН=7765434566
Получатель1=ОАО АКБ "Солнышко"
ПолучательРасчСчет=70601810200021210220
ПолучательБанк1=ОАО АКБ "Солнышко"
ПолучательБанк2=г. МОСКВА
ПолучательБИК=044525201
ПолучательКорсчет=98765432198765432100
ВидОплаты=17
НазначениеПлатежа=Плата за прием и обработку платежных документов
КонецДокумента
СекцияДокумент=Платежное поручение
Номер=1
Дата=10.01.2014
Сумма=3500
ДатаСписано=10.01.2014
Плательщик=ИНН 778899001122772801001 Иванов Иван Иванович (ИП)
ПлательщикИНН=778899001122
ПлательщикСчет=12345678901234567890
Плательщик1=Иванов Иван Иванович (ИП)
ПлательщикРасчСчет=12345678901234567890
ПлательщикБанк1=ОАО АКБ "Солнышко"
ПлательщикБанк2=г. МОСКВА
ПлательщикБИК=044525201
ПлательщикКорсчет=98765432198765432100
ДатаПоступило=
Получатель=ИНН 7707704692772801001 ОАО "Единая электронная торговая площадка"
ПолучательИНН=7707704692
ПолучательСчет=40702810000760001497
Получатель1=ОАО "Единая электронная торговая площадка"
ПолучательРасчСчет=40702810000760001497
ПолучательБанк1=ОАО "БАНК МОСКВЫ"
ПолучательБанк2=г. МОСКВА
ПолучательБИК=044525219
ПолучательКорсчет=30101810500000000219
ВидОплаты=01
СтатусСоставителя=01
ПлательщикКПП=772801001
ПолучательКПП=772801001
ПоказательКБК=00000000000000000000
ОКАТО=0
ПоказательОснования=0
ПоказательПериода=0
ПоказательНомера=0
ПоказательДаты=10.01.2014
ПоказательТипа=0
СрокПлатежа=10.01.2014
Очередность=5
НазначениеПлатежа=Сумма 3500.00, в т.ч. НДС - 388,99
КонецДокумента
КонецФайла

Значит если документ текстовый то и «парсить» его легко. Данные в файле представлены в формате:

Секция
Ключ=Значение
КонецСекции

Следовательно достаточно принять файл за массив строк и начинать проходить по этому массиву циклом. Для удобства парсер возвращает массив объектов.

Document.php - Модель документа с правилами назначения

<?php

namespace bank;
class Document {

    public $doctype;
    public $inbankid;
    public $docdate;
    public $summ;
    public $outdate;
    public $indate;
    public $payeraccount;
    public $payerinfo;
    public $payerinn;
    public $payer;
    public $payerdealaccount;
    public $payerbank1;
    public $payerbank2;
    public $payerbik;
    public $payerfixaccount;
    public $recieveraccount;
    public $recieverinfo;
    public $recieverinn;
    public $reciever1;
    public $recieverdealaccount;
    public $recieverbank1;
    public $recieverbank2;
    public $recieverbik;
    public $recieverfixaccount;
    public $paytype;
    public $paydirection;
    public $makerstatus;
    public $payerkpp;
    public $recieverkpp;
    public $showerkbk;
    public $okato;
    public $showerfundament;
    public $showerperiod;
    public $showernumber;
    public $showerdate;
    public $showertype;
    public $paymentperiod;
    public $quenue;

    public function __construct() {
        
    }

    public function rules($rule) {
        $rules = [
            'СекцияДокумент' => 'doctype',
            'Номер' => 'inbankid',
            'Дата' => 'docdate',
            'Сумма' => 'summ',
            'ДатаСписано' => 'outdate',
            'ДатаПоступило' => 'indate',
            'ПлательщикСчет' => 'payeraccount',
            'Плательщик' => 'payerinfo',
            'ПлательщикИНН' => 'payerinn',
            'Плательщик1' => 'payer',
            'ПлательщикРасчСчет' => 'payerdealaccount',
            'ПлательщикБанк1' => 'payerbank1',
            'ПлательщикБанк2' => 'payerbank2',
            'ПлательщикБИК' => 'payerbik',
            'ПлательщикКорсчет' => 'payerfixaccount',
            'ПолучательСчет' => 'recieveraccount',
            'Получатель' => 'recieverinfo',
            'ПолучательИНН' => 'recieverinn',
            'Получатель1' => 'reciever1',
            'ПолучательРасчСчет' => 'recieverdealaccount',
            'ПолучательБанк1' => 'recieverbank1',
            'ПолучательБанк2' => 'recieverbank2',
            'ПолучательБИК' => 'recieverbik',
            'ПолучательКорсчет' => 'recieverfixaccount',
            'ВидОплаты' => 'paytype',
            'НазначениеПлатежа' => 'paydirection',
            'СтатусСоставителя' => 'makerstatus',
            'ПлательщикКПП' => 'payerkpp',
            'ПолучательКПП' => 'recieverkpp',
            'ПоказательКБК' => 'showerkbk',
            'ОКАТО' => 'okato',
            'ПоказательОснования' => 'showerfundament',
            'ПоказательПериода' => 'showerperiod',
            'ПоказательНомера' => 'showernumber',
            'ПоказательДаты' => 'showerdate',
            'ПоказательТипа' => 'showertype',
            'СрокПлатежа' => 'paymentperiod',
            'Очередность' => 'quenue',
        ];
        return $rules[$rule];
    }

    public function set($section, $param) {
        $rulled = $this->rules($section);
        $this->$rulled = $param;
    }

}
?>

Bank.php - Класс парсера документов
<?php

include 'Document.php'; //Подключаем файл модели

class Bank {

    protected $documents; // Свойство для хранения "отпарсенных" документов
    //Конструктор принимает на вход путь к файлу
    function __construct($fileaddr) {
        $maas = file($fileaddr); // Открываем файл как массив строк
        $documents = []; // Создаем пустой массив для хранения документов
        $docid = 0; // Устанавливаем счетчик ID документа на 0
        foreach ($maas as $key => $value) { //Начинаем парсить каждую строку
            $value2 = rtrim($value); // Тримируем правую сторону строки от управляющих символов
            $value2 = mb_convert_encoding($value2, "utf-8", "windows-1251"); // Конвертируем значение в utf-8 так как изначальная кодировка файла windows-1251
            $result = explode('=', $value2); // Разбиваем строку на Ключ => Значение
            if (count($result) == 2) { // Проверяем прошла ли разбивка
                if ($result[0] == 'СекцияДокумент') { //Если разбивка прошла и ключ результата СекцияДокумент то
                    $workflow = new Document(); //Создаем новый Объект
                }
                if (isset($workflow)) { //Если объект создан то 
                    $workflow->set($result[0], $result[1]); // Назначаем Свойство, Содержимое
                }
            } else { //Если разбивка не прошла
                if ($result[0] == 'КонецДокумента') { //То проверяем конец ли это документа 
                    $documents[$docid] = $workflow; //Добавляем в массив документов новый документ
                    $docid++; //Плюсуем счетчик
                }
            }
        }
        $this->documents = $documents; // Передаем массив документов в Свойство класса
    }

    function getDocs() { 
        return $this->documents; // Отдаем документы по запросу
    }

}
?>

Код для проверки

<?php
        include 'Bank.php'; //Подключаем парсер
        $file = 'export_to_1c.txt'; // Назначаем файл выписки
        $bank = new Bank($file); // Запускаем парсинг
        $docs = $bank->getDocs(); //Получаем все спарсенные документы

        var_dump($docs);// Дамп всех документов
?>

Применять данный «парсер» не рекомендуется на каких-то крупных проектах, так как класс не учитывает многих нюансов формата обмена.
Также нет никакой обработки ошибок. Данный класс создан только для ознакомительных целей и не претендует на гениальность, но с моей точки зрения как отправная точка вполне себе годен.

Спасибо за внимание и заранее спасибо за комментарии.

Автор: akryll

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js