На цій сторінці
Друковані форми 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 їх немає.
