Перейти к основному содержанию
`Ctrl`+`K`

# Тип объекта

Сервис предоставляет набор стандартных возможностей, доступных для всех типизируемых классов. Основным назначением типа объекта является хранение настроек по документу, которые могут быть переопределены на проекте.

Основные настройки:

- Настройка закладок

- Настройка печатных форм

- Настройка переходов состояний

- Настройка объектных характеристик

Также предусмотрены механизмы для подключения настроек для модуля или подсистемы.

Тип объекта может менять поведение документа в зависимости от бизнес процесса, в котором данный документ участвует. В случае, если необходимо запрограммировать поведение документа в зависимости от типа объект следует использовать системное имя подкласса.

Внимание

Использовать системные имена типов объекта в коде нельзя, так как типы объектов могут быть добавлены в проекте.

На базе типа объекта реализовано множество сервисных возможностей, позволяющих тонко настраивать типизированные документы не привлекая программистов.

## Подключение типа объекта к классу

Примечание

Для супертипа document (Документ) ссылка на тип `idObjectType` создается автоматически

Пример объявления атрибута:

    <attr name="idObjectType"
          attribute-type="Long"
          caption="Тип объекта"
          order="50"
          type="refObject"
          isVisible="true"
          ref.class="Btk_ObjectType"/>

Система имеет общий справочник типов объекта (`Настройка системы \ Сущности > Типы объектов > Типы объектов`)

Можно регистрировать типы объекта в коде Регистрация в коде

Объекты класса типизируются классом-настройкой `Btk_ObjectType`. В данной настройке можно задать несколько типов для одного класса системы, а также назначить тип по умолчанию. Обязательным условием для типизации объектов является наличие в типизируемом классе атрибута-ссылки на `Btk_ObjectType`. Атрибут обязательно должен называться `idObjectType`. Это имя зарезервировано фреймворком и не может использоваться для других целей.

## Подкласс

Подкласс – это логическая типизация для разделения бизнес-логики в рамках одного класса. Подклассы добавляются разработчиками и на них можно завязываться в коде. Несколько типов объекта может быть привязано к одному подклассу

Система имеет общий справочник подклассов (`Настройка системы \ Сущности > Типы объектов > Подклассы`), в котором настраивается:

- Код

- Наименование

- Суперкласс (Класс к которому будет привязан данный подкласс)

Можно регистрировать подклассы в коде Регистрация в коде

Примечание

Системные имена подклассов можно использовать в коде.

## Стандартные настройки

### Закладки типа объектов

Для типизированного объекта доступна возможность управления выводом закладок.

Система имеет общий справочник закладок (`Настройка системы \ Сущности > Закладки детализации`), в котором настраивается:

- имя выборки

- отображение

- наименование

- условие вывода

- иконка

- перечень классов, для которых возможен вывод закладки.

Можно регистрировать закладки в коде Регистрация в коде

Связь с типом объекта осуществляется по списку допустимых классов. Чтобы включить отображение закладки для типа объекта нужно:

1. Откройте `Настройка системы \ Сущности > Типы объектов > Типы объектов`

2. Выберите настройку `Закладки типа объектов`

3. Отобразите все закладки
   Для этого на панели фильтрации закладок снимите флажок `Отображать неактивные`

4. Выберите требуемую закладку

5. Установите на ней флажок «Активна»

Можно регистрировать закладки для типа в коде Регистрация в коде

По умолчанию в разметке выборки Avm сервис настройки закладок не используется. Программист должен указать для нужного отображения динамическое получение закладок от типа объекта.

Существует два варианта вывода детализации фрейма: в виде закладок и в виде списка

#### Детализация виде закладок

Набор закладок отображается либо снизу, либо справа от карточки или списка

Для подключения в Avm нужно указать выборку с динамическими закладками

    <tabComposer>
    	<frame filter.isVisible="false">
    		<card>
    			<layout>
    				<hBox>
    					<attr name="sNumber"/>
    					<attr name="sCaption"/>
    					<attr name="idPrjVerHL"/>
    				</hBox>
    				<hBox>
    					<attr name="idDepOwnerHL"/>
    					<attr name="idObjectTypeHL"/>
    					<attr name="idStateHL"/>
    				</hBox>
    			</layout>
    		</card>
    	</frame>
    	<tabItems isVisible="true"
    	          selection="gtk-ru.bitec.app.btk.Btk_ObjectTypeTabAvi"
    	          representation="List_Tab"
    	          selection.selectionAttr="SSELECTIONNAME"
    	          selection.representationAttr="SREPRESENTATIONNAME"
    	          selection.captionAttr="SCAPTION"
    	          selection.imageIndexAttr="NIMAGE"
    	          selection.paramsAttr="JSONPARAMS"

    			/>
    </tabComposer>

#### Детализация в виде списка закладок

Набор закладок отображается в виде списка закладок, справа от которого выводится содержимое текущий закладки. Для подключения в Avm нужно указать выборку с динамическим содержимым.

    <dynamicComposer>
    	<frame filter.isVisible="false"
    	       header.isWide="true"
    	       toolBar.isCaptionsVisible="true">
    		<card useMasterData="false"/>
    	</frame>
    	<dynamicItems masterAlign="top">
    		<dynamicItem align="client"
    		             representation="DynList"
    		             selection="gtk-ru.bitec.app.btk.Btk_ObjectTypeTabAvi"/>
    	</dynamicItems>
    </dynamicComposer>

### Параметры динамических закладок

Дополнительные атрибуты для динамических закладок, настраиваемые на типе объекта, могут использоваться для изменения поведения детализации. Для этого им передают уникальные значения или псевдонимы, которые затем используются для получения данных.

За хранение параметров отвечает атрибут `Btk_ObjectTypeTab#sParamsClause`, использующий формат JSON

Параметр `sParamsClause` может быть настроен двумя способами:

- При регистрации закладки типа объекта через код в функции `Btk_ObjectTypeTabApi#registerTab`

- В интерфейсе приложения в поле `Параметры выборки` на детализации `Закладки типа объекта` в пункте меню `Настройка системы \ Сущности > Типы объектов > Типы объектов`

Примечание

Значение переменной `sParamsClause` явно преобразуются к типу JSONB, предоставляемому PostgreSQL, поэтому должно являться валидным JSON-объектом, например:

- Используя функцию `jsonb_build_object('key1', value1, 'key2', value2)`

- Строкой типа `'{"key1": value1, "key2": value2}'`

Итоговый JSON-объект доступен как атрибут выборки `Btk_ObjectTypeTabAvi.List_Tab` или `Btk_ObjectTypeTabAvi.DynList` и может быть получен с помощью функции `Btk_ObjectTypeLib#tabParamsJSON`, откуда по ключу можно достать нужные значения

#### Получение атрибутов выборки

Кроме стандартных типов данных, используемых JSON, значение внутри объекта может быть псевдонимом, соответствующим любому доступному параметру выборки. Так, например, для получения идентификатора объекта мастер-детали можно использовать выражение `:super$id`. Тогда итоговый JSON будет выглядеть так: `jsonb_build_object('idMaster', :super$id)`

### Печатные формы

Позволяет настраивать список печатных форм для типа объекта. Настроенные печатные формы будут доступны под операцией печати для карточки объекта.

Печатные формы добавляются из общего справочника и могут быть активированы для типа объекта. Доступ к формированию печатной формы может регулироваться состоянием объекта.

### Переходы состояний

Состояния класса позволяют управлять бизнес-логикой объекта: доступ на редактирование атрибутов, возможность выполнения операций в зависимости от состояний и т.д.

Настройка состояний подразумевает наличие в классе атрибута, ссылочного на состояние и типа объекта.

    <attr name="idState"
          attribute-type="Long"
          caption="Состояние"
          order="40"
          type="refObject"
          ref.class="Btk_ClassState"/>

Для класса, имеющего атрибут, ссылочный на состояние, необходимо определить перечень возможных для него состояний.

Список состояний можно настроить в карточке класса, либо вручную, через метод `*Api().regState` Регистрация в коде. При создании состояний необходимо помнить, что у класса должно присутствовать ровно одно начальное состояние.

Возможные переходы между состояниями настраиваются для типа объекта на закладке `Переходы состояний`. Можно регистрировать переходы состояний для типа в коде Регистрация в коде.

Сеттеры состояний никак не проверяют эти переходы, они влияют только на выпадающий список состояний.

Выборка для выпадающего списка состояний класса, в которые возможен переход от текущего: `gtk-ru.bitec.app.btk.Btk_ClassStateAvi#Lookup_Class`

Пример разметки атрибута в Avm:

    <attr name="idStateHL" caption="Состояние" order="30.1" isLastInLine="false">
        <editor>
            <lookup lookupQuery="gtk-ru.bitec.app.btk.Btk_ClassStateAvi#Lookup_Class"
                    changeableAttr="idState"
                    isLookupLazyLoad="true" lookupKeyAttr="id" lookupListAttr="sHeadLine"/>
        </editor>
        <card isControlWidthFixed="true" controlWidth="60"/>
        <ref class="Btk_ClassState"/>
    </attr>

Методы для работы с состояниями:

    /**
    * Метод ищет состояние по сист. имени и сист. имени класса, к которому оно относится
    * @param spSystemName  Сист. имя состояния
    * @param spMasterClass Сист. имя класса, к которому относится состояние
    * @param bpRaiseErr    При значении = 1.nn будут создаваться исключения, если не найден класс, либо нужное состояние
    */
    Btk_ClassStateApi().findByNameAndClass(spSystemName:NString, spMasterClass:NString, bpRaiseErr:NNumber = 0.nn): NLong

    /**
    * Возвращает начальное состояние для класса
    * @param idpMasterClass идентификатор класса
    */
    Btk_ClassStateApi().getClassStartState(idpMasterClass: NLong) :NLong

    /**
        * Возвращает номер состояния класса по его id
        */
    Btk_ClassStateApi().getOrder(idp: NLong): NNumber

В прикладном коде не всегда удобно проверять ссылку на состояние, поэтому у каждого состояния есть номер. Фреймворк позволяет сохранять номер состояния в отдельном атрибуте.

Если в классе объявлен специальный атрибут с признаком `isStateMC=true`, фреймворк автоматически будет сохранять в него номер текущего состояния.

    <attr name="idStateMC"
          attribute-type="Number"
          caption="Состояние"
          order="51"
          type="basic"
          isVisible="false"
          isStateMC="true" />

#### История состояний

Для классов, имеющих атрибут состояния (`idState`) по умолчанию, ведется история состояний. Данные хранятся в классе `Btk_ObjectStateHistory`. Через dpi-сеттер состояния создаются записи в журнале изменения состояний.

Для отключения истории состояний необходимо воспользоваться атрибутом `isStateHistoryEnabled` тега `class`.

Для просмотра истории состояния объекта:

1. Откройте «Информацию об объекте»

2. Перейдите в закладку «История состояний» Откроется универсальная закладка `Btk_ObjectStateHistoryAvi.List_GidObj`, которая отображает историю состояний объекта. Работает от супер-параметра, в котором указан gid-объекта.

Возможные параметры закладки `Btk_ObjectStateHistoryAvi.List_GidObj`:

- `sGidAttrName` - имя атрибута, в котором хранится gid-объекта из мастер выборки.
  По умолчанию gid.

- `bWithStack` - признак необходимости отображения стека вызова.
  Доступные значения: 0, 1. По умолчанию 0.

Пример использования параметров, при подключении закладки через разметку выборки:

    <tabItem selection="gtk-Btk_ObjectStateHistoryAvi"
             representation="List_GidObj"
             caption="История состояний">
        <params>
            <param name="sGidAttrName"
                   value="gid"
                   dataType="String"/>
            <param name="bWithStack"
                   value="1"
                   dataType="Number"/>
        </params>
    </tabItem>

#### Настройка вызова процедур на переход между состояниями

В разрезе типа объекта возможно настроить перечень процедур, которые будут выполнены при переходе из одного состояния в другое.

Есть несколько типов событий, на которые можно настроить вызов произвольных процедур:

- `На вход в состояние` - будут вызваны, если это состояние будет конечным при любом переходе. Настраивается в детализации к состоянию.

- `На выход из состояния` - будут вызваны, если это состояние будет начальным при любом переходе. Настраивается в детализации к состоянию.

- `На переход` - будут вызываны, если будет осуществлен именно этот переход. Настраивается в детализации к переходу.

Порядок вызова событий:

1. Выполнение процедур на выход из состояния

2. Выполнение процедур на переход

3. Выполнение процедур на вход в состояние

Доступные переменные в `jexl`-скрипте:

- `rop` - `rop` объекта, для которого была вызвана смена состояния.

- `idOldState` - старое состояние объекта

- `idNewState` - новое состояние объекта

#### Управление проектными настройками состояний

Проектные настройки переходов состояний обеспечивают контроль над изменениями в бизнес-логике системы, предотвращая случайные модификации важных переходов между состояниями.

Назначение функционала

Функционал используется для:

- Защиты проектно настроенных переходов от случайных изменений.

- Требования явного подтверждения при ручном вмешательстве.

- Автоматического проставления флага проектного переопределения.

Логика обработки изменений переходов

При работе с переходами состояний система обеспечивает контроль над проектными настройками через флаг `bIsProjectSet`. Этот механизм предотвращает случайные изменения в проектно настроенных состояниях и требует подтверждения при ручном вмешательстве.

При выполнении операций добавления или удаления переходов система проверяет, является ли начальное состояние проектно настроенным:

- Если состояние не проектно настроено (`bIsProjectSet = 0`), операция требует подтверждения пользователя.

- Если состояние проектно настроено (`bIsProjectSet = 1`), изменение выполняется без подтверждения.

Пример проверки начального состояния:

    private def withProjectSetConfirmation(bvIsProjectSet: Boolean, warningText: String, operation: () => Unit): Unit = {
      if (bvIsProjectSet) {
        operation()
      } else {
        dialogs.showMsgDialog(
          msgBoxType = MsgDlg.confirmation,
          text = warningText,
          buttons = List(MsgDlgButton.yes, MsgDlgButton.no)
        ) match {
          case MsgDlgButton.yes => operation()
          case _ =>
        }
      }
    }

Добавление перехода

- Проверяется флаг `bIsProjectSet` начального состояния.

- При `bIsProjectSet = 0` выводится предупреждение:
  «Внимание, внесение ручных правок автоматически проектно переопределяет переходы между состояниями!»

- После подтверждения пользователем:

  - Создаётся новый переход.

  - Устанавливается флаг `bIsProjectSet = 1`.

Удаление перехода

- Также проверяется флаг `bIsProjectSet` начального состояния.

- При `bIsProjectSet = 0` выводится предупреждение:
  «Внимание, удаление перехода состояний автоматически проектно переопределяет начальное состояние!»

- После подтверждения пользователем:

  - Переход удаляется.

  - Устанавливается флаг `bIsProjectSet = 1`.

Для проставления поля проектного переопределения в true используется метод:

    // После ручных изменений система автоматически устанавливает флаг
    if (!bvIsProjectSet) {
      classStateApi.setbIsProjectSet(startStateRop, 1.nr)
    }

Регистрация перехода состояния в API

Метод `Btk_StateChangeApi.register()` предоставляет параметр `bpIgnoreProjectSet` для управления проверкой проектных настроек:

      /**
        * Метод регистрации возможных переходов состояний
        *
        * @param idpStartState       Начальное состояние
        * @param idpFinishState      Конечное состояние
        * @param idpObjectType       тип для которого будет возможен переход
        * @param bpIgnoreProjectSet  Проверка для возможности пересоздать переход (по стандарту запрещается пересоздавать, если состояние переопеределено проектно)
        */

    def register(
      idpStartState: NLong,
      idpFinishState: NLong,
      idpObjectType: NLong,
      bpIgnoreProjectSet: Boolean = false  // игнорировать проверку проектных настроек
    ): ApiRop

Обработка зависимостей при удалении перехода состояний

    // При удалении перехода выполняются дополнительные проверки
    override def delete(rop: ApiRop): Unit = {
      Btk_Ept().beforeDeleteStateChange(rop.get(_.id))  // проверка перед удалением
      Btk_AcRoleStateChangeGrantApi().deleteByStateChange(rop.get(_.id))  // очистка прав доступа
      super.delete(rop)
    }

Особенности работы

- При `bpIgnoreProjectSet = false` (по умолчанию) переход создается только если начальное состояние проектно не переопределено, т.е. `bIsProjectSet = 0`.

- При `bpIgnoreProjectSet = true` переход создается независимо от проектных настроек.

- При программном создании перехода флаг `bIsProjectSet` автоматически устанавливается в значение «1».

### Объектные характеристики

Можно настроить вывод объектных характеристик на каждый тип объекта. На закладке характеристик учитывается настройка объектных характеристик на тип объекта.

### Пообъектные права по умолчанию

На закладке можно настроить права доступа по умолчанию для пообъектного режима доступа. Настройка происходит в списки с атрибутами:

- Пользователь

- Роль

- Вид роли ОФС

- Группа доступа

#### Запрет редактирования объектов после создания

Механизм запрета редактирования даёт администраторам простой способ защитить критичные данные типизированных объектов (например, ключи интеграции) от случайного изменения или удаления после их первого сохранения.

Флаг запрета редактирования задаётся на типе объекта: `Настройка системы - Сущности - Типы объектов - Свойства типа объекта`. Атрибут — `"Запрещено редактирование объектов после создания"`.

Особенности реализации

Проверка происходит перед flush (сохранение дискеткой) на всех выборках, учитываются как параметры, хранящиеся в JSON, так и параметры в базе данных. Атрибуты-исключения обрабатываются по имени, без учёта регистра.

Главный метод проверки находится в `Btk_ObjectTypePkg.validateReadOnly()`.

Примечание

При попытке сохранения объекта с типом, запрещённым для редактирования, пользователь увидит ошибку:

Запрещено редактировать объект класса <наименование класса> с типом <наименование типа объекта> после создания. Системные имена изменённых атрибутов: <системные имена атрибутов, запрещённых к редактированию>

##### Атрибуты-исключения

Функционал предоставляет возможность отключить запрет на редактирование для конкретных параметров с помощью флага `"Отключен запрет редактирования"`, при этом проверки для остальных параметров класса сохраняются.

Пути настройки исключений в интерфейсе:

- Атрибуты класса
  `Настройка системы - Сущности - Типы объектов - Управление атрибутами`

- Атрибуты типа объекта (объектные и универсальные характеристики)
  `Настройка системы - Сущности - Объектные характеристики`

- Атрибуты шаблона
  `Настройка системы - Настройки и сервисы - Шаблоны характеристик - Атрибуты шаблона`

Примечание

Системные атрибуты (имя заканчивается на `_dz`) и `bNotUsed` — `"Не используется"`, `dExpiryDate` — `"Дата окончания использования"` можно изменять даже при включённой настройке `"Запрещено редактирование объектов после создания"`.

## Подключение индивидуальных настроек объекта

Настройки типа объекта могут быть расширены индивидуальными классами настроек. Такие настройки могут включать или отключать бизнес-логику, управлять фреймами, настраивать права доступа и т.д. в зависимости от поставленной задачи. Индивидуальная настройка добавляются в список настроек для типа документа.

Интерфейс доступен из приложения `Настройка системы`, меню: `Сущности > Типы объектов > Настройка детализации типов объектов`.

При создании собственной настройки для типа объекта можно указать список классов, у которых должна выводиться данная настройка. Если список классов пуст, то настройка выводится у всех типов объекта.

Также можно указать список подклассов, для которых требуется выводить настройку. Если список подклассов не указан, ограничения по подклассам не применяются.

## Регистрация из кода

### Регистрация закладок

Описание метода `Btk_TabApi().register`:

    /**
        * Процедура для регистрации новой строки
        *
        * @param spSystemName  Необязательный параметр - Системное имя
        * @param spCaption     Название закладки
        * @param spSel         Выборка
        * @param spRep         Отображение
        * @param idprefClass   Необязательный параметр - Класс на который регистрируется закладка
        * @param spDescription Необязательный параметр - Описание
        * @param spCondition   Необязательный параметр - Условие появления
        * @param spManualFunction Необязательный параметр - Функция получения списка закладок
        * @param idpDataClass  Необязательный параметр - Класс отображаемых в закладке данных(для универсальных коллекций)
        * @param spMasterAttr  Необязательный параметр - Атрибут с мнемокодом атрибута, через который класс из закладки будет ссылаться на мастера
        * @param npImage       Необязательный параметр - Картинка по умолчанию
        */

Пример ручной настройки Api класса `Stm_ActInApi.scala`:

    def regTab(): Unit = {
      session.commit()
      session.setDefaultUOWEditType(RWSharedUOWET)

      Btk_TabApi().register(
        spCaption = "Товарные позиции"
        , spSel = "gtk-Stm_ActInDetAvi"
        , spRep = "List_idDoc"
        , idprefClass = idClass
      )

      Btk_TabApi().register(
        spCaption = "Складские ордера"
        , spSel = "gtk-Stk_WarrantInAvi"
        , spRep = "LinkDocs"
        , idprefClass = idClass
      )
      session.commit()
    }

Пример регистрации скрипта в тэге dbData для odm класса `Stm_ActIn`:

    <script name="regTab" version="1">
        <install>Stm_ActInApi.regTab();</install>
    </script>

### Регистрация состояний

Описание метода `Btk_ClassStateApi().register`:

    /**
    * Метод регистрирует состояние для класса по сист. имени. Если остальные атрибуты не переданы, они не изменяются
    * Переданные значения параметров записываются в объект, если он найден по id класса и сист. имени состояния
    * @param idpMasterClass Класс, к которому относится состояние
    * @param spSystemName   Сист. имя состояния - должно быть уникально в рамках класса, к которому относится состояние
    * @param spCaption      Необязательный параметр - наименование
    * @param bpStartState   Необязательный параметр - признак стартового состояния
    * @param npOrder        Необязательный параметр - порядковый номер состояния в классе
    */

Кроме того есть перегруженная версия метода, где первый параметр – сист.имя класса

    /**
    * @param spMasterClass  Мнемокод класса, для которого регистрируем состояния
    */

Пример ручной настройки Api класса `Stm_ActInApi.scala`:

    def regState: Unit = {
      session.commit()
      session.setDefaultUOWEditType(RWSharedUOWET)
      //Регистрация состояний
      Btk_ClassStateApi().register(
        idpMasterClass = idClass,
        spSystemName = "Forming",
        spCaption = "Формируется",
        bpStartState = 1.nn,
        npOrder = 100.nn)
      session.flush() //чтоб было начальное состояние
      Btk_ClassStateApi().register(
        idpMasterClass = idClass,
        spSystemName = "Executing",
        spCaption = "Исполняется",
        bpStartState = 0.nn,
        npOrder = 200.nn)
      Btk_ClassStateApi().register(
        idpMasterClass = idClass,
        spSystemName = "Done",
        spCaption = "Выполнена",
        bpStartState = 0.nn,
        npOrder = 300.nn)
      session.commit()
    }

Пример регистрации скрипта в тэге dbData для odm класса `Stm_ActIn`:

    <script name="regState" version="1">
        <install>Stm_ActInApi.regState();</install>
    </script>

### Регистрация подкласса, типа объекта, закладок для типа и переходов состояний

Пример ручной настройки Api класса `Stm_ActInApi.scala`:

    def regObjectType(bpNeedRefresh: Boolean = true): Unit = {
      session.commit()
      Btk_Pkg().setRWSharedUOWEditType()
      val idvInvoice = Btk_SubClassApi().register("invoiceIn", "Приходная накладная", idClass, "").get(_.id)
      session.flush()

      if (bpNeedRefresh || Btk_ObjectTypeApi().findByMnemoCodeAndClass("Stm_ActInInvoice", idClass).isNull) {
        //регистрируем тип
        val idvObjectType = Btk_ObjectTypeApi().register(
          spCode = "Stm_ActInInvoice".ns
          , spCaption = "Приходная накладная".ns
          , spShortCaption = "Приходная накладная".ns
          , idpRefClass = idClass
          , idpSubClass = idvInvoice
          , bpIsDefault = 1.nn
        )
        //ищем закладку и привязываем к типу
        var idvTab = Btk_TabApi().findByMnemoCode("Stm_ActInDetAvi.List_idDoc")
        if (idvTab.isNotNull)
          Btk_ObjectTypeTabApi().registerTab(
            idpObjectType = idvObjectType
            , idpTab = idvTab
            , spCaption = "Товарные позиции"
            , npOrder = 10.nn
          )

        idvTab = Btk_TabApi().findByMnemoCode("Stk_WarrantInAvi.LinkDocs")
        if (idvTab.isNotNull)
          Btk_ObjectTypeTabApi().registerTab(
            idpObjectType = idvObjectType
            , idpTab = idvTab
            , spCaption = "Складские ордера"
            , npOrder = 20.nn
          )
        //регистрируем переходы состояний для типа
        Btk_StateChangeApi().registerForObjectType(idvObjectType, List(
          "Forming" -> "Executing",
          "Executing" -> "Done",
          "Executing" -> "Forming",
          "Done" -> "Forming",
          "Done" -> "Executing"
        ))
      }
      session.commit()
    }

Пример регистрации скрипта в тэге dbData для odm класса `Stm_ActIn`:

    <script name="regObjectType" version="1">
        <depends>
            <dep on="Stm_ActIn.regState"/>
            <dep on="Stm_ActIn.regTab"/>
        </depends>
        <install>Stm_ActInApi.regObjectType(false);</install>
    </script>

## Общая схема классов и типов объекта