Пример для схемы Таблица внутри повторяющихся блоков
|
---|
Загрузите шаблон с помощью метода documentgenerator.template.add. После этого можете создать
документ
Пример содержимого шаблона (Скачать пример): // Описание значений values 'values' => [ 'Title' => 'Welcome to my template', 'Description' => '<b>Description is here</b>', 'Picture' => null, // you can put here link to an image 'Events' => [ [ 'Title' => 'Automation', 'Description' => 'Some description of the automation event', 'SpeakerName' => '{Event1SpeakersSpeakerName}', 'SpeakerCompany' => '{Event1SpeakersSpeakerCompany}', 'SpeakerPosition' => '{Event1SpeakersSpeakerPosition}', ], [ 'Title' => 'Documents', 'Description' => 'This event is about document procession', 'SpeakerName' => '{Event2SpeakersSpeakerName}', 'SpeakerCompany' => '{Event2SpeakersSpeakerCompany}', 'SpeakerPosition' => '{Event2SpeakersSpeakerPosition}', ], ], 'EventsEventTitle' => 'Events.Event.Title', 'EventsEventDescription' => 'Events.Event.Description', 'EventsEventSpeakerName' => 'Events.Event.SpeakerName', 'EventsEventSpeakerCompany' => 'Events.Event.SpeakerCompany', 'EventsEventSpeakerPosition' => 'Events.Event.SpeakerPosition', 'Event1SpeakersSpeakerName' => 'Event1Speakers.Speaker.Name', 'Event1SpeakersSpeakerCompany' => 'Event1Speakers.Speaker.Company', 'Event1SpeakersSpeakerPosition' => 'Event1Speakers.Speaker.Position', 'Event1Speakers' => [ [ 'Name' => 'Ivan Petrov', 'Company' => 'Cool Ltd.', 'Position' => 'Core developer', ], [ 'Name' => 'Igor Milov', 'Company' => 'Cool Ltd.', 'Position' => 'Product Manager', ], ], 'Event2Speakers' => [ [ 'Name' => 'Sergey Ivanov', 'Company' => 'Devils corp.', 'Position' => 'Chief', ], ], 'Event2SpeakersSpeakerName' => 'Event2Speakers.Speaker.Name', 'Event2SpeakersSpeakerCompany' => 'Event2Speakers.Speaker.Company', 'Event2SpeakersSpeakerPosition' => 'Event2Speakers.Speaker.Position', ] // Описание полей fields 'fields' => [ 'Events' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Event', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event1Speakers' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Speaker', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event2Speakers' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Speaker', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event1SpeakersSpeakerName' => ['TITLE' => 'Event1SpeakersSpeakerName'], 'Event1SpeakersSpeakerCompany' => ['TITLE' => 'Event1SpeakersSpeakerCompany'], 'Event1SpeakersSpeakerPosition' => ['TITLE' => 'Event1SpeakersSpeakerPosition'], 'Event2SpeakersSpeakerName' => ['TITLE' => 'Event2SpeakersSpeakerName'], 'Event2SpeakersSpeakerCompany' => ['TITLE' => 'Event2SpeakersSpeakerCompany'], 'Event2SpeakersSpeakerPosition' => ['TITLE' => 'Event2SpeakersSpeakerPosition'], |
Примеры генерации документа
Здесь изложен полностью процесс генерации документа. Все примеры написаны на php через веб-хук.
Создание нумератора
Для начала создадим новый нумератор для реста с помощью documentgenerator.numerator.add
.
\Bitrix\Main\Loader::includeModule('rest'); $client = new \Bitrix\Main\Web\HttpClient(); $webHookUrl = 'http://mycrm.bitrix24.com/rest/1/webhookkey/'; $prefix = 'documentgenerator'; $data = [ 'fields' => [ 'name' => 'Rest Numerator', 'template' => '{NUMBER}', 'settings' => [ 'Bitrix_Main_Numerator_Generator_SequentNumberGenerator' => [ 'start' => '0', 'step' => '1', ], ], ], ]; $url = $webHookUrl.$prefix.'.numerator.add/'; $answer = $client->post($url, $data); try { $result = \Bitrix\Main\Web\Json::decode($answer); } catch(Exception $e) { var_dump($answer); } print_r($result);
Ответ
[result] => Array ( [numerator] => Array ( [name] => new rest numerator [template] => {NUMBER} [id] => 68 [settings] => Array ( [Bitrix_Main_Numerator_Generator_SequentNumberGenerator] => Array ( [start] => 0 [step] => 1 [periodicBy] => [timezone] => [isDirectNumeration] => ) ) ) )
Из ответа получаем id
нумератора и можем дальше его использовать.
Загрузка шаблона
Сначала необходимо загрузить шаблон. Весь код как в предыдущем примере, но другие входные данные и название метода:
documentgenerator.template.add
$data = [ 'fields' => [ 'name' => 'Rest Template', 'file' => base64_encode(file_get_contents($_SERVER['DOCUMENT_ROOT'].'/upload/rest_template.docx')), 'numeratorId' => 1, 'region' => 'ru', 'users' => ['UA'], 'providers' => ['Bitrix\\DocumentGenerator\\DataProvider\\Rest'], ], ]; $url = $webHookUrl.$prefix.'.template.add/';
Ответ
[result] => Array ( [template] => Array ( [id] => 203 [name] => Rest Template [region] => ru [code] => [download] => http://mycrm.bitrix24.com/bitrix/services/main/ajax.php?action=documentgenerator.template.download&id=203&ts=1539173306 [active] => Y [moduleId] => rest [numeratorId] => 1 [withStamps] => N [providers] => Array ( [bitrix\documentgenerator\dataprovider\rest] => bitrix\documentgenerator\dataprovider\rest ) [users] => Array ( [UA] => UA ) [isDeleted] => N [sort] => 500 [createTime] => 2018-10-10T14:08:26+02:00 [updateTime] => 2018-10-10T14:08:26+02:00 [downloadMachine] => http://mycrm.bitrix24.com/rest/1/webhookkey/documentgenerator.template.download/?token=documentgenerator%7CYWN0a // тут длинная ссылка ) )
Список полей
Проверим, что поля шаблона распознались правильно. Выполним метод documentgenerator.template.getfields
:
$data = [ 'id' => 203, 'providerClassName' => '\\Bitrix\\DocumentGenerator\\DataProvider\\Rest', 'value' => 1, ]; $url = $webHookUrl.$prefix.'.template.getfields/';
Ответ
[result] => Array ( [templateFields] => Array ( [DocumentNumber] => Array ( [title] => Номер [value] => 1 [group] => Array ( [0] => Документ ) [default] => 1 ) [SomeDate] => Array ( [value] => [default] => ) [SomeName] => Array ( [value] => [default] => ) [Stamp] => Array ( [value] => [default] => ) [Image] => Array ( [value] => [default] => ) [TableItemImage] => Array ( [value] => [default] => ) [TableItemName] => Array ( [value] => [default] => ) [TableItemPrice] => Array ( [value] => [default] => ) [TableIndex] => Array ( [value] => [default] => ) ) )
Как видим, все поля документа на месте.
Генерация простого документа
Если в документ необходимо вставить только простые текстовые данные, то надо в метод documentgenerator.document.add
передать только массив values
с текстовыми значениями:
$data = [ 'templateId' => 203, 'providerClassName' => 'Bitrix\\DocumentGenerator\\DataProvider\\Rest', 'value' => 1, 'values' => [ 'SomeDate' => '14.02.2018', 'SomeName' => 'Горелкин Владислав', ], ]; $url = $webHookUrl.$prefix.'.document.add/';
Но это самый простой случай. Теперь рассмотрим вариант, когда нам надо вставить картинки, печать, использовать модификатор для даты и имени, и заполнить таблицу несколькими значениями
Генерация документа с изображениями и печатями
Чтобы в документ передать сложные данные, не только в строковом формате, необходимо правильно сформировать параметр fields
. Для начала, заполним изображение и печать.
$data = [ 'templateId' => 203, 'providerClassName' => 'Bitrix\\DocumentGenerator\\DataProvider\\Rest', 'value' => 1, 'values' => [ 'SomeDate' => '14.02.2018', 'SomeName' => 'Горелкин Владислав', 'Stamp' => 'http://myrestapp.com/upload/stamp.png', // внешний путь к файлу печати 'Image' => 'http://myrestapp.com/upload/image.jpg', // внешний путь к файлу изображения ], 'fields' => [ 'Stamp' => ['TYPE' => 'STAMP'], // тип поля - печать 'Image' => ['TYPE' => 'IMAGE'], // тип поля - изображение ] ]; $url = $webHookUrl.$prefix.'.document.add/';
В массиве fields
можно указать тип поля, по ключу TYPE
.
- Для полей "Изображение" тип -
STAMP
- Для полей "Печать или подпись" тип -
IMAGE
В массиве values
в качестве значений необходимо указать абсолютный путь к файлу. Файл будет скачан по этому адресу и вставлен в документ.
Генерация документа с модификаторами даты и имени
Про сами модификаторы можно почитать здесь.
Использование модификаторов для дат и имён через REST не обязательно - входные данные могут быть заранее отформатированы самим приложением. Тем не менее, это может быть удобно. Поэтому в REST есть возможность использовать модификаторы. Для этого необходимо передать соответствующий тип поля в fields
. Также в fields
по ключу FORMAT
можно передать формат по умолчанию. Если в самом шаблоне у этого поля будет указан модификатор - будет применен модификатор шаблона.
Чтобы модификаторы работали для полей типа дата, необходимо передать их в следующем виде:
- в
values
дата должна быть передана в формате atom (как во всех rest-методах) - в
fields
TYPE
=DATE
- также в
fields
по ключуFORMAT['format']
можно передать модификатор по умолчанию (также, как в шаблоне)
Чтобы модификаторы работали для полей типа имя необходимо передать их в следующем виде:
- в
values
имя должно быть передано в виде массива
[ 'NAME' => 'Игорь', // имя 'LAST_NAME' => 'Иванов', // фамилия 'SECOND_NAME' => 'Петрович', // отчество 'GENDER' => 'M', // пол ]
По ключу GENDER
можно указать пол в явном виде (M
- мужской, F
- женский). Если пол не указан, то модуль попытается определить его по отчеству. Если отчество не указано - пол не будет определен и склонение не будет работать.
- в
fields
TYPE
=NAME
- в
fields
по ключуFORMAT['format']
можно передать формат по умолчанию - в
fields
по ключуFORMAT['case']
можно передать падеж по умолчанию
$data = [ 'templateId' => 203, 'providerClassName' => 'Bitrix\\DocumentGenerator\\DataProvider\\Rest', 'value' => 1, 'values' => [ 'SomeDate' => '2018-10-10T14:30:18+02:00', // значение передано в формате atom 'SomeName' => [ // имя передано в виде массива 'NAME' => 'Владислав', 'LAST_NAME' => 'Горелкин', 'GENDER' => 'M', ], ], 'fields' => [ 'SomeDate' => [ 'TYPE' => 'DATE', 'FORMAT' => [ 'format' => 'd f Y H:i', // формат вывода ], ], // тип поля - дата 'SomeName' => [ 'TYPE' => 'NAME', 'FORMAT' => [ // здесь можно передать формат поля по умолчанию 'case' => 0, // код падежа 'format' => '#NAME# #LAST_NAME#' // формат вывода ] ], // тип поля - имя ] ]; $url = $webHookUrl.$prefix.'.document.add/';
Генерация документа с данными в виде массива
В нашем тестовом шаблоне есть таблица, куда надо вставить картинку, название и цену товара. Модификаторы для цен нельзя использовать в ресте генератора документов, поэтому цену придётся передавать в виде сформированной строки.
Ниже рабочий пример кода, после него подробности.
$data = [ 'templateId' => 203, 'providerClassName' => '\\Bitrix\\DocumentGenerator\\DataProvider\\Rest', 'value' => 1, 'values' => [ 'Table' => [ [ 'Name' => 'Item name 1', 'Price' => '$111.23', 'Image' => 'http://myrestapp.com/upload/stamp.png' ], [ 'Name' => 'Item name 2', 'Price' => '$222.34', 'Image' => 'http://myrestapp.com/upload/stamp.png' ], ], 'TableItemName' => 'Table.Item.Name', 'TableItemImage' => 'Table.Item.Image', 'TableItemPrice' => 'Table.Item.Price', 'TableIndex' => 'Table.INDEX', ], 'fields' => [ 'Table' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Item', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'TableItemImage' => ['TYPE' => 'IMAGE'], ], ]; $url = $webHookUrl.$prefix.'.document.add/';
Напоминаем, что в шаблон вставлена таблица, в таблице три поля {TableItemName}, {TableItemImage}, {TableItemPrice}. Для начала посмотрим, как заполняется массив полей fields
.
- Передаем настройки поля
Table
. Такого поля в явном виде нет в шаблоне, но оно нам нужно, чтобы передать по этому ключу массив значений для таблицы. - Для этого поля нужно обязательно указать провайдера
fields['Table']['PROVIDER'] = 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider'
. Таким образом мы указываем, что по этому ключу придёт массив значений. - Надо заполнить массив настроек провайдера.
fields['Table']['OPTIONS']['ITEM_NAME'] = 'Item'
. Здесь мы передали внутренний ключ, по которому провайдер будет обращаться к элементам массива. fields['Table']['OPTIONS']['ITEM_PROVIDER'] = 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider'
- здесь указывается, что каждый элемент массива поляTable
по ключуItem
- это простой хеш.- Указываем, что поле
TableItemImage
является изображением - здесь всё как обычно.
Теперь про массив values
.
- По ключу
Table
передаем простой массив (с индексными последовательными ключами). Каждый элемент массива - это ассоциативный массив, где ключ - это правая часть поля, за исключениемTable
(название поля-массива) иItem
(название внутреннего ключа). - В качестве значения для самих полей таблицы передаем цепочку получения значения из провайдера. Строится она как последовательные коды провайдеров, разделенные точкой. В нашем случае это будет
Table
- название поля-массива, откуда получаются значения. Потом точка. ДальшеItem
- название внутреннего ключа провайдераTable
, по которому провайдер отдает элементы массива. Потом точка. Дальше идёт ключ внутреннего ассоциативного массива из элементовTable
. - У провайдера
ArrayDataProvider
есть внутренняя переменнаяINDEX
, которая указывает на текущий номер элемента (начиная с 1). Чтобы в поле {TableIndex} внутри таблицы подставился порядковый номер, было указаноvalues['TableIndex'] = 'Table.INDEX'
.
Если указать в качестве значения поля обычную строку, то она вставится в таблицу как есть во все строки.
Копирование таблиц
Начиная с версии 18.7.200 модуля documentgenerator появилась возможность создавать документы с вложенными списками, т.е. когда одно из значений списка первого уровня - это ещё один список (Внимание: работает только через REST и PHP API, через интерфейс такое не сделать).
Это может быть полезно, когда необходимо вставить несколько таблиц одинаковой структуры, но с разным количеством строк.
Основная идея заключается в том, что список первого уровня должен в качестве значений отдавать названия полей для внутренних списков. Все описания и значения полей должны быть переданы сразу. В массиве полей внешний список должен идти первым (т.к. поля обрабатываются в том же порядке, в котором они переданы в описании)
Этот способ можно использовать в схеме Таблица внутри повторяющихся блоков или Повторяющиеся блоки внутри повторяющихся блоков, но нельзя вставить таблицу внутри таблицы.
Пример для схемы Повторяющиеся блоки внутри повторяющихся блоков
|
---|
Загрузите шаблон с помощью метода documentgenerator.template.add. После этого можете создать
документ
Пример содержимого шаблона (Скачать пример): <?php require_once($_SERVER['DOCUMENT_ROOT'].'/rest_test/rest.php'); $templateId = 58; $entityTypeId = 2; $entityid = 28; $action = new RestAction('document', 'add'); $action->setPrefix('crm.documentgenerator'); $data = [ 'templateId' => $templateId, 'entityTypeId' => $entityTypeId, 'entityId' => $entityid, 'values' => [ 'Title' => 'Welcome to my template', 'Description' => '<b>Description is here</b>', 'Picture' => null, // you can put here link to an image 'Events' => [ [ 'Title' => 'Automation', 'Description' => 'Some description of the automation event', 'SpeakerName' => '{Event1SpeakersSpeakerName}', 'BlockStart' => '{Event1Speakers.BLOCK_START}', 'BlockEnd' => '{Event1Speakers.BLOCK_END}', 'SpeakerCompany' => '{Event1SpeakersSpeakerCompany}', 'SpeakerPosition' => '{Event1SpeakersSpeakerPosition}', ], [ 'Title' => 'Documents', 'Description' => 'This event is about document procession', 'BlockStart' => '{Event2Speakers.BLOCK_START}', 'BlockEnd' => '{Event2Speakers.BLOCK_END}', 'SpeakerName' => '{Event2SpeakersSpeakerName}', 'SpeakerCompany' => '{Event2SpeakersSpeakerCompany}', 'SpeakerPosition' => '{Event2SpeakersSpeakerPosition}', ], ], // 'Events' => [ // [ // 'Title' => 'Automation', // 'Description' => 'Some description of the automation event', // 'SpeakerName' => '__Event1SpeakersSpeakerName__', // 'BlockStart' => '__Event1Speakers.BLOCK_START__', // 'BlockEnd' => '__Event1Speakers.BLOCK_END__', // 'SpeakerCompany' => '__Event1SpeakersSpeakerCompany__', // 'SpeakerPosition' => '__Event1SpeakersSpeakerPosition__', // ], // [ // 'Title' => 'Documents', // 'Description' => 'This event is about document procession', // 'BlockStart' => '__Event2Speakers.BLOCK_START__', // 'BlockEnd' => '__Event2Speakers.BLOCK_END__', // 'SpeakerName' => '__Event2SpeakersSpeakerName__', // 'SpeakerCompany' => '__Event2SpeakersSpeakerCompany__', // 'SpeakerPosition' => '__Event2SpeakersSpeakerPosition__', // ], //], 'EventsEventTitle' => 'Events.Event.Title', 'EventsEventDescription' => 'Events.Event.Description', 'EventsEventSpeakerName' => 'Events.Event.SpeakerName', 'EventsEventBlockStart' => 'Events.Event.BlockStart', 'EventsEventBlockEnd' => 'Events.Event.BlockEnd', 'EventsEventSpeakerCompany' => 'Events.Event.SpeakerCompany', 'EventsEventSpeakerPosition' => 'Events.Event.SpeakerPosition', 'Event1SpeakersSpeakerName' => 'Event1Speakers.Speaker.Name', 'Event1SpeakersSpeakerCompany' => 'Event1Speakers.Speaker.Company', 'Event1SpeakersSpeakerPosition' => 'Event1Speakers.Speaker.Position', 'Event1Speakers' => [ [ 'Name' => 'Ivan Petrov', 'Company' => 'Cool Ltd.', 'Position' => 'Core developer', ], [ 'Name' => 'Igor Milov', 'Company' => 'Cool Ltd.', 'Position' => 'Product Manager', ], ], 'Event2Speakers' => [ [ 'Name' => 'Sergey Ivanov', 'Company' => 'Devils corp.', 'Position' => 'Chief', ], ], 'Event2SpeakersSpeakerName' => 'Event2Speakers.Speaker.Name', 'Event2SpeakersSpeakerCompany' => 'Event2Speakers.Speaker.Company', 'Event2SpeakersSpeakerPosition' => 'Event2Speakers.Speaker.Position', ], 'fields' => [ 'Events' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Event', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event1Speakers' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Speaker', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event2Speakers' => [ 'PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\ArrayDataProvider', 'OPTIONS' => [ 'ITEM_NAME' => 'Speaker', 'ITEM_PROVIDER' => 'Bitrix\\DocumentGenerator\\DataProvider\\HashDataProvider', ], ], 'Event1SpeakersSpeakerName' => ['TITLE' => 'Event1SpeakersSpeakerName'], 'Event1SpeakersSpeakerCompany' => ['TITLE' => 'Event1SpeakersSpeakerCompany'], 'Event1SpeakersSpeakerPosition' => ['TITLE' => 'Event1SpeakersSpeakerPosition'], 'Event2SpeakersSpeakerName' => ['TITLE' => 'Event2SpeakersSpeakerName'], 'Event2SpeakersSpeakerCompany' => ['TITLE' => 'Event2SpeakersSpeakerCompany'], 'Event2SpeakersSpeakerPosition' => ['TITLE' => 'Event2SpeakersSpeakerPosition'] ] ]; $result = $action->run($data, 'document'); echo '<pre>'; print_r($result); echo '</pre>'; |
Сообщение не промодерировано, возможны ошибки и неточности.
|
||
Предупреждение для тех, кто решит делать сложный проект через REST API, используя конструкции, подобные "Таблица внутри повторяющихся блоков", которая описана выше.
Здесь есть не описанные ограничения! Я о них не знал и пожалел. Обработка запроса генерации документов, идущего на облачный сервер Битрикс, очень тяжелая. Чем больше в шаблоне динамических данных, тем она тяжелее. В нашем проекте был полностью динамически формируемый документ с высокой вариативностью, из-за чего пришлось все делать такими конструкциями. И примерно при 3 конструкциях "Таблица внутри повторяющихся блоков", каждая из которых содержала примерно 3 таблицы (это было всего 5 страниц в текстовом документе), сервер Битрикса стал не справляться и выдавать ошибку INTERNAL_SERVER_ERROR, документ при этом не создается вообще. То есть именно с обработкой этих запросов могут быть большие задержки, и можно неожиданно упереться в неописанное ограничение при относительно небольшом объеме документа. Решения у данной проблемы нет, кроме как использовать для генерации документов какую-то свою коробку вместо облака (там нет этих ограничений). В ТП заявка по проблеме есть, под номером 161135. Сервер Битрикса начинает отклонять запросы, когда не может выполнить их за 60 секунд. Через curl_getinfo можно отслеживать этот параметр для текущего запроса, чтобы понимать, где находится допустимая граница. Пример логов отклоненного запроса:
| ||
Пользовательские комментарии
Мы будем рады, если разработчики добавят свои комментарии по практическому использованию методов системы.Для этого нужно всего лишь авторизоваться на сайте
Но помните, что Пользовательские комментарии, несмотря на модерацию, не являются официальной документацией. Ответственность за их использование несет сам пользователь.
Также Пользовательские комментарии не являются местом для обсуждения функционала. По подобным вопросам обращайтесь на форумы.