Шаблон чека

Шаблон имеет строго определённую, но расширяемую структуру. Описание шаблона задаётся в формате JSON и содержит обязательные поля и переменные.

Базовая структура шаблона HTML-чека
{
   "width": 80,
   "margin_left": 0,
   "margin_right": 10,
   "img_id": 0,
   "show_storno_position": true,
   "strikeout_storno_position": true,
   "show_storno_payment": true,
   "strikeout_storno_payment": true,
   "variables": {
       "change": "(сдача)",
       "type_sale": "Продажа",
       "type_return": "Возврат",
       "tax_without_vat": "Без НДС"
   },
   "header": [...],
   "positions": [...],
   "position_totals": [...],
   "payments": [...],
   "payment_totals": [...],
   "footer": [...]
}
Глобальные поля шаблона
  • width — ширина ленты чека в миллиметрах (например, 80 для 80-мм термоленты, 58 для 58-мм и т.п.).
    Используется:

    • для установки CSS: @page { size: <width>mm auto; },
    • для вычисления ширины строки в символах (логика <SF>, <DF> и т.д.).
  • margin_left — логический отступ слева.

  • margin_right — логический отступ справа.

    В HTML-рендере margin_left и margin_right умножаются на внутренний коэффициент LayoutUnitToMm и переводятся в миллиметры:

    .cheque-container {
    padding-left:  margin_left  * LayoutUnitToMm (мм);
    padding-right: margin_right * LayoutUnitToMm (мм);
    }

    Это позволяет «подкручивать» поля визуально, не привязываясь к конкретному DPI.

  • img_id — идентификатор изображения (логотип/картинка) в базе.
    Если img_id > 0, при построении чека картинка один раз загружается из БД и может выводиться в любом блоке, где show_img = true.

  • show_storno_position (true / false) — отображать ли сторнированные позиции номенклатуры (позиции, у которых есть признак сторно или storno_uuid).

  • strikeout_storno_position (true / false) — зачёркивать ли сторнированные позиции.
    Работает только если show_storno_position = true.

  • show_storno_payment (true / false) — отображать ли сторнированные позиции оплат.

  • strikeout_storno_payment (true / false) — зачёркивать ли сторнированные оплаты.
    Аналогично позициям, работает только при show_storno_payment = true.

  • variables — набор текстовых констант, используемых в подстановках:

    • change — текст, добавляемый к типу оплаты для сдачи (payment.type_name).
      Значение по умолчанию: "(сдача)".

    • type_sale — текст для переменной <doc.type> в документах продажи.
      По умолчанию: "Продажа".

    • type_return — текст для переменной <doc.type> в документах возврата.
      По умолчанию: "Возврат".

    • tax_without_vat — текст для позиций без НДС.
      По умолчанию: "Без НДС".


Базовые элементы шаблона

Каждый элемент массивов header, positions, position_totals, payments, payment_totals, footer — объект со следующей структурой:

{
   "text": "Строка текста с переменными",
   "font": "Lucida Console, 10pt, style=bold",
   "interval": 2,
   "alignment": 1,
   "show_img": false,
   "img_width": 0,
   "img_height": 0,
   "barcode_height": 0,
   "barcode_module": 0,
   "barcode_show_text": false,
   "barcode_type": 0
}

Общие поля элемента
  • text — текст шаблона строки. Может содержать:

    • переменные вида <doc.*>, <pos.*>, <payment.*> (описаны ниже);
    • спец-маркеры выравнивания <SF>, <DF>, <UF>, <EF>, <PF>, <AF>;
    • произвольный статический текст.
  • font — описание шрифта. В HTML-рендере используется для:

    • размера шрифта (Xpt),
    • жирности / курсива (style=bold, style=italic и т.п.),
    • семейства шрифта (опционально).

    По умолчанию, если font не указан или не распарсен, используется:

    font-family: 'Lucida Console', monospace;
    font-size: 10pt;
    line-height: 1.1;

    Если в font задан другой шрифт, он будет проброшен в HTML.
    Однако логика маркеров <SF>/<DF>/… рассчитана на моноширинный шрифт, поэтому рекомендуется во всех строках указывать именно Lucida Console или другой моноширинный шрифт.

    Примеры значений font:

    • "Lucida Console, 10pt"
    • "Lucida Console, 10pt, style=bold"
    • "Lucida Console, 8pt, style=italic"
  • interval — вертикальный интервал после строки.

    В HTML-рендере:

    margin-bottom = interval * LayoutUnitToMm (в мм)

    где LayoutUnitToMm — внутренний коэффициент пересчёта условных единиц шаблона в миллиметры.
    Пример: interval: 30margin-bottom: 30 * LayoutUnitToMm мм.

  • alignment — выравнивание строки:

    • 0 — по левому краю (class="left"),
    • 1 — по центру (class="center"),
    • 2 — по правому краю (class="right").
  • show_img — если true, в строке выводится глобальное изображение по img_id, а не текст.

  • img_width, img_height — размеры изображения в пикселях (CSS-свойства width/height); используются, только если show_img = true.

  • barcode_height, barcode_module, barcode_show_text, barcode_type — отвечают за вывод штрих-кода / QR-кода (см. отдельный раздел ниже).


Спец-маркеры заполнения (моноширинный режим)

В HTML-рендере строки считаются набранными моноширинным шрифтом. Для «символьного» выравнивания используются маркеры:

  • <SF> — заполнение пробелами (' '),
  • <DF> — заполнение символом '-',
  • <UF> — заполнение символом '_',
  • <EF> — заполнение символом '=',
  • <PF> — заполнение символом '+',
  • <AF> — заполнение символом '*'.

Алгоритм:

  1. В строке ищется маркер (например, <SF>).
  2. Маркер удаляется.
  3. Строка логически делится на левую и правую части по месту расположения маркера.
  4. В точку разрыва вставляются символы заполнения (' ', '-' и т.д.), пока общая длина строки не достигнет целевой ширины строки в символах.
  5. Целевая ширина строки в символах вычисляется эвристически на основе ширины ленты:

    lineWidthChars ≈ floor(widthMm / 2.0)

    Например:

    • при width = 80 → ~40 символов,
    • при width = 58 → ~29 символов.

Это позволяет, например, задать:

{
  "text": "Всего:<SF><pos.total.price>",
  "font": "Lucida Console, 10pt",
  "alignment": 0
}

и получить строку, где сумма «прилипает» к правому краю строки без использования таблиц.

Изображения (логотип)

Для вывода логотипа/любого общего изображения используется:

  1. Глобально: поле img_id в корне шаблона.
    Если img_id > 0, при построении чека картинка загружается один раз из БД и сохраняется в памяти.

  2. В элементах: show_img:

    • если show_img: true, текст в поле text игнорируется, и вместо него выводится изображение из img_id;
    • img_width и img_height задают размеры изображения в пикселях (CSS width/height).

Пример:

{
   "text": "",
   "font": "",
   "interval": 30,
   "alignment": 1,
   "show_img": true,
   "img_width": 180,
   "img_height": 180
}

В HTML рендерится как:

<div class="line center">
  <img src="data:image/png;base64,..." style="width:180px;height:180px;">
</div>
Штрих-коды и QR-коды

Если в элементе задано barcode_type > 0, строка рендерится как изображение штрих-кода/QR-кода:

  • текст text сначала обрабатывается подстановками (<doc.*>, <pos.*>, <payment.*>),
  • затем по результату генерируется картинка.

Поля:

  • barcode_height — желаемая высота линейного штрих-кода (EAN/Code128) в пикселях.
    Используется при генерации через BarcodeLib.

  • barcode_module — масштаб модуля штрих-кода:

    • для линейных кодов влияет на итоговую ширину,
    • для QR-кода используется как pixelsPerModule.
  • barcode_show_text (true / false) — отображать ли текст под штрих-кодом (только для линейных кодов: EAN13, EAN8, Code128).

  • barcode_type — тип кода:

    • 0 — нет штрих-кода (строка обычная, выводится текст),
    • 1 — EAN13,
    • 2 — EAN8,
    • 3 — Code128,
    • 4 — QR-код.

Пример линейного штрих-кода с кодом документа:

{
   "font": "Lucida Console, 10pt",
   "text": "<doc.code>",
   "barcode_height": 50,
   "barcode_module": 2,
   "barcode_show_text": false,
   "barcode_type": 3,
   "interval": 30,
   "alignment": 1
}
header — заголовок чека

Секция header содержит общую информацию по документу: код, дату, время, кассу, смену, кассира, покупателя и т.п.

"header": [
   {
       "text": "",
       "font": "",
       "interval": 30,
       "alignment": 1,
       "show_img": true,
       "img_width": 180,
       "img_height": 180
   },
   {
       "text": "Добро пожаловать",
       "font": "Lucida Console, 10pt, style=bold",
       "interval": 5,
       "alignment": 1
   },
   {
       "text": "Код:<SF><doc.code>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "<doc.date><SF><doc.time>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "Тип:<SF><doc.type>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "Касса:<SF>0000<doc.cash_id>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "Смена:<SF><doc.session>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "Кассир:<SF><doc.cashier_name>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 1
   },
   {
       "text": "<DF>",
       "font": "Lucida Console, 10pt",
       "interval": 3,
       "alignment": 1
   }
],

Доступные переменные в header:

  • doc.code — код документа продажи/возврата;
  • doc.date — дата регистрации чека;
  • doc.time — время регистрации чека;
  • doc.session — код кассовой смены;
  • doc.cashier_name — ФИО кассира;
  • doc.seller_name — ФИО продавца;
  • doc.type — тип документа (variables.type_sale / variables.type_return);
  • doc.cash_id — идентификатор кассы;
  • doc.cash_serial_num — серийный номер кассы (если используется);
  • doc.card_barcode — штрих-код карты покупателя;
  • doc.customer_main_phone — основной телефон покупателя;
  • doc.customer_full_name — ФИО покупателя;
  • doc.promo_balance — баланс бонусов до операции;
  • doc.promo_withdraw — сумма списанных бонусов;
  • doc.promo_enrollment — сумма начисленных бонусов;
  • doc.promo_new_balance — баланс бонусов после операции.

Особенность:
если document.card == null, строки, содержащие
<doc.card_barcode>, <doc.customer_full_name>, <doc.customer_main_phone> не выводятся (полностью скрываются).

positions — список позиций

Секция positions описывает, как выводить каждую позицию номенклатуры: наименование, количество, цену, НДС и т.д.

"positions": [
   {
       "text": "<pos.n>. <pos.item.name>[<pos.item.unit>]",
       "font": "Lucida Console, 10pt",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "<pos.quantity> x <pos.price> = <pos.amount>",
       "font": "Lucida Console, 10pt",
       "interval": 0,
       "alignment": 2
   },
   {
       "text": "в т.ч. НДС <pos.vat_amount> ",
       "font": "Lucida Console, 10pt",
       "interval": 2,
       "alignment": 2
   }
],

Переменные:

  • pos.n — порядковый номер позиции;

  • pos.item.name — наименование номенклатуры;

  • pos.item.code — код номенклатуры;

  • pos.item.articul — артикул;

  • pos.item.unit — единица измерения;

  • pos.item.unit2 — единица измерения с КДТ;

  • pos.item.kdt — количество в КДТ;

  • pos.item.size — размер;

  • pos.item.color — цвет;

  • pos.item.brand — бренд;

  • pos.item.producer — производитель;

  • pos.item.country — страна производителя;

  • pos.item.department — отдел;

  • pos.item.group — номенклатурная группа;

  • pos.quantity — количество (форматируется в ###,###,###,###,##0.00#;);

  • pos.price — цена;

  • pos.amount — сумма (pos.quantity * pos.price);

  • pos.full_price — цена без скидки;

  • pos.discount_value — скидка за единицу;

  • pos.discount_amount — сумма скидки по позиции (pos.quantity * pos.discount_value);

  • pos.vat.name — ставка НДС (или variables.tax_without_vat, если НДС нет);

  • pos.vat_amount — сумма НДС (или variables.tax_without_vat, если НДС нет);

  • pos.icps — ИКПУ;

  • pos.label — маркировка.

При сторно-позициях применяется логика show_storno_position / strikeout_storno_position из корня шаблона:

  • сторнированные позиции могут скрываться,
  • либо отображаться с зачёркнутым текстом.
position_totals — итоги по позициям

Секция position_totals выводит агрегированные значения по позициям: общую сумму, сумму скидок, итог к оплате.

"position_totals": [
   {
       "text": "<DF>",
       "font": "Lucida Console, 10pt",
       "interval": 3,
       "alignment": 1
   },
   {
       "text": "Всего:<SF><pos.total.price2>",
       "font": "Lucida Console, 10pt",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "Скидки:<SF><pos.total.discount>",
       "font": "Lucida Console, 10pt",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "К оплате:<SF><pos.total.price>",
       "font": "Lucida Console, 10pt, style=bold",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "<DF>",
       "font": "Lucida Console, 10pt",
       "interval": 3,
       "alignment": 1
   }
],

Переменные:

  • pos.total.price2 — полная сумма без учёта скидок;
  • pos.total.discount — общая сумма скидки;
  • pos.total.price — итоговая сумма с учётом скидки.
payments — список оплат

Секция payments описывает, как выводить каждую оплату (наличные, карта, бонусы, сдача и т.п.).

"payments": [
   {
       "text": "<payment.type_name><SF><payment.value>",
       "font": "Lucida Console, 10pt",
       "interval": 2,
       "alignment": 0
   }
],

Переменные:

  • payment.type_name — наименование типа оплаты.
    Для оплаты, являющейся сдачей (change_uuid не пустой), к названию автоматически добавляется variables.change.

  • payment.value — сумма по оплате.

Сторнированные оплаты (по has_storno / storno_uuid) обрабатываются аналогично позициям через настройки show_storno_payment и strikeout_storno_payment.

payment_totals — итоги по оплатам

Секция payment_totals показывает итог по внесённым оплатам и сдаче.

"payment_totals": [
   {
       "text": "<DF>",
       "font": "Lucida Console, 10pt",
       "interval": 3,
       "alignment": 1
   },
   {
       "text": "Оплачено:<SF><payment.total.payed_value>",
       "font": "Lucida Console, 10pt, style=bold",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "Сдача:<SF><payment.total.change_value>",
       "font": "Lucida Console, 10pt, style=bold",
       "interval": 2,
       "alignment": 0
   },
   {
       "text": "<DF>",
       "font": "Lucida Console, 10pt",
       "interval": 3,
       "alignment": 1
   }
],

Переменные:

  • payment.total.payed_value — общая сумма оплат (без сдачи);
  • payment.total.change_value — сумма сдачи (по модулю).

Секция footer — произвольный «подвал»: штрих-код чека, текст благодарности, рекламная информация, контакты и т.п.

"footer": [
   {
       "font": "Lucida Console, 10pt",
       "text": "<doc.code>",
       "barcode_height": 50,
       "barcode_module": 2,
       "barcode_show_text": false,
       "barcode_type": 3,
       "interval": 30,
       "alignment": 1
   },
   {
       "text": "Спасибо за покупку",
       "font": "Lucida Console, 10pt, style=bold",
       "interval": 3,
       "alignment": 1
   }
]

В footer доступны те же переменные, что и в блоке header , а также все возможности по штрих-кодам и спец-маркерам.