# Урок 5. Практика разработки. Часть 2 В данном уроке мы рассмотрим: 1. Типы объектов 2. Состояния классов 3. Динамическое управление редактируемостью полей 4. Действия на перевод состояния ## Типы объектов Сервис предоставляет набор стандартных возможностей, доступных для всех типизируемых классов. Основным назначением типа объекта является хранение настроек по документу, которые могут быть переопределены на проекте. [Руководство разработчика: Тип объекта](books/AppGuide/030_class/075_тип_объекта.md) ## Состояния Состояния класса позволяют управлять бизнес-логикой объекта. [Руководство разработчика: Тип объекта # Переходы состояний](books/AppGuide/030_class/075_тип_объекта.md#переходы-состояний) ## Практические задания ### Добавление атрибутов типа объекта и состояния - В классе `Lbr_OutOrder`, `Lbr_InOrder` и `Lbr_InAct` добавьте атрибуты: |name|attribute-type|caption|Дополнительно| |-|-|-|-| | idState | Long | Состояние | Ссылочный на объект, Ссылается на класс Btk_ClassState, не копируется при выполнении копирования | | idStateMC | Number | Номер состояния | Не видимый, не копируется при выполнении копирования, является порядковым номером состояния (`isStateMC="true"`) | | idObjectType | Long | Тип | Ссылочный на объект, Ссылается на класс Btk_ObjectType, хедлайн | - Запустите кодогенерацию по этим классам и запустите генератор таблиц для них ### Добавление состояния для классов - Откройте карточку класса `Lbr_InAct` (`Настройка системы \ Сущности > Классы`) и добавьте состояния: |Системное имя|Наименование|Порядковый номер|Стартовое состояния| |-|-|-|-| |Create|Оформляется|100|1| |Executed|Выполнен|300|0| - Для классов `Lbr_InOrder` и `Lbr_OutOrder` в api сделайте метод `regState` для регистрации аналогичных состояний и пропишите его в odm в тэге `dbData`. [Руководство разработчика: Тип объекта # Регистрация состояний](books/AppGuide/030_class/075_тип_объекта.md#регистрация-состояний) - Запустите генерацию таблиц для данных классов, чтобы отработал скрипт регистрации состояний. При перезапуске скрипта необходимо увеличивать его версию. ### Создание закладки для класса через справочник закладок - Создайте закладку в справочнике закладок для позиций `Lbr_InActDet`. - Системное имя - `Lbr_InActDetAvi.List_idInAct` - Наименование - `Позиции` - Имя выборки - `Lbr_InActDetAvi` - Имя отображения - `List_idInAct` В детализации укажите класс `Lbr_InAct`. [Руководство разработчика: Тип объекта # Закладки](books/AppGuide/030_class/075_тип_объекта.md#закладки-типа-объектов) - Для классов `Lbr_InOrder` и `Lbr_OutOrder` в api сделайте метод `regTab` для регистрации закладок со своими позициями и пропишите его в odm. [Руководство разработчика: Тип объекта # Регистрация закладок](books/AppGuide/030_class/075_тип_объекта.md#регистрация-закладок) - Запустите генерацию таблиц для данных классов, чтобы отработал скрипт регистрации. Данные закладки будут нужны для дальнейшей настройки на типе объекта. ### Настройка типов объектов - Создайте тип объекта с кодом, наименованием и кр. наименованием `Lbr_InAct` - `Приходная накладная` через справочник типов объекта и установите на нем флаг по умолчанию, настройте для него закладку с позициями и переходы состояний. Доступные закладки для класса будут отображаться, если установить в фильтре флаг `Отображать неактивные` - Для того, чтобы при создании объекта подставлялся тип по умолчанию, в `Lbr_InActApi` переопределите метод `insert` и пропишите в конце вызов установки типа объекта по умолчанию `setidObjectType(rop, Btk_ObjectTypeApi().getDefaultObjType(idClass))` - В `Lbr_InAct.avm` отображении `Card` подключите закладки от типа объекта. [Руководство разработчика: Тип объекта # Детализация виде закладок](books/AppGuide/030_class/075_тип_объекта.md#детализация-виде-закладок) - Там же у атрибута `idObjectTypeHL` измените тип редактора на выпадающий список с `lookupQuery="gtk-Btk_ObjectTypeAvi#MainLookup"` - В `Lbr_InActApi` создайте метод `regObjectType` для регистрации еще одного типа `Lbr_InAct_Add` - `Дополнительная приходная накладная`, с параметром `bpIsDefault = 0`. Там же пропишите регистрацию закладок для типа и переходов состояния, пропишите метод в odm. Запустите генерацию таблиц по данному классу. [Руководство разработчика: Тип объекта # Регистрация подкласса, типа объекта, закладок для типа и переходов состояний](books/AppGuide/030_class/075_тип_объекта.md#регистрация-подкласса-типа-объекта-закладок-для-типа-и-переходов-состояний) - Для классов `Lbr_InOrder` и `Lbr_OutOrder` сделайте аналогичную настройку в `avm` и в `Api().insert`, также в `Api` сделайте метод для регистрации типа по умолчанию с кодом и наименованием из класса. Там же пропишите регистрацию закладок для типа и переходов состояния, пропишите метод в odm, с зависимостями от предыдущих скриптов `regTab` и `regState`. Запустите генерацию таблиц по данным классам. Так как тип объекта и его коллекции является классами с разделяемым режимом кеширования (Shared), то необходимо после любых изменений на них, сбрасывать Shared кэш ### Разработка бизнес логики ```{attention} Не используйте copyAro для получения значений атрибутивного состава rop, так как это увеличивает расход оперативной памяти, для получения значений атрибута следует применять rop.get(_.атрибут) ``` #### Вычисление заголовка с учетом типа объекта - В `Api` классов-документов измените вычисление заголовка `calcHeadLine`, заголовок должен быть в формате `{(Краткое наименование из типа объекта).nvl(HL класса)} № {sNumDoc} от {dDoc в формате дд.мм.гггг}`. - Для созданных ранее объектов пересчитайте заголовки, для этого в карточках классов, под молотком и ключом запустите операцию `Пересчитать заголовки и мнемокоды объектов класса`. Для проверки можно посмотреть данные столбца sheadline_dz в таблицах. #### Динамическое управление редактируемостью полей - В `Avi` документов для карточек переопределите сеттер состояния `setidState`, в конце пропишите методы для корректного срабатывания `checkWorkability` мастера и деталей, для того чтобы последующие задания работали корректно при переводе состояния: ```scala //не обязательные действия //завершение транзакции session.commit() //снятие блокировки Btk_FormSessionApi().closeLockUnit() //необходимые действия //обновление карточки selection.refreshItem() //вызов checkWorkability в карточке selection.checkWorkability() //вызов checkWorkability в деталях selection.cwaDetails() ``` - Для реализации динамического управления редактируемостью в `Avi` позиций документов, для отображений `List_idDoc` и `List_idInAct` переопределите метод `checkWorkability`, напишите блокировку добавления, удаления, редактирования позиций, если номер состояния документа отличен от 100. Можно воспользоваться данными методами: ```scala //переменная для управления редактируемостью val bvRO = getVar("super$idStateMC").asNNumber.isDistinct(100.nn) //для одного атрибута selection.attrs("Имя атрибута").isReadOnly = bvRO //для списка атрибутов selection.attrs().foreach(_.isReadOnly = bvRO) //для операций selection.opers("Имя операции").isEnabled = !bvRO ``` - В `Avi` документов для карточек переопределите `checkWorkability`, напишите блокировку на редактирование всех полей, кроме `idState`, `idStateHL` и `nSum`, если номер состояния документа отличен от 100 #### Действия на перевод состояния В `Lbr_InActApi`: - Создайте метод проверки документа (например `validateDoc`), на вход будет rop документа. - В нем пропишите вызов ошибки, если не будут выполнены какие либо условия (указаны ниже). Ошибку можно сделать одну общую с не выполненными условиями или отдельную по каждому условию. Вызов ошибки осуществляется методом `throw AppException("Текст ошибки")`. Перечень условий: 1. Заполнены атрибуты документа (дата, организация, библиотекарь) 2. Наличие хотя бы одной записи в позициях 3. Заполнены атрибуты в позициях (книга, количество) - Переопределите сеттер состояния (`setidState`), в начале метода пропишите вызов метода проверки, если номер нового состояния будет >=300 и номер старого состояния < 300. - В `Lbr_InOrderApi` и `Lbr_OutOrderApi` напишите аналогичную логику, только без проверки количества в позиции. #### Проверка при удалении в `Api` документов переопределите метод `delete` и напишите в начале проверку, чтобы нельзя было удалить документ, если он находится не в состоянии `Оформляется`