В этом уроке мы рассмотрим возможности платформы Workflow Technology по работе с текстовыми документами для выгрузки данных. А также познакомимся с механизмом отправки e-mail и настройкой почтового агента.
Для кнопок экспорта и отправки писем нам понадобятся иконки. Скачайте архив с изображениями и разархивируйте его в папку проекта \Template\Projects\1. Template\Forms\Images\24x24.
Если хотите начать практику с этого урока, то вам необходимо развернуть учебный проект по инструкции в статье Разворачивание проекта.
При разворачивании проекта используйте backup базы данных, который можете найти в архиве из раздела Ответы прошлого урока. Скопируйте папки Forms, Workflow и Patterns в папку с развернутым проектом, например, в папку D:\WT\Projects\Template\Projects\1. Template.
Инструкция по подключению шаблонов находится по ссылке.
Экспорт в документ
Для экспорта данных в документ нам понадобится шаблон самого документа и команда типа ExportToDocxCommand или ExportToExcelCommand, которая будет подставлять в документ все необходимые данные.
Шаблон документа
Шаблон документа можете скачать по ссылке ниже:
Скачайте и сохраните его в папку \Template\Projects\1. Template\Forms\Templates, предварительно создав ее.
В шаблоне используются переменные двух видов:
<#VariableName#> - для отображения скалярных значений. Например, <#OrderNumber#>, <#ClientName#> и другие;
<%VariableName%> - для отображения массива (используются только в таблицах). Например, <%OrderPositionTitle%>, <%OrderPositionUnitPrice%> и другие.
При использовании переменных-массивов команда тиражирует строку таблицы столько раз, сколько составляет длина наибольшего массива среди используемых в строке переменных.
В тэге <TemplateFileName> указан относительный путь до нашего шаблона.
В тэге <Parameters> перечислены параметры, значения которых будут подставляться в переменные в документе. Имя параметра в команде должно совпадает с именем переменной в документе.
Параметры OrderNumber, OrderDateDay и OrderDescription заполняем на основе соответствующих полей заказа:
Для даты заказа указываем формат строки, к которой будет приводиться дата.
Для скалярных переменных ClientName, ClientPhone и ClientEmail будем использовать ClientSecondaryGetDataConnection. Добавьте в него недостающее поле Email.
Переменные массивов OrderPositionRowNumber, OrderPositionTitle, OrderPositionQuantity, OrderPositionUnitPrice и OrderPositionTotalPrice будем заполнять на основе значений в соответствующих колонках таблицы OrderPositionDatabaseTable.
Отлично! У нас есть команда экспорта данных заказа в текстовый документ. Теперь осталось реализовать кнопку, по которой будет происходить выполнение этой команды.
Сохранение данных
При нажатии на кнопку "Печать" будем проверять наличие изменений и предлагать пользователю их сохранить, прежде чем продолжить, а по кнопке "Сохранить" не будем закрывать форму заказа и позволим пользователю продолжить работу с карточкой заказа.
Переделаем логику сохранения данных и начнем с кнопки "Сохранить".
Для того чтобы форма не закрывалась при сохранении, необходимо из команды SaveSequentialCommand удалить вызов команды FormCloseCommand. При этом мы должны сбрасывать признак изменения объектов на форме, чтобы при закрытии формы по крестику пользователь не получал сообщение о несохраненных изменениях.
Создадим команду ValueSetCommand, в которой через set-проперти FormChanged будем сбрасывать признак изменения объектов на форме:
Теперь добавим ее вызов в описание команды SaveSequentialCommand.
Не будем забывать о том, что форма карточки заказа может быть открыта на создание. Следовательно, необходимо обновлять параметр Edit, когда происходит сохранение формы, чтобы перевести форму в режим редактирования. Создадим соответствующую команду:
Теперь мы должны добавить команду FormCloseCommand в Execution, который срабатывает, если пользователь хочет сохранить изменения при закрытии формы по крестику:
Создадим команду вывода сообщения с предупреждением о несохраненных изменениях:
TemplateOrderEdit.xml
<CommandName="SaveOnPrintMessageBoxCommand"Type="MessageBoxCommand"Assembly="Commands"> <Caption>Сохранение</Caption> <Text>Форма содержит несохраненные изменения.\rХотите сохранить и продолжить?</Text> <IconType="Question" /> <ButtonsType="YesNo" /></Command>
В FootPanel добавим описание кнопки печати документа:
Запустите приложение и проверьте открытие карточки заказа и печать документа.
Отлично! Теперь можем реализовать отправку этого документа на почту клиенту.
Отправка письма на почту
Настройки
Создадим в базе данных таблицу для хранения настроек почтового агента:
CREATESEQUENCEtemplate.settings_id_seq;CREATETABLEtemplate.settings( settings_id smallintNOT NULLDEFAULT nextval('template.settings_id_seq'::regclass), smtp_server character varying, smtp_port integer, email_address character varying, email_password character varying,sslbooleanNOT NULLDEFAULT false, CONSTRAINT pk_settings_id PRIMARY KEY (settings_id));
Перейдем в файл серверной xml (Template.xml) и добавим запросы на получение и обновление настроек почтового агента:
Template.xml
<SqlQueryName="SettingsSelectSqlQuery"> <Text> SELECT smtp_server AS "SmtpServerAddress", smtp_port AS "SmtpServerPort", ssl AS "SSL", email_address AS "Email", email_password AS "EmailPassword" FROM template.settings LIMIT 1; </Text></SqlQuery><SqlQueryName="SettingsUpdateSqlQuery"> <Text> UPDATE template.settings SET smtp_server = {SmtpServerAddress}, smtp_port = {SmtpServerPort}, ssl = {SSL}, email_address = {Email}, email_password = {EmailPassword}; </Text></SqlQuery>
Так как у нас нет запроса на вставку новых строк в таблицу template.settings, то необходимо создать пустую запись, которую будем обновлять через запрос SettingsUpdateSqlQuery.
INSERT INTO template.settings DEFAULTVALUES;
Форма настроек
Перейдем в файл главной формы (TemplateStart.xml), где первым делом в главное меню добавим пункт Администрирование -> Настройки..., по которому будет открываться форма настроек для почтового агента.
Создайте самостоятельно форму настроек (TemplateSettings.xml).
Паттерны EmptyForm и EmptyFormWithFooter не поддерживают паттерн onClose, который мы рассматривали на 4ом уроке. В архиве ниже есть необходимые файлы паттерна onClose, который вы можете применять в редакторе. Скачайте новый архив с шаблонами и замените содержимое папки проекта \Template\Projects\1. Template\Patterns.
У вас должна получиться форма вида:
Адрес SMTP-сервера (SmtpServerAddressTextBox) - адрес почтового сервера;
Порт SMTP-сервера (SmtpServerPortTextBox) - порт почтового сервера;
SSL (SSLCheckBox) - защита соединения;
Почтовый ящик (EmailAddressTextBox) - ящик, с которого будет осуществляться отправка писем;
Пароль (EmailPasswordTextBox) - пароль для авторизации на почтовом сервере.
Для текстового поля SmtpServerPortTextBox используйте свойство AllowedSymbols, для того чтобы задать ограничения на ввод цифр. Для поля EmailPasswordTextBox используйте свойство Password со значением True для перевода текстового поля в режим ввода пароля.
На рисунке выше показаны параметры для настройки работы приложения с почтовым сервисом Яндекса. Подробнее о настройке сторонних почтовых программ можете прочитать по ссылке.
Команда отправки писем
Вернемся в файл TemplateOrderEdit.xml и создадим соединение с данными для загрузки настроек почтового сервиса:
Чтобы отправить документ на электронную почту клиенту, документ нужно сформировать. В нашем случае вызвать команду OrderExportToDocxCommand.
По умолчанию команда ExportToDocxCommand открывает файл в текстовом редакторе после того как его сформирует и заменит переменные. Чтобы файл не открывался, когда вызываем команду для формирования документа для отправки на почту, добавим в описание команды OrderExportToDocxCommand вложенный тэг <Open>:
<CommandName="OrderExportToDocxCommand"Type="ExportToDocxCommand"Assembly="Commands"> <TemplateFileName>Templates\TemplateOrder.docx</TemplateFileName> <Open> <InputName="Open">True</Input> </Open> <Parameters><!-- Параметры команды --> </Parameters></Command>
В тэге <Open> укажем конструкцию Input со значением по умолчанию. Это значение будет использоваться, если при вызове команды мы не будем указывать Input для передачи нового значения.
Команда EmailSendCommand формирует письмо с заголовком из тэга <Subject> и текстом из тэга <Text>, прикрепляет к письму файлы из тэга <Files> и рассылает копию письма на все адреса, переданные в тэг <Addressees>.
Результатом выполнения команды ExportToDocxCommand будет полный путь с названием файла, который сформирован из указанного шаблона. Этот результат мы передаем в команду EmailSendCommand.
Если письмо успешно отправлено, то результатом команды будет значение 0. Создадим условие для проверки результата команды, которое будем использовать, чтобы уведомлять пользователя об успешности отправки:
Для отправки письма на почту создадим команду типа SequentialCommand, в которой будем последовательно вызывать команду на формирование документа и отправку его на почту:
Команда OrderEmailSentSuccessfullyMessageBoxCommand - команда типа MessageBoxCommand, которая будет выводить пользователю сообщение о результате выполнения команды отправки письма. Создайте ее самостоятельно.
Добавим в FootPanel кнопку, по которой будем отправлять письма:
Запустите приложение и проверьте работу команд на формирование документа и отправку письма на почту клиента.
Группы обязательных полей
Порой бывают задачи, когда для разных действий необходимы разные обязательные поля. Например, в карточке заказа для сохранения заказа в базу данных важно указать номер заказа и выбрать клиента. Это минимальная информация, необходимая для создания заказа, но ее недостаточно для печати счета и отправки его на почту клиента. Необходимо, чтобы была заполнена таблица позиций заказа.
Следовательно, в зависимости от действия будем проверять разные данные. Для этого в платформе реализована возможность разбиения проверок на группы. Тэг <Checking> имеет вложенный тэг <Group>, с мощью которого осуществляется разбиение.
Назначим Checking для объектов OrderNumberTextBox и ClientComboBox группу Saving:
В условии OrderPositionDatabaseTableIsEmptyEqualCondition проверяется значение get-проперти RowsCount на равенство нулю.
Переменная ShowAsteriskHintVariable необходима для того, чтобы подсветка ошибки заполнения объекта происходила в конкретный момент, а не сразу после открытия формы.
Добавим команду ShowAsteriskHintValueSetCommand в начало последовательности команд кнопок PrintButton и EmailSendButton.
Чтобы проверить, сработал ли хотя бы один Checking какой-либо группы, необходимо в get-проперти CheckingFired передать имя нужной группы. Создадим соответствующие условия проверки:
Условие MandatoryFieldsAreFilledEqualCondition удалим. В Execution на сохранение изменений при закрытии формы и на кнопке SaveButton будем проверять условие для группы Saving - MandatoryFieldsAllowedSavingNestedCondition. А на кнопках PrintButton и EmailSendButton будем проверять оба условия.
При этом проверку этих условий перенесем из тэга <Enabled> в последовательность команд. Таким образом, синтаксис кнопки PrintButton будет иметь вид:
Аналогичным образом измените описание кнопки EmailSendButton, скорректировав текст сообщения для команды PrintingMessageBoxCommand.
Откройте карточку заказа для создания нового заказа и убедитесь, что подсвечиваются только поля "Клиент" и "Номер заказа":
Заполните одно или оба обязательных поля и проверьте логику работы кнопки "Печать":
Самостоятельно
У нас на форме не реализованы проверки на наличие электронной почты в карточке клиента, а также нет проверки на полноту и корректность настроек почтового сервиса.
Реализуйте самостоятельно необходимые проверки и уведомления пользователя. Добавьте в карточку заказа в блок данных о клиенте поле с адресом электронной почты.
Итоги
В этом уроке мы познакомились с командой ExportToDocxCommand, которая позволяет передавать в текстовый документ данные с формы, используя заранее подготовленный шаблон документа.
Также создали форму для настроек почтового агента и познакомились с командой EmailSendCommand для отправки e-mail на почту клиентов.
На следующем уроке реализуем кассовые операции, добавим отчет по бюджету и выгрузку его в Excel файл.
Ответы
В архиве присутствуют xml-файлы форм и серверный xml-файл, также лежит бэкап базы данных и файл с запросами на изменение структуры базы данных - с помощью файлов можете проверить себя.