Берём jrxml шаблон и устанавливаем в приложение
В первой части я рассказал о том, как подготовить в iReport шаблон отчёта для библиотеки JasperReports. А эта статья посвящена тому, как получившийся шаблон интегрировать непосредственно в приложение NORD POS. И если в первой части программа нужна была только, как источник данных для построения примера отчёта по справочнику товаров, то в данной статье она будет необходима для интеграции отчёта в интерфейс приложения, а также для демонстрации возможностей взаимодействия бизнес логики приложения и элементов шаблона библиотеки JasperReports.
Кроме этого, пришлось разделить статью на две части из-за того, что при подготовки материала я обнаружил ошибку печати отчёта в версии 3.0.1CE. Ошибка возникала из-за неправильного вызова диалога выбора принтера при использовании не стандартного оформления из Swing Look&Feel библиотеки Insubstantial. Ошибка не возникала при использовании темы Metal или оформления в стиле операционной системы. Но, так как в NORD POS по-умолчанию используется нестандартная тема CremeSkin, то для написания этой части необходимо было устранить данный баг и выпустить обновлённую версию NORD POS 3.0.2CE. И именно эту версию мы будем использовать во второй части статьи.
Размещаем шаблон
Чтобы установить шаблон отчёта не обязательно скачивать исходники всего приложения, достаточно сохранить файл из iRepot в папке reports установленного приложения указав путь ./reports/io/example/reports/ для него. Кроме того, необходимо создать BeanShell скрипт для инициализации шаблона в NORD POS, а также ресурс Properties локализации текстовых полей шаблона.
Пишем скрипт
Код скрипта должен инициализировать наш шаблон отчёта в программе и передать значения из базы данных приложения в поля формы. И так в первой строке скрипта делаем инициализацию класса PanelReportBean(), отвечающего за взаимодействие с библиотекой JasperReports:
report = new com.openbravo.pos.reports.PanelReportBean();
Задаём для него основные параметры:
report.setTitleKey("Menu.ExtProducts"); // Задаём название панели
report.setReport("/io/example/reports/productsext"); // Указываем на файл формирующего отчёт
report.setResourceBundle("io/example/reports/productsext_messages"); // и на файл локализации
И строку SQL-запроса для получения значения из базы данных:
report.setSentence("SELECT"+
" PRODUCTS.NAME AS PRODUCT_NAME" +
", PRODUCTS.REFERENCE AS PRODUCT_REFERENCE" +
", PRODUCTS.PRICESELL AS PRODUCT_PRICESELL" +
", PRODUCTS.CATEGORY AS CATEGORY_ID" +
", CATEGORIES.NAME AS CATEGORY_NAME" +
", PRODUCTS.TAXCAT AS TAX_ID" +
" FROM PRODUCTS" +
" LEFT OUTER JOIN CATEGORIES ON PRODUCTS.CATEGORY = CATEGORIES.ID" +
" LEFT OUTER JOIN TAXCATEGORIES ON PRODUCTS.TAXCAT = TAXCATEGORIES.ID" +
" LEFT OUTER JOIN TAXES ON TAXCATEGORIES.ID = TAXES.CATEGORY" +
" WHERE ?(QBF_FILTER)" +
" ORDER BY CATEGORIES.NAME, PRODUCTS.NAME");
Здесь нужно обратить внимание на условие WHERE ?(QBF_FILTER), оно позволяет вставить в запрос фильтр из интерфейса приложения. Например для справочника товаров это ProductFilter() с следующими полями параметров:
report.addParameter("PRODUCTS.NAME");
report.addParameter("PRODUCTS.PRICEBUY");
report.addParameter("PRODUCTS.PRICESELL");
report.addParameter("PRODUCTS.CATEGORY");
report.addParameter("PRODUCTS.CODE");
report.addQBFFilter(new com.openbravo.pos.ticket.ProductFilter());
С помощью фильтра пользователь NORD POS сможете сделать выборку по цене товара, его категории или использую регулярное выражение SQL выбрать товар только с определённым названием. Например, выражение А%, даст нам список товаров начинающихся только на букву «А» из любой категории.
В конце нашего скрипта обязательно нужно указать поля, которые будут использоваться в jrxml-шаблоне для построения отчёта:
report.addField("PRODUCT_NAME", com.openbravo.data.loader.Datas.STRING);
report.addField("PRODUCT_REFERENCE", com.openbravo.data.loader.Datas.STRING);
report.addField("PRODUCT_PRICESELL", com.openbravo.data.loader.Datas.DOUBLE);
report.addField("CATEGORY_ID", com.openbravo.data.loader.Datas.STRING);
report.addField("CATEGORY_NAME", com.openbravo.data.loader.Datas.STRING);
report.addField("TAX_ID", com.openbravo.data.loader.Datas.STRING);
report;
И вызвать средствами BeanShell скрипта созданный нами отчёт.
report.setTitleKey(«Menu.ProductList»); // Задаём название панели
report.setReport("/io/example/reports/productsext"); // Указываем на файл формирующего отчёт
report.setResourceBundle(«io/example/reports/productsext_messages»); // и на файл локализации
report.setSentence(«SELECT»+
" PRODUCTS.NAME AS PRODUCT_NAME" +
", PRODUCTS.REFERENCE AS PRODUCT_REFERENCE" +
", PRODUCTS.PRICESELL AS PRODUCT_PRICESELL" +
", PRODUCTS.CATEGORY AS CATEGORY_ID" +
", CATEGORIES.NAME AS CATEGORY_NAME" +
", PRODUCTS.TAXCAT AS TAX_ID" +
" FROM PRODUCTS" +
" LEFT OUTER JOIN CATEGORIES ON PRODUCTS.CATEGORY = CATEGORIES.ID" +
" LEFT OUTER JOIN TAXCATEGORIES ON PRODUCTS.TAXCAT = TAXCATEGORIES.ID" +
" LEFT OUTER JOIN TAXES ON TAXCATEGORIES.ID = TAXES.CATEGORY" +
" WHERE ?(QBF_FILTER)" +
" ORDER BY CATEGORIES.NAME, PRODUCTS.NAME");
report.addParameter(«PRODUCTS.NAME»);
report.addParameter(«PRODUCTS.PRICEBUY»);
report.addParameter(«PRODUCTS.PRICESELL»);
report.addParameter(«PRODUCTS.CATEGORY»);
report.addParameter(«PRODUCTS.CODE»);
report.addQBFFilter(new com.openbravo.pos.ticket.ProductFilter());
report.addField(«PRODUCT_NAME», com.openbravo.data.loader.Datas.STRING);
report.addField(«PRODUCT_REFERENCE», com.openbravo.data.loader.Datas.STRING);
report.addField(«PRODUCT_PRICESELL», com.openbravo.data.loader.Datas.DOUBLE);
report.addField(«CATEGORY_ID», com.openbravo.data.loader.Datas.STRING);
report.addField(«CATEGORY_NAME», com.openbravo.data.loader.Datas.STRING);
report.addField(«TAX_ID», com.openbravo.data.loader.Datas.STRING);
report;
Локализуем поля
Для этого нам необходимо вернутся в iReport и заменить поля подписей на текстовые, чтобы в выражение указать переменную вида $R{label.key} для локализации. Например для шапки отчёта задаём значение $R{label.title} в в текстовом поле jrxml-шаблона.
После чего добавляем для этого ключа значение в файл productsext_messages.properies.
label.title=List of Products
label.line.number=N
label.product.reference=Reference
label.product.name=Name
label.product.price=Price
label.product.vat=VAT
label.product.TaxPrice=Price+Tax
label.report.summary=Summary
В качества базового языка лучше использовать английский добавив затем к нему перевод на другом языке. Например для русского языка это будет productsext_messages_ru.properies файл.
label.title=Список товаров
label.line.number=№
label.product.reference=Артикул
label.product.name=Название
label.product.price=Цена
label.product.vat=НДС
label.product.TaxPrice=Цена+Налог
label.report.summary=Всего позиций
Пересчитываем налоги
В первой части ставку налога мы брали непосредственно из базы данных, но формируя отчёт из приложения, лучше вести расчёт ставки и суммы налога использую специально для этого предназначенный метод getTaxRate класса TaxesLogic. Для этого в шаблоне надо создать параметр TAXESLOGIC.
<parameter name="TAXESLOGIC" class="com.openbravo.pos.sales.TaxesLogic" isForPrompting="false"/>
Который вызывается при расчёте цены и получает ставку налогу непосредственно на дату составления отчёта, что позволяет использовать возможности NORD POS для расчёта НДС в случае изменения её ставки после определённой даты.
<textField pattern="" isBlankWhenNull="false">
<reportElement uuid="1158eb51-5046-4b15-88f2-2456bac9eea1" x="425" y="2" width="84" height="32"/>
<textElement textAlignment="Right" verticalAlignment="Top"/>
<textFieldExpression><![CDATA[com.openbravo.format.Formats.CURRENCY.formatValue(
new Double(
$F{PRODUCT_PRICESELL}.doubleValue() *
(1.0 + $P{TAXESLOGIC}.getTaxRate($F{TAX_ID}, new Date()))
)
)
]]></textFieldExpression>
</textField>
Также в данном примере вместо паттерна самого шаблона для денежных значений используется паттерн приложения, чтобы обеспечить единообразие вывода всех значений.
Добавляем логотип и QR-код
Также с помощью вызова методов внешних классов в отчёт можно добавить различные ресурсы родительского приложения. Например в базе данных NORD POS хранится изображение логотипа. Вставить его в отчёт с помощью SQL-запроса не получится, но можно воспользоваться методом getResourceAsImage класса DataLogicSystem, вызвав его запросом из выражения поля изображения.
com.openbravo.pos.forms.DataLogicSystem.getResourceAsImage("Window.SupportBy")
<image scaleImage="Clip">
<reportElement uuid="5b7371fd-db3f-488e-80b2-1f2bc912703b" key="image-1" mode="Transparent" x="381" y="1" width="132" height="34"/>
<box>
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<bottomPen lineWidth="0.0" lineColor="#000000"/>
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
</box>
<imageExpression><![CDATA[com.openbravo.pos.forms.DataLogicSystem.getResourceAsImage("Window.SupportBy")]]></imageExpression>
</image>
Или, например, в JasperReports среди поддерживаемых штрих-кодов нет QR-кода, а в NORD POS интегрирована библиотека ZXing, с помощью неё можно сгенерировать QR-кода для отчёта например с ссылкой на сайт.
com.nordpos.device.util.BarcodeImage.getQRCode("http://nordpos.mobi")
<image scaleImage="RetainShape" hAlign="Center" vAlign="Middle">
<reportElement uuid="425a36a5-4937-4551-8b26-8ffe7245f9f0" key="barcode-1" x="449" y="13" width="64" height="64"/>
<box>
<topPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<leftPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
<bottomPen lineWidth="0.0" lineColor="#000000"/>
<rightPen lineWidth="0.0" lineStyle="Solid" lineColor="#000000"/>
</box>
<graphicElement fill="Solid">
<pen lineWidth="0.0" lineStyle="Solid"/>
</graphicElement>
<imageExpression><![CDATA[com.nordpos.device.util.BarcodeImage.getQRCode("http://nordpos.mobi")]]></imageExpression>
</image>
Настраиваем доступ
Теперь остался последний шаг, это открыть доступ к отчёту из NORD POS. С начала добавим кнопку нашего отчёт в интерфейс приложения. Открываем в Настройки -> Ресурсы, находим BeanShell-скрипт Menu.Root и добавляем в раздел MenuSalesManagement панель отчёта.
submenu.addPanel("/com/openbravo/images/appointment.png", "Menu.ProductList", "/io/example/reports/productsext.bsh");
Второй шаг, это разрешить в профиле для группы пользователей доступ к отчёту. Переходим Настройки -> Профили, выбираем роль из списка и добавляем в XML-документ разрешение доступа к нашему отчёту.
<class name="/io/example/reports/productsext.bsh"/>
Всё, перезагружаем NORD POS, открываем панель отчёта и формируем его. На этом задача по созданию отчёта для NORD POS успешно завершена.
Кроме создания отчётов с помощью средств JasperReports в NORD POS можно формировать этикетки, заполнять таблицы, строить графики и диаграммы, но о заложенных для этого основах я постарался рассказать читателям Хабра в этой статье. А в дальнейшем, если это будет интересно, то я хочу продолжить рассказ о других возможностях NORD POS, которые появились благодаря использованию сторонних библиотек. Но прежде хотел бы сделать небольшой опрос среди тех читателей, кто обе части дочитал до конца.
Автор: Svininykh