Иногда требуется печатать что то с мобильного устройства – ярлыки, чеки, заказы и даже договоры и спецификации. Даже если устройство оффлайн. Для этого нужны макеты как у 1С – т.е. что то, сохраняющее свой вид, размеры, пропорции при выводе. И при этом макет должен заполняться данными. Как решить это минимальными трудозатратами, но при этом еще чтобы было просто разработчику прикладных решений. Первое что приходит на ум – PDF с заполняемыми полями, но на практике с этим форматом оказалось все нестабильно – в каких то случаях работает, в каких то нет. Это не открытый формат к сожалению.
Отличные макеты у 1С. Но как их привинтить к обработчикам на питоне? Оказалось довольно просто – выгрузить в HTML и дать питону. В питоне для этого есть супероружие – шаблонизатор Jinja. А для более запущенных случаев есть еще одно – BeautifulSoap.
Все что нужно знать о jinja чтобы сделать любую печатную форму
Сначала рассмотрим просто HTML– строку, без какой либо разметки - только параграфы. Просто вывод по циклу несколько строк в отдельных парагарфах. Весь обработчик выглядит так:
from jinja2 import Template
t = Template("""{% for user in users -%}
<p>Привет, {{ user }}!</p>
{% endfor %}""")
res =t.render(users=["admin", "Alex", "prog1C"])
hashMap.put("PrintPreview",res)
В шаблоне
По сути, из необходимо, что нужно знать о шаблонизаторе – это то, что значения подставляются в двойных фигурных скобках, а не в [] как в шаблонах 1С:
<p>Привет, {{ user }}!</p>
но еще, так как часто приходится выводить табличные части понадобится цикл {% for user in users -%} - {% endfor %}
В коде обработчика
Template – берет html и делает из него шаблон, a render подставляет в шаблон ваши значения и возвращает опять html. Можно конечно вообще обойтись без шаблонизатора Jinja и собирать html динамически, но тогда потеряется вся суть разметки шаблона.
Команда PrintPreview открывает окно предпросмотра и вывода на печать(также теперь можно вывести html на экран)
По сути, это все что нужно знать из теории. Остальное – приемы разработки.
Вариант печатной формы – накладная с шапкой и строками
Рассмотрим вариант – взять из 1С обычную накладную с табличной частью. Берем вот такой макет, выгружаем в HTML через "Сохранить как" и прикрепляем к конфигурации через Медиафайлы. Обратите внимание, что я задал значения в строках через коллекцию (line) чтобы заполнять в цикле.
После выгрузки я зашел блокнотом и вставил вот сюда цикл. Закрыл, сохранил, прикрепил в Медиафайлы.
И вот весь код обработчика: получаю html строку из файла, передаю шаблонизатору, создаю массив lines - строки таблицы, передаю его и переменные шапки шаблонизатору в render. На выходе получаем html строку, которую передаем экранной переменной размещенной в контейнере (появился новый тип элемента контейнера - HTML)
filename = suClass.get_stored_file("bill")
with open(filename) as file_:
htmltxt = file_.read()
htmltxt.replace(" "," ")
template = Template(htmltxt)
lines = []
for i in range(1, 5):
i = str(i)
line = dict(npp=i, name="Товар "+i,price=str(random.randint(10, 10000)),qty=str(random.randint(1, 5)))
lines.append(line)
res =template.render(lines=lines,customer = "Дмитрий Воронцов")
hashMap.put("bill",res)
Печатная форма ярлыка из 1С с штрихкодом
Теперь попробуем перетащить еще одну печатную форму из 1С. На самом деле можно взять любой HTML редактор и сделать ее в нем, есть много онлайновых редакторов например. Но в 1С есть жесткая разметка макета, да и может понадобиться использовать уже готовый макет из какой ни будь конфигурации 1С.
Для этого я просто сохраняю форму в HTML через "Сохранить как". Я сделал форму со штрихкодом, где в качестве штрихкода сделал просто рандомную картинку чтобы задать на макете размеры
И прикрепляю ее к конфигурации в качестве медиафайла на закладке Медиафайлы. Теперь этот файл попадет на устройство и можно с ним работать.
Сам обработчик выглядит так
import barcode
from barcode.writer import ImageWriter
from io import BytesIO
from barcode import generate
from jinja2 import Template
from bs4 import BeautifulSoup as BS
import base64
filename = suClass.get_stored_file("template1")
with open(filename) as file_:
htmltxt = file_.read()
htmltxt.replace(" "," ")
soup = BS(htmltxt)
for imgtag in soup.find_all('img'):
EAN = barcode.get_barcode_class('ean13')
#ean = EAN(u'123456789011', writer=ImageWriter())
fp = BytesIO()
generate('EAN13', u'5901234123457', writer=ImageWriter(), output=fp)
base64data = base64.b64encode(fp.getvalue()).decode('utf-8')
imgtag['src']="data:image/jpg;base64,"+base64data
htmltxt=str(soup)
template = Template(htmltxt)
docdata = { 'number': '1-555', 'customer': "Тульская мануфактура №1",'barcode':'tool.jpg' }
res =template.render(doc=docdata)
hashMap.put("PrintPreview",res)
Тут можно обратить на следующие моменты:
1С в макет вставляет " ", которые не нравятся Jinja поэтому я их убираю фильтром по строке.
Чтобы разместить штрихкод я применяю такой прием – сначала с помощью BeautifulSoap ищу картинку, потом генерирую картинку штрихкода и вставляю на место картинки. Само собой таким же способом можно размещать и просто картинки.
Дальнейшее также как и у предыдущего обработчика – просто подставляю значения и получаю HTML который потом вывожу.
Экраны с HTML и JavaScript
Иногда бывает нужно нарисовать что то красивое с картинками, таблицами, например обучающий тьюториал по конфигурации (картинки и «Далее...») и для этого удобнее использовать HTML. Поэтому теперь HTML поле можно размещать в контейнерах. В качестве значения – HTML строку, полученную с помощью Jinja или любым другим способом.
В демо конфе есть этот пример и там показано как размещать вызовы JS и как они потом обработывают события. Т.е. эти кнопки не для красоты - они рабочие, вызывают обработчик ввода симпла и передают ему параметр. Тут полноценный JavaScript
Еще небольшое дополнение
Появился Java класс, доступный из питона SimpleUtilites, в котором пока один метод get_stored_file который возвращает абсолютный путь к файлу переданному через Медиафайлы - это может быть html как в этой статье или любой другой файл. Пример обращения в примерах печатных форм - получение макета html
Подпишитесь на мой Телеграмм канал, чтобы получать актуальные новости и анонсы по проекту Simple UI: https://t.me/devsimpleui