Протокол обмена информацией с 1С
- Установка:
composer require mavsan/laravel-1c-protocol
- Для версии Laravel ниже 11 используйте ветку (тестировалось только для версии Laravel 7!)
v7
:composer require mavsan/laravel-1c-protocol:v7.x-dev
. Там же инструкция в файлеreadme.md
. - Для версии Laravel 5 используйте ветку
v5
:composer require mavsan/laravel-1c-protocol:v5.x-dev
. Там же инструкция в файлеreadme.md
. - Зарегистрировать сервис-провайдер в
config/app.php
(для Laravel 5.4 и ниже)
/*
* Протокол обмена информацией с 1С
*/
Mavsan\LaProtocol\Providers\ProtocolProvider::class,
- Опубликовать конфигурацию и изменить при необходимости:
php artisan vendor:publish --tag=la1CProtocolConfig
- Проверить параметр middleware файла конфигурации. Значением этого параметра должен быть массив. В это массиве должен быть указан промежуточный слой (middleware) или группа промежуточных слоев, в котором как минимум - стартует сессия
\Illuminate\Session\Middleware\StartSession::class
. Если сессия не стартует - ничего работать не будет. Важно в этой-же группе middleware НЕ ДОЛЖНО быть класса шифрования куки\App\Http\Middleware\EncryptCookies::class
или любого другого способа шифрования куки, т.к. в 1С передается id сессии как есть или если по приходу от 1С будет произведена попытка шифрации/дешифрации - ничего хорошего из этого не будет. - При необходимости осуществлять выгрузку информации с сайта в 1С можно поставить готовый пакет с минимально необходимым функционалом (которого, обычно, хватает с головой)
composer require arsengoian/commerce-ml
, см. раздел Отправка данных в 1С. - В случае, если необходима выгрузка данных о заказах в 1С, но чем-то не устраивает пакет, рекомендуемый выше (например в 1С какой-то уникальный модуль обмена, который не распознает версию XML или еще что, это-же 1С) - можете написать свой обработчик выгрузки, см. раздел Отправка данных в 1С.
- Создать модель, которая будет обрабатывать пришедшие данные. Модель должна реализовывать интерфейс
\Mavsan\LaProtocol\Interfaces\Import
. Если на стороне 1С используется модуль обмена 1С Битрикс необходимо, чтобы эта модель так-же реализовывала интерфейс\Mavsan\LaProtocol\Interfaces\ImportBitrix
. Контроллер обмена в нужный момент создает эту модель и вызывает методimport
, передавая туда полный путь к файлу, который необходимо обработать. Имя этого файла присылает 1С. В файле конфигурации прописать эту модель:
'catalogWorkModel' => \App\Model::class,
Если на стороне 1С используется модуль обмена 1C Битрикс
Протокол обмена с 1С Битрикс отличается от стандартного. В файле конфигурации необходимо настроить соответствующие параметры:
isBitrixOn1C=true
в этом случае в 1С будет отправляться желаемая версия файла обмена с данными каталога и версия XML с данными о заказах. Собственно только из-за того, что при отправке информации о заказах необходимо отправлять версию файла обмена и был введен этот и другие, касающиеся битрикса параметры. Кроме этого отправляется CSRF.saleXmlVersion
версия XML с данными и о заказах, т.к. я не нашел ни какого описания версий 1С Битрикс, то ставлю там то, что предлагают на сайте с описанием протокола, т.е.2.03
. На момент написания этого текста - несмотря на то, что в 1С улетает требование версии 2.03 1C все-равно присылает версию 3.1. Возможно они что-то изменили, но забыли в доку написать или я что-то не правильно понял, нужна помощь.catalogXmlVersion
версия XML с данными и о заказах, тоже ставлю, как описано в стандарте -2.08
.
Как работает
Сервис провайдер регистрирует роут, с url, указанным в файле конфигурации. 1C стучится по этому ури и отсылает команды, описанные в стандарте.
Для аутентификации соединения должен быть создан пользовать. Его имя пользователя и пароль присылает 1C. Верификация пользователя производится как обычно: Auth::attempt(['email' => $user, 'password' => $pass])
.
Контроллер обрабатывает эти команды, отсылая требуемые ответы.
При приеме файлов подчищаются файлы предыдущих обменов, т.к. в протоколе не описана команда, что обмен завершен. Если файл zip - после получения он автоматически распаковывается.
Как выполнить тестирование
Внимание! Для тестирования используется пакет madnest/madzipper для работы с ZIP архивом. Если будете использовать предложенный мной тест - необходимо добавить его в ваш composer
: composer require madnest/madzipper
.
При необходимости можно протестировать работу обмена, для этого в файле конфигурации пропишите:
// файл(ы) которые будут отосланы тестом для обработки, эмулируя отправку файлов 1С
'filesToSendTest' => ['fileName.zip'],
// файл(ы) которые требуется обработать моделью после получения, эмулируя отправку команд обработки 1С
'filesToWorkTest' => ['import.xml', 'offers.xml'],
Если в вашем файле обмена имеются подпапки, то в filesToWorkTest
путь упакованным в архив файлам необходимо указывать с указанием этих подпапок. В общем, структуру пути к файлам, как они запакованы в архиве, указанном в filesToSendTest
:
'filesToWorkTest' => ['import/import01.xml', 'import/import02.xml', 'offers.xml'],
PhpUnit должен использовать файл phpunit.xml
, который идет с этим модулем, или в стандартных тестах в phpunit.xml
необходимо прописать путь к тестам этого модуля:
<testsuites>
...
<testsuite name="1с Protocol">
<directory suffix="Test.php">./vendor/mavsan/laravel-1c-protocol/src/Tests/Unit</directory>
</testsuite>
...
</testsuites>
В версию 0.0.8 в файл конфигурации добавлена возможность изменить имя пользователя и пароль для тестов. Если пользователя нет - он создаётся, но не удаляется (актуально для тестов на реальной базе, а не в памяти).
Таким образом можно протестировать протокол обмена, а не сам обмен, т.е. нельзя проверить что было добавлено в таблицы, верность логики обмена.
Для полного тестирования лучше всего будет в /tests/Unit
создать свой тест, скопировав в него код из\Mavsan\LaProtocol\Tests\Unit\CatalogTest
(к сожалению, унаследовать нельзя, т.к. в этом случае будет ошибка phpunit: ’This test depends on ’) в методе testImport
, в котором выполняется отправка команды обработчику протокола - type=catalig&mode=import
, свои проверки лучше всего добавлять после полной обработки каталога:
public function testImport($session)
{
...
$this->importFiles($files, $session);
// вот тут
return $session;
}
Обратите внимание, что в каждой итерации метода testImport
происходит обновление приложения: $this->refreshApplication();
. Если этого не делать, то каждый POST
или GET
запрос в цикле будет один и тот же для всех обрабатываемых файлов, таким образом имя файла для тестов будет всегда передаваться одно и то же. Обратите внимание, что если вы используете память для тестирования БД, то при создании нового приложения эта БД в памяти будет обнуляться. Поэтому в качестве БД для тестов надо использовать что-то другое. Например, для DB_CONNECTION
значение sqlite
, а для DB_DATABASE
вместо значения :memory:
файл для sqlite
: sqlite.test
и это файл sqlite.test
надо предварительно создать.
Если есть необходимость протестировать работу файла обмена, стоит добавить в тесты несколько разных тестовых методов. Например: testCategories
, testProducts
, testContargents
и т.д. В этом случае тесты могут выглядеть вот так (вместо одного единственного теста testImport
):
#[Depends('testInit')]
public function testImportProducts()
{
$session = $this->testFile(); // отправка обычного файла обмена и получение сессии
$files = $this->getFilesToWorkTest('goods');
$this->importFiles($files, $session);
$model = Product::where('id1c', 'ИД товара в 1С')->first();
$this->assertCount('name', $model->name);
...
// проверка удаления/восстановления/изменения
$session = $this->sendRestoreRemoveExchangeFiles();
$this->importFiles($files, $session);
$model = Product::where('id1c', 'ИД товара в 1С')->first();
$this->assertCount('new name', $model->name);
...
}
/**
* Файлы для обработки. Например, для импорта вам нужны не все файлы, указанные в конфиге, а только их часть:
* ['folder/goods_1.xml', ..., 'folder/goods_n.xml', 'folder2/clients_1.xml', ..., 'folder2/clients_n.xml', 'folder3/store_1.xml', ..., 'folder3/store_n.xml', ...]
* а нужны только goods.
*
* @param string $type тип файлов, например goods
* @return array
*/
protected function getFilesToWorkTest(string $type = ''): array
{
$files = config('protocolExchange1C.filesToWorkTest', []);
if (empty($files)) {
$files = ['fakeImportProtocolTest.txt'];
}
if (!empty($files)) {
$files = collect((array)$files)->filter(fn($file) => str_contains($file, $type))->toArray();
}
return (array)$files;
}
// отправка еще одно файла обмена, в котором содержатся измененные данные, для тестов
protected function sendRestoreRemoveExchangeFiles(): array|Store
{
return $this->sendFiles(['storage/test/fileToTest2.zip']);
}
Отправка данных заказа в 1С
Для выгрузки данных о заказах можно использовать пакет arsengoian/commerce-ml, который позволяет быстро реализовать выгрузку минимально необходимого количества данных. Это количества данных обычно вполне хватает. Имейте в виду, что этот пакет только формирует ответ в виде XML. Т.е. реализовывать модель, которая будет выбирать данные о заказах и передавать их для формирования ответа в виде XML в библиотеку arsengoian/commerce-ml
все равно прийдется.
Для начала необходимо установить пакет arsengoian/commerce-ml
, прописать модель, которая будет подготавливать данные о заказе в файле конфигурации в параметре saleShareModel
. Эта модель должна реализовывать интерфейс \Mavsan\LaProtocol\Interfaces\ExportOrders
.
В случае, если функционала не хватает, то в файле конфигурации, в параметре saleShareToXML
необходимо указать модель, которая реализует интерфейс \Mavsan\LaProtocol\Interfaces\ExportOrdersSelf
. Данная модель не только должна выбрать данные о заказе, но и сформировать XML, который будет отправлен 1С.
После того, как 1С отправит команду на получение данных о заказах - контроллер проверяет файл конфигурации. Если указана модель в параметре saleShareModel
, то будет запущено формирование ответа пакетом arsengoian/commerce-ml
.
Если параметр saleShareModel
пуст, то будет создан экземпляр класса, указанный в параметре saleShareToXML
. У этого класса будет вызван метод getXML()
. Этот метод должен вернуть данные в формате XML, которые и будут отправлены в 1С.
При этом необходимо учитывать, что параметр saleShareModel
имеет больший приоритет, т.е. если там что-то указано, то работа по формированию XML будет вестись пакетом arsengoian/commerce-ml
не зависимо от того - прописано ли что-то параметре конфигруации saleShareToXML
.
В некоторых случаях 1С может прислать команду success
. Тогда, если модель экспорта заказов реализует интерфейс Mavsan\LaProtocol\Interfaces\ExportSuccess
будет вызван метод stepSuccess()
.
1С-Битрикс
С версии модуля обмена 1С-Битрикс 6.5.0.0 применяется контейнерный механизм обмена документов. Т.е. каждый документ в файле обмена должен быть обернут в тэг <Контейнер>
см здесь. Предполагается, что каждый документ должен быть обернут в тег <Контейнер>
. Во всяком случае, когда приходит информация от 1С о заказах - все выглядит именно так: <КоммерческаяИнформация ...><Контейнер><Документ>...</Документ></Контейнер><Контейнер><Документ>...</Документ></Контейнер></КоммерческаяИнформация>
.
В какой-то из версий обмена модулем 1С-Битрикс более не применяется кодировка windows-1251
, т.е. XML с данными о заказах надо слать в кодировке utf-8
, к сожалению, я не выяснил, с какой версии модуля обмена 1С-Битрикс это произошло.
Мне так и не удалось корректно отправлять адресную информацию контагента (покупателя), для версии обмена CommerceML 3.1, поэтому эту информацию просто отправляю в комментарии к заказу. Возможно, в 1С какой-то справочник не настроен или что-то вроде того. Обратите внимание, что в доке указано, что Адрес доставки должен быть в теге <ЗначенияРеквизитов><ЗначениеРеквизита><Наименование>Адрес доставки</Наименование><Значение>Тут адрес доставки</Значение></ЗначениеРеквизита></ЗначенияРеквизитов>
. До того, как клиент что-то в 1С не изменил - адрес доставки сохранялся нормально.
Если ни разу не реализовывали обмен между сайтом и модулем 1С-Битрикс, то единственный совет, который я могу дать - поставить себе локально 1С (торренты в помощь), узнать какая версия модуля обмена 1С-Битрикс используется клиентом, узнать какая версия и какая конфигурация использует эту версию обмена. Найти, скачать и установить конфиграцию (опять-же торренты) и модуль обмена, создать в 1С базу с демонстрационными данными и тестировать, т.к. с первого (или даже сотого) раза может не заработать. В конфигруации 1С точку старта, я искал глобальным поиском по названию кнопки, с которой начинается обмен (в разных версиях модуля обмена может называться по-разному, см. в форме). При поиске надо отметить чекбоксом “Элементы форм”. Как попасть в конфигратор и прочее - ищите в интернетах.
Обработка данных каталога
На определенном этапе 1С отсылает команду начать обработку присланных файлов. Контроллер создает экземпляр объекта модели, указанной в конфигурации (ключ конфигурации - catalogWorkModel
) и вызывает метод import($fileName)
, где $fileName
- имя полный путь к файлу, который требуется обработать.
По мере работы этот метод должен возвращать:
self::answerSuccess
, если обработка файла завершена;slef::answerProgress
, если требуется продолжить обработку файла (например большой объём данных);slef::answerFailure
, если произошла ошибка.
В не зависимости от ответа - будет вызван метод getAnswerDetail()
, который должен вернуть детальный ответ или пустую строку. Например:
обработано 500 записей из 100500
;ошибка: у товара указана группа, но такой группы нет
файл успешно обработан
Если необходимо передать несколько строк - они должны быть разделены символов перевода каретки \n
.
1C-Битрикс
В случае, если на стороне 1С используется модуль обмена 1С-Битрикс, необходимо в файле конфигурации параметр isBitrixOn1C
установить в true
. Это заставит контроллер отправлять запросы в в виде, который требует модуль обмена 1C-Битрикс.
Если в настройках модуля обмена включена опция “Деактивировать товары и разделы, не попавшие в полную выгрузку” в конце обмена (а возможно и в каких-то других случаях) будет прислана команда deactivate
(в стандартном протоколе такой команды нет).
В этом случае, если модель обработки данных от 1С реализует интерфейс \Mavsan\LaProtocol\Interfaces\ImportBitrix
, будет вызван метод modeDeactivate($startTime)
этого интерфейса. Эта команда говорит, что необходимо очистить данные, которых не было в файле обмена. Т.е. надо обязательно при обработке каталога всем товарам и группам товаров, справочниками и т.д. (в общем всем записям, которые прилетели и не должны быть удалены) - обязательно устанавливать дату обновления updated_at
, чтобы в методе modeDeactivate($startTime)
вы знали, что надо удалять.
Собственно вот это $startTime
и есть метка времени начала обработки. Его отсылает контроллер вместе с другими параметрами, в самом начале обмена, при инициализации сессии. Это метка времени, в формате date('Y-m-d H:i:s')
.
Последней от 1С-Битрикс прилетает команда complete
, если модель обработки данных от 1С реализует интерфейс \Mavsan\LaProtocol\Interfaces\ImportBitrix
, то будет вызван метод modeComplete()
этого интерфейса.
Описание
Протокол обмена информацией с 1С