1C-Bitrix Document Generation Module Development
Document generation — invoices, acts, contracts, delivery notes — is needed in every other Bitrix project. There are no standard tools for this: neither in sale nor in crm. The task is usually handled ad hoc via phpWord or done manually. The module provides a systematic approach: templates, variables, versioning, and signatures.
Where It Is Needed
Typical scenarios: an automatic invoice after an order is placed in an online store, a contract upon user registration in a B2B section, a work completion act for a closed CRM deal, a commercial proposal for a sales manager. In each case the document must be generated instantly, contain current data, and look professional.
Module Architecture
The vendor.docgen module with the following tables:
-
b_vendor_docgen_template— document templates: id, name, type (order/contract/act/offer), format (docx/pdf), template_file, variables_schema, version, is_active -
b_vendor_docgen_document— generated documents: id, template_id, entity_type, entity_id, file_id (inb_file), status, generated_at, generated_by -
b_vendor_docgen_variable— registered variables: name, source_class, description
Variable System
Each variable in the template is wrapped in double curly braces: {{ORDER_NUMBER}}, {{CLIENT_NAME}}, {{ITEMS_TABLE}}. Variables are registered via providers:
class OrderVariableProvider implements VariableProviderInterface
{
public function getVariables(int $entityId): array
{
$order = \Bitrix\Sale\Order::load($entityId);
$props = $order->getPropertyCollection();
return [
'ORDER_NUMBER' => $order->getField('ACCOUNT_NUMBER'),
'ORDER_DATE' => $order->getDateInsert()->format('d.m.Y'),
'ORDER_SUM' => number_format($order->getPrice(), 2, ',', ' '),
'ORDER_CURRENCY' => $order->getCurrency(),
'CLIENT_NAME' => $props->getPayerName(),
'CLIENT_INN' => $props->getUserProp('INN')?->getValue(),
'CLIENT_ADDRESS' => $props->getAddress(),
'ITEMS_TABLE' => $this->buildItemsTable($order->getBasket()),
];
}
}
Providers are registered in the module settings and are automatically applied during generation based on the document type.
DOCX Generation
Word templates are processed via PhpWord:
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($templatePath);
foreach ($variables as $name => $value) {
if (is_array($value)) {
// Table — clone rows
$templateProcessor->cloneRow('ITEM_NAME', count($value));
foreach ($value as $i => $item) {
$templateProcessor->setValue("ITEM_NAME#{$i}", $item['name']);
$templateProcessor->setValue("ITEM_QTY#{$i}", $item['quantity']);
$templateProcessor->setValue("ITEM_PRICE#{$i}", $item['price']);
}
} else {
$templateProcessor->setValue($name, htmlspecialchars($value));
}
}
$outputPath = '/upload/vendor_docgen/' . uniqid() . '.docx';
$templateProcessor->saveAs($outputPath);
PDF Conversion
DOCX is generated quickly, but clients often want PDF. Conversion is the most painful step. Options:
-
LibreOffice in headless mode:
libreoffice --headless --convert-to pdf file.docx— best quality, requires installation on the server - PhpSpreadsheet + mPDF — for HTML-template-based documents, easier style management
- DocRaptor / PDF Rocket — cloud services, no server-side software required
The converter is a parameter in the module settings. Default: mPDF for HTML templates, LibreOffice for DOCX.
HTML Templates
An alternative to Word templates — HTML with CSS. Easier to maintain, no encoding issues. The template is stored directly in b_vendor_docgen_template in the html_template field; variables are substituted via simple search-and-replace or Twig:
$loader = new \Twig\Loader\ArrayLoader(['doc' => $template['HTML_TEMPLATE']]);
$twig = new \Twig\Environment($loader);
$html = $twig->render('doc', $variables);
// Convert to PDF via mPDF
$mpdf = new \Mpdf\Mpdf(['mode' => 'utf-8', 'format' => 'A4']);
$mpdf->WriteHTML($html);
$mpdf->Output($outputPath, 'F');
Storage and Access
The finished file is saved via \CFile::SaveFile() into the b_file table — the standard Bitrix mechanism. The download link is generated via \CFile::GetPath(). The b_vendor_docgen_document table stores the file_id and metadata.
Document access is checked by ownership: a user can download a document linked to their order or profile. CRM managers can access documents for their own deals. Administrators have access to all documents.
Automatic Generation on Events
A document can be generated automatically when a Bitrix event fires:
// In init.php or via an event handler in the module installer
AddEventHandler('sale', 'OnSaleOrderPaid', ['\Vendor\DocGen\EventHandler', 'onOrderPaid']);
// In the handler class
public static function onOrderPaid(\Bitrix\Main\Event $event): void
{
$orderId = $event->getParameter('id');
DocGenerator::generate('invoice', 'sale_order', $orderId);
// → automatically attaches the document to the order and sends it to the buyer
}
Development Timeline
| Stage | Duration |
|---|---|
| Architecture, ORM tables, installer | 1 day |
| Variable system and data providers | 2 days |
| DOCX generation (PhpWord) | 2 days |
| PDF generation (mPDF or LibreOffice) | 1 day |
| HTML templates via Twig | 1 day |
| Storage, access, download | 1 day |
| Automatic generation on events | 1 day |
| Template administrative interface | 2 days |
| Testing | 1 day |
Total: 12 working days. Complex document layouts with headers, footers, signatures, and stamps — +2 days.







