Development of a 1C-Bitrix document generation module

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1177
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

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 (in b_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.