На прошлом уроке создали экран редактирования заказа, но реализацию возможности изменять клиента и редактировать позиции заказа оставил на этот урок.
Скачайте архив с изображениями и разархивируйте его в папку проекта \Template\Projects\1. Template\MobileForms\Images.
Редактирование клиента
Так как список клиентов может быть большим и неудобным для использования ComboBox, то договорились для выбора клиента использовать отдельный экран. В прошлом уроке на экран редактирования заказа справа от поля с именем клиента добавили кнопку, которую планировали использовать для перехода на форму со списком клиентов. Самостоятельно создайте пустую форму списка клиентов и команду открытия этой формы, которая будет вызываться по ранее созданной кнопке:
На форму списка клиентов передаем значение ClientId текущего клиента в заказе, полученного из базы данных. Помним, что запрос на получение списка должен возвращать все неархивные записи и запись, на которую ссылается редактируемый заказ.
Строка поиска
Чтобы пользователю было удобно работать с потенциально большим списком, добавим возможность поиска клиента по имени.
Строка поиска будет представлена объектом типа Panel с именем SearchPanel, содержащим элементы:
SearchButton - хоть и является объектом типа Button, но это просто изображение лупы, не выполняющее никакой команды
SearchTextBox - текстовое поле для ввода строки поиска
ClearSearchButton - кнопка с изображением повернутого крестика для очистки строки поиска
Объект SearchPanel будет иметь настройки BorderCorner и BackColor аналогичные тем, что делали для панелей блоков на экране заказа. Высота панели 40 единиц.
Самостоятельно создайте объект SearchTextBox, который будет справа от SearchButton без отступов. По высоте текстовое поле должно совпадать с высотой панели, следовательно отступ сверху будет нулевым. Ширина текстового поля должна учитывать размер кнопки ClearSearchButton и оставлять отступ справа в 10 единиц. Для объекта SearchTextBox текст-подсказки будет "Поиск". А его цвет зависит от оформления системы: для темной темы используется DarkGray, а для светлой темы - LightGray. Цвет основного текста (тэг <ForeColor>) тоже зависит от выбранного оформления системы: для темной темы используется WhiteSmoke, а для светлой темы - MostlyBlack. Значение тэга <BackColor> можно тянуть из аналогичного свойства объекта SearchPanel. В тэге <FontStyle> укажем значение TextFont. По умолчанию TextBox имеет рамку, чтобы ее убрать используем тэг <Multiline> со значением True.
Кнопка ClearSearchButton для сброса значения объекта SearchTextBox будет иметь вид:
Самостоятельно создайте команду ResetSearchStringValueSetCommand.
Запустите приложение и проверьте отображение строки поиска на экране выбора клиента.
Отлично!
Самостоятельно добавьте на форму список с клиентами ClientCollectionView. В качестве источника данных используйте SecondaryGetDataConnection, в котором должны быть отфильтрованные по строке поиска данный из PrimaryGetDataConnection.
Запрос на получение списка клиентов должен содержать поля:
В результате у вас должна получиться форма вида:
Запустите приложение и проверьте работу фильтра списка:
Выбор клиента
Добавим на форму параметры, в которых будем возвращать на родительскую форму данные выбранного клиента:
Как видите на форме используем паттерн Updated - добавьте в файл параметр Updated и создайте команду для его обновления.
Замена клиента в заказе
Вернемся в файл описания карточки заказа и реализуем обновления данных о клиенте в OrderPrimaryGetDataConnection. Самостоятельно создайте команду типа ValueSetCommand, в которой заменяйте значения в полях DataConnection соответствующих возвращаемым параметрам. Реализуйте Execution, в котором будет вызываться эта команда, используя паттерн Updated.
Запустите приложение и проверьте функциональность смены клиента в заказе.
Дополнительно: на кнопку смены клиента наложите ограничение, если заказ оплачен.
Редактирование позиций заказа
Начнем с реализации возможности добавление позиций в заказ и изменение кол-ва товара в позиции, а затем добавим удаление позиций.
Создадим ConvertDataConnection, который будет преобразовывать OrderPositionPrimaryGetDataConnection:
Здесь мы добавляем поле ID, которое будет временным идентификатором, который будем передавать на форму со списком товаров, чтобы правильно выставить флаги Added, Upated и Deleted. О них подробнее позже. Так же добавили поле IsNew, флаг которым будем помечать позиции заказа не сохраненные в базе данных.
В качестве значения нового поля указали объект CounterVariable, который является переменной-счетчиком и каждый раз при обращении увеличивает текущее значение на единицу и возвращает его.
На форму каталога передаем параметр MaterialArray с массивом добавленных товаров в заказ.
На экране редактирования заказа добавьте кнопку Изменить, укажите для нее команду MaterialListFormShowCommand. Кнопку разместите справа над списком позиций заказов:
Перейдем в файл новой формы и в него добавим строку поиска, как делали на форме выбора клиента.
С родительской формы передаем параметр MaterialArray, добавим его на форму, а чтобы было удобно работать с передаваемым массивом данных создадим ArrayGetDataConnection:
Создайте самостоятельно MaterialPrimaryGetDataConnection, который будет получать данные из запроса:
Template.xml
<SqlQueryName="AppMaterialSelectSqlQuery"> <Text> SELECT M.material_id AS "MaterialId", M.title AS "Title", M.material_category_id AS "MaterialCategoryId", MC.title AS "MaterialCategoryTitle", U.short_title AS "UnitShortTitle", M.unit_price AS "UnitPrice", trim(to_char(M.unit_price, '999G999G999D00')) || ' руб./' || U.short_title AS "UnitPriceString", M.material_id != ALL({MaterialId}::bigint[]) AS "NotUse", M.material_id = ANY({MaterialId}::bigint[]) AS "Selected" FROM template.material M LEFT JOIN template.material_category MC USING(material_category_id) LEFT JOIN template.unit U USING(unit_id) WHERE NOT M.archive OR M.material_id = ANY({MaterialId}::bigint[]) ORDER BY M.title; </Text></SqlQuery>
В качестве параметра в запрос передаем массив MaterialId, полученных с родительской формы.
Здесь так же возвращаем два поля с ценой за единицу товара: UnitPrice и UnitPriceString - значение из первого будем возвращать на родительскую форму и использовать для расчета итоговой стоимости, а второе для отображения в карточке товара.
Так же возвращаем два флага:
NotUse - true, если в заказе нет позиции с этим товаром, по этому флагу будет отображаться кнопка "Добавить" в карточке товара,
Selected - true, если в заказе есть позиция с этим товаром, по этому флагу будет отображаться количество товара и кнопки изменения.
Обернем загружающее соединение в ConvertDataConnection и добавим новые поля:
Поле TotalPrice необходимо для хранения итоговой суммы по выбранному товару.
В полях Quantity и ID подставляем соответствующие значения из массива полученного от родительской формы.
Поля Added, Updated и Deleted необходимы, чтобы при передачи на родительскую форму различать новые товары, которые нужно добавить через set-проперти AddRows, позиции в которых нужно обновить количество товара, и позиции подлежащие удалению из заказа.
Создайте MaterialCollectionView для отображения списка товаров. Добавьте в шаблон карточки элемента списка описание полей для наименования товара, его категории и цены за единицу.
Сразу создадим условие, в котором будем проверять наличие значения в поле ID:
В команде находим индекс строки в MaterialConvertDataConnection по значению MaterialId элемента, по кнопке которого сделали тап, и в найденной строке меняем значения флагов и ставим количество равное единице. В результате кнопка исчезнет из карточки и вместо нее должны появиться элементы управления количеством товара в заказе.
Так же изменяем значения в полях Added, Updated и Deleted. Новые значения для Added и Updated зависят от наличия временного идентификатора на тот случай, если сначала удалили товар, и сразу нажали на кнопку Добавить. Если у товара есть временный ID, то мы должны рассматривать изменение существующего, а не добавление нового.
В поле IsNew должно сохраняться значение, полученное с родительской формы, и ставиться True, если добавляем новую позицию.
В условие QuantityOfSelectedMaterialGreater1Condition проверяем количество на больше единицы, чтобы определить, какую команду следует выполнить. Если количество больше единицы, то будем его уменьшать на единицу, а если равно единицы, то меняем значения флагов NotUse и Selected на противоположные, а количество сбрасываем на 0.
Самостоятельно напишите условие и обе команды. Не забудьте менять значения в полях Added, Updated и Deleted, учитывая при этом временный ID. Если у товара нет временного идентификатора, то можно просто сбросить количество и не помечать его на удаление из карточки заказа. При уменьшении количества товара важно правильно
Текущее количество товара будем отображать в объекте:
Тэг <RightItems> содержит список элементов меню, которые будут отображаться справа при свайпе карточки влево. Если необходимо отображать такое меню слева при свайпе карточки в право, то используем тэг <LeftItems>.
Элементы свайп-меню описываются тегом <SwipeItem>, в котором указывается текст надписи, путь до изображения, цвет фона и последовательность команд.
Добавим в файл описание используемого цвета для кнопки удаления:
Запустим приложение, чтобы проверить отображение меню с кнопкой удаления записи:
s
Итоги
На уроке мы рассмотрели процесс аутентификации пользователя, .
Ответы
В архиве присутствуют xml-файлы форм для мобильного приложения и серверный xml-файл, также лежит бэкап базы данных и файл с запросами на изменение структуры базы данных - с помощью файлов можете проверить себя.
Архив не содержит xml-файлы форм десктопного приложения.