Документація/Налаштування пристроїв

Адміністратору

Мова шаблонів — Chunk

Поля, фільтри, умови та цикли Chunk Templates у друкованих формах PalmOrder.

Друковані форми PalmOrder використовують Chunk Templates — мову шаблонів для підстановки даних, форматування значень, умов і циклів. Вона працює і в HTML-шаблонах для PDF, і в шаблонах .prn для друку на принтері.

Під час формування документа застосунок обробляє команди Chunk та підставляє значення полів. У PDF-формі HTML і CSS задають вигляд сторінки, а Chunk визначає, які дані на ній показати.

Щоб створити власну PDF-форму, візьміть готовий приклад, змініть HTML і використовуйте синтаксис нижче. Порядок передавання файлів на пристрій описано на сторінці Налаштування друку.

Основні конструкції

ЗаписПризначення
{$doc.number}Підставити значення поля.
{$doc.customer_name|html}Підставити текст із захистом спеціальних символів HTML.
{$row.price|decimal}Вивести число з двома знаками після десяткового роздільника.
{% if (…) %}…{% endif %}Показати фрагмент за умовою.
{% loop in $table as $row %}…{% endloop %}Повторити фрагмент для кожного рядка документа.
{!-- Коментар --}Коментар, який не потрапить у результат.

Звичайний текст та HTML поза командами залишаються у формі. Імена полів і команд пишіть точно, з урахуванням регістру: doc.number та doc.Number — різні імена.

Поля та групи даних

Значення поля записується як {$ім'я}. Крапка відокремлює групу даних від поля:

<h1>Замовлення № {$doc.number|html}</h1>
<p>Дата: {$doc.date_localized|html}</p>
<p>Клієнт: {$doc.customer_name|html}</p>

Для замовлення доступні такі групи:

ГрупаЩо містить
docПоля шапки документа: number, customer_name, sum, discount та інші. date_localized — дата в локалізованому форматі.
doc.customerПоля клієнта з довідника: наприклад, doc.customer.code.
weРеквізити компанії: company, address, registration, billing, comment.
tableРядки табличної частини. Їх перебирають у циклі.
rowПоточний рядок усередині циклу, якщо йому задано ім'я row.
row.productПоля товару з довідника для поточного рядка.

Поля документа та довідників мають відповідати вашим схемам даних. Наприклад, {$doc.customer.address|html} доступне, якщо довідник клієнтів містить поле address і для документа знайдено клієнта.

Реквізити we заповнюються на пристрої в Налаштування → Друк → Реквізити.

Відсутнє та порожнє значення

Якщо поля немає, звичайний тег може залишитися в результаті як текст {$doc.some_field}. Після двокрапки можна вказати текст замість відсутнього значення:

<p>Примітка: {$doc.info|html:Не вказано}</p>

Порожнє значення після двокрапки прибирає відсутній тег:

<p>{$doc.info|html:}</p>

Двокрапка задає заміну лише для відсутнього значення. Якщо поле є, але містить порожній рядок, використовуйте onempty:

<p>Примітка: {$doc.info|onempty(Не вказано)|html}</p>

Цей запис показує «Не вказано» і для відсутнього поля, і для порожнього рядка. Щоб прибрати весь абзац разом із підписом, використовуйте умову.

Фільтри та форматування

Фільтр записується після вертикальної риски |. Кілька фільтрів виконуються зліва направо:

<p>{$doc.info|onempty(Без примітки)|html}</p>

Спочатку onempty підставляє текст для порожнього значення, потім html готує його для HTML.

ФільтрПрикладРезультат
html{$row.name|html}Символи &, <, > та лапки відображаються як текст і не порушують HTML.
decimal{$row.price|decimal}Два знаки після десяткового роздільника: наприклад, 42,50.
number{$row.count|number}Число без зайвих кінцевих нулів, до шести знаків після десяткового роздільника: наприклад, 2,5.
onempty(текст){$doc.info|onempty(Не вказано)|html}Текст замість відсутнього або порожнього значення.
trim{$doc.customer_name|trim|html}Прибирає пробіли на початку та в кінці тексту.
uc{$we.company|uc|html}Переводить текст у верхній регістр.
lc{$doc.customer.code|lc|html}Переводить текст у нижній регістр.

decimal і number — фільтри PalmOrder. Роздільники чисел залежать від налаштувань мови пристрою; приклади вище наведено для української.

Для HTML-форм додавайте html до текстових полів: назв товарів, клієнтів, реквізитів і приміток. У текстових шаблонах .prn цей фільтр не потрібний.

Для числового поля також може бути доступний тег із суфіксом _display, наприклад {$row.count_display}. Він містить значення з точністю, заданою в налаштуваннях колонки на пристрої. Такий тег формується для числових полів, які мають відповідні налаштування колонок.

Вирівнювання тексту та чисел

У PDF-формах — HTML і CSS

У PDF-формі вирівнювання задається стилем text-align: left — ліворуч, center — по центру, right — праворуч. Наприклад, заголовок можна розмістити по центру, назви товарів — ліворуч, а кількість і суми — праворуч:

<h1 style="text-align: center;">Замовлення № {$doc.number|html}</h1>
<table style="width: 100%;">
  <tbody>
    {% loop in $table as $row %}
    <tr>
      <td style="text-align: left;">{$row.name|html}</td>
      <td style="text-align: right;">{$row.count|number}</td>
      <td style="text-align: right;">{$row.sum|decimal}</td>
    </tr>
    {% onEmpty %}
    <tr>
      <td colspan="3">У документі немає товарів</td>
    </tr>
    {% endloop %}
  </tbody>
</table>

Для однакового оформлення багатьох комірок винесіть стилі в класи всередині <style>, як у готовому HTML-шаблоні.

У текстових формах .prn — sprintf

Для колонок фіксованої ширини використовуйте фільтр Chunk sprintf. Він доповнює значення пробілами до заданої ширини:

ФорматПрикладРезультат
%20s{$row.name|sprintf(%20s)}Текст праворуч у полі щонайменше на 20 символів; пробіли додаються зліва.
%-20s{$row.name|sprintf(%-20s)}Текст ліворуч у полі щонайменше на 20 символів; пробіли додаються справа.
%-20.20s{$row.name|sprintf(%-20.20s)}Текст ліворуч у полі на 20 символів; довша назва обрізається до 20 символів.
%10s{$row.sum|decimal|sprintf(%10s)}Сума з двома десятковими знаками, вирівняна праворуч у полі щонайменше на 10 символів.

У %20s число 20 задає мінімальну ширину, s означає текстове значення, а мінус у %-20s змінює вирівнювання на ліве. Додаткова частина .20 обмежує довжину тексту. Без неї значення, довше за ширину поля, виводиться повністю й може зсунути сусідні колонки.

Наприклад, рядок із назвою на 20 символів, кількістю на 8 і сумою на 10:

{% loop in $table as $row %}
{$row.name|sprintf(%-20.20s)} {$row.count|number|sprintf(%8s)} {$row.sum|decimal|sprintf(%10s)}
{% onEmpty %}
У документі немає товарів
{% endloop %}

Для товару «Вода», кількості 2,5 і суми 125,00 результат виглядатиме так:

Вода                      2,5     125,00

Числа спочатку форматуйте через number або decimal, а потім вирівнюйте через sprintf. Так ширина враховуватиме вже готове число з десятковим роздільником.

Вирівнювання пробілами працює з моноширинним шрифтом принтера, де кожен символ займає однакову ширину. Загальна ширина рядка має відповідати кількості символів, які принтер вміщує в обраному режимі. У звичайному HTML пробіли згортаються, тому для PDF використовуйте CSS.

Умови

Умова показує частину форми лише за певного значення поля. Наприклад, для замовлення doc.has_discount дорівнює 1, якщо документ має знижку:

{% if ($doc.has_discount == 1) %}
<p>Знижка: {$doc.discount|decimal} грн</p>
{% else %}
<p>Без знижки</p>
{% endif %}

Блок {% else %} необов'язковий. У готових формах також зустрічається {% /if %} — це інший запис закриття умови, рівнозначний {% endif %}.

ОператорЗначення
==Значення рівні.
!=Значення відрізняються.
&&Обидві умови виконуються.
||Виконується хоча б одна умова.
!$полеЗначення поля відсутнє.

Текст у порівняннях беріть у подвійні лапки. Для групування умов використовуйте дужки.

Порівняння == і != працюють із текстовим записом значень: 1 та 1.0 відрізняються. Звичайні числові порівняння >, <, >=, <= в умовах не підтримуються. Для ознак із відомими значеннями використовуйте точне порівняння, як doc.has_discount == 1 у прикладі вище.

Кілька варіантів і вкладені умови

Для кількох варіантів використовуйте {% elseIf (…) %}. Наприклад, різний підпис залежно від наявності реквізитів:

{% if ($we.company && $we.company != "") %}
<p>Постачальник: {$we.company|html}</p>
{% elseIf ($we.registration && $we.registration != "") %}
<p>Постачальник, ЄДРПОУ або ІПН: {$we.registration|html}</p>
{% else %}
<p>Реквізити постачальника не заповнено</p>
{% endif %}

Виконується перша відповідна гілка. Умови можна вкладати одна в одну; кожна повинна мати власне закриття:

{% if ($we.company && $we.company != "") %}
<p>{$we.company|html}</p>
  {% if ($we.address && $we.address != "") %}
  <p>{$we.address|html}</p>
  {% endif %}
{% endif %}

Приховування порожніх полів

Щоб не показувати підпис «Банківські реквізити» без самих реквізитів:

{% if ($we.billing && $we.billing != "") %}
<p>Банківські реквізити: {$we.billing|html}</p>
{% endif %}

$we.billing перевіряє наявність значення, а $we.billing != "" — що воно не є порожнім рядком. Така перевірка підходить і для адреси, примітки та інших необов'язкових текстових полів.

Умова {% if ($поле) %} сама по собі не перевіряє, чи заповнено поле: порожній рядок і число 0 також є наявними значеннями. Тому для ознаки знижки перевіряйте == 1, а для необов'язкового тексту — наявність і нерівність "".

Цикли та рядки документа

Цикл повторює фрагмент для кожного запису в table. Ім'я після as задає поточний рядок; у прикладах це row:

<table>
  <thead>
    <tr>
      <th>№</th>
      <th>Товар</th>
      <th>Кількість</th>
      <th>Сума</th>
    </tr>
  </thead>
  <tbody>
    {% loop in $table as $row counter=$num,1 %}
    <tr>
      <td>{$num}</td>
      <td>{$row.name|html}</td>
      <td>{$row.count|number}</td>
      <td>{$row.sum|decimal}</td>
    </tr>
    {% onEmpty %}
    <tr>
      <td colspan="4">У документі немає товарів</td>
    </tr>
    {% endloop %}
  </tbody>
</table>
  • in $table — звідки брати записи;
  • as $row — як звертатися до поточного запису;
  • counter=$num,1 — створити лічильник num, починаючи з 1;
  • {% onEmpty %} — показати цей фрагмент, якщо записів немає;
  • {% endloop %} — завершити цикл.

Лічильник необов'язковий. Додавайте блок onEmpty, щоб за відсутності записів показати власний текст. Без цього блока Chunk виведе повідомлення про порожню таблицю. Усередині циклу доступні також поля шапки, наприклад {$doc.number}, та умови. Щоб приховати колонку зі знижкою, поставте однакову умову і навколо її заголовка <th>, і навколо комірки <td> у рядку.

Перший і останній рядок

Параметр first_last=true додає ознаки $first і $last. Вони наявні лише на першому та останньому записі відповідно:

{% loop in $table as $row first_last=true %}
  {% if ($first) %}
  <p>Перелік товарів:</p>
  {% endif %}
<p>{$row.name|html}</p>
  {% if ($last) %}
  <p>Кінець переліку</p>
  {% endif %}
{% onEmpty %}
<p>У документі немає товарів</p>
{% endloop %}

Для одного запису встановлені обидві ознаки. Вони стосуються всього переліку товарів, а не першого чи останнього рядка сторінки PDF.

Роздільник між записами

Блок {% divider %} задає роздільник, який виводиться тільки між записами, без зайвої коми після останнього:

<p>
{% loop in $table as $row %}
{$row.name|html}
{% divider %}, {% enddivider %}
{% onEmpty %}—
{% endloop %}
</p>

Повторне використання фрагментів

Спільні реквізити або підписи можна визначити один раз як іменований фрагмент, а потім вставляти через include:

{#company_details}
<p>{$we.company|html}</p>
{% if ($we.address && $we.address != "") %}
<p>{$we.address|html}</p>
{% endif %}
{#}

{% include #company_details %}
<h1>Замовлення № {$doc.number|html}</h1>
{% include #company_details %}

{#company_details} починає визначення, а {#} завершує його. Саме визначення не виводиться у формі: вміст з'являється лише в місці include. Ім'я після # має збігатися з ім'ям фрагмента. Фрагмент отримує доступ до даних у місці його вставлення.

Для спільного фрагмента в кількох формах створіть окремий файл, наприклад common.chtml:

{#signature}
<p>Відвантажив: ____________________</p>
<p>Отримав: ____________________</p>
{#}

У головному HTML-шаблоні вставте його так:

{% include common#signature %}

Завантажте common.chtml на пристрій через той самий механізм обміну, що й головний шаблон, залишивши стандартне місце збереження. У include вказуйте ім'я common без розширення: для окремих файлів фрагментів завантажувач використовує .chtml. У <file> конфігурації pdf_forms.xml залишається ім'я головного HTML-шаблону.

Обчислення

Для простих обчислень у PalmOrder є фільтр po_calc. Наприклад, вивести половину суми документа з двома десятковими знаками:

<p>Половина суми: {$doc.sum|po_calc(doc.sum/2)|decimal} грн</p>

Усередині виразу назви полів записуються без $. Доступні арифметичні дії +, -, *, / і дужки. Після обчислення можна застосувати decimal або number.

Для підсумків документа використовуйте готові поля doc.sum, doc.discount та суми рядків. Вони вже враховують розрахунки застосунку, знижки й округлення.

Коментарі

{!-- Цей блок показує реквізити компанії. --}
<p>{$we.company|html}</p>

Коментар Chunk видаляється під час обробки шаблону, разом із тегами всередині нього.

Перевірка шаблону

Після зміни шаблону завантажте його на пристрій і сформуйте документ повторно. Перевірте форму із заповненими та порожніми реквізитами, зі знижкою та без неї, з одним і кількома товарами.

Що видно у форміЩо перевірити
Залишився текст {$…}Написання поля та його наявність у даних. Для необов'язкового поля додайте заміну або умову.
Підпис є, а значення порожнєЧи охоплює умова весь абзац разом із підписом.
Знижка показується і для нульового значенняЧи використано порівняння doc.has_discount == 1.
Рядки товарів не повторюютьсяЧи розміщені комірки всередині loop і чи використовується row для полів рядка.
Назви з & або < відображаються неправильноФільтр html у текстових полях HTML-шаблону.
Неправильна кількість десяткових знаківВибір decimal, number або відповідного поля _display.
Фрагмент не знайденоІм'я після include, визначення {#…} або отримання окремого файла .chtml на пристрій.

Щоб побачити назви доступних груп даних і тегів, тимчасово додайте в HTML-шаблон {% tagStack(html) %}. Команда виводить імена тегів поточного контексту. Її також можна розмістити всередині циклу. Після перевірки приберіть її з форми.

Додаткові можливості мови описано в документації Chunk Templates. Фільтри PalmOrder decimal, number та po_calc описані на цій сторінці; у загальній документації Chunk їх немає.