Тип объекта#

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

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

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

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

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

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

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

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

Внимание

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

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

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

Примечание

Для супертипа 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 - новое состояние объекта

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

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

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

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

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

  • Роль

  • Вид роли ОФС

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

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

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

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

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

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

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

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

Описание метода 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,
    npOrer = 100.nn)
  session.flush() //чтоб было начальное состояние
  Btk_ClassStateApi().register(
    idpMasterClass = idClass,
    spSystemName = "Executing",
    spCaption = "Исполняется",
    bpStartState = 0.nn,
    npOrer = 200.nn)
  Btk_ClassStateApi().register(
    idpMasterClass = idClass,
    spSystemName = "Done",
    spCaption = "Выполнена",
    bpStartState = 0.nn,
    npOrer = 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>

Общая схема классов#