Контрольное задание
Contents
Контрольное задание#
Вариант 1#
Регистр движения книг#
Создание класса-журнала#
Создайте директорию
regmov
и в нем классLbr_RegisterMov
-Регистр движения книг
с типомjournal
и атрибутами:
name |
attribute-type |
caption |
Дополнительно |
---|---|---|---|
idBook |
Long |
Книга |
Ссылается на класс Lbr_Book |
gidSrcDoc |
Varchar |
Документ источник |
Атрибут переменной ссылочности ( |
gidDet |
Varchar |
Позиция источник |
Атрибут переменной ссылочности |
nDirection |
Number |
Направление |
|
idLibrarian |
Long |
Библиотекарь |
Ссылочный на объект, ссылается на класс Bs_Person |
idPerson |
Long |
Читатель |
Ссылочный на объект, Ссылается на класс Bs_Person |
nQty |
Number |
Кол-во |
|
dReg |
Date |
Дата операции |
Редактор даты |
idDepOwner |
Long |
Организация |
Ссылочный на объект, Ссылается на класс Bs_DepOwner |
Запустите кодогенерацию по данному классу
Добавьте
orm
класса вall.xml
и запустите генератор таблиц для негоДобавьте в
Lbr_MainMenuAvi
пунктРегистр движения книг
подТесты и отладка
, в котором пропишите открытие умол. списка дляLbr_RegisterMovAvi
Отражение в регистр и удаление из него#
В Lbr_RegisterMovApi
напишите логику для отражения и удаления из регистра:
Для универсальности и изоляции логики регистра объявите
case class
(для удобства можно объявить передclass Lbr_RegisterMovApi
, например назватьobjReg
) с полями из таблицы нижеСоздайте метод отражения в регистр по списку объектов данного
case class
(напримерwrtByObj(apObj: List[objReg]
). В нем напишите обход (например черезforeach
) по списку объектовapObj
и создание записей в регистре по данным из них, при установке количества, можно записывать сразу с учетом nDirection, чтобы в дальнейшем при вычислении остатков не писать nQty*nDirection.Напишите метод удаления из регистра по полю
gidSrcDoc
, на вход будет gid документа (напримерdeleteBySrcDoc(gipSrcDoc: NGid)
). Вместо запросов можно использовать транзакционный индекс. Руководство разработчика: Взаимодействие с базой данных # Транзакционный индекс.
В Api
документов:
Напишите метод отражения в регистр по позициям документа, на вход будет rop документа (например
wrtToReg(rop: ApiRop)
). Для этого создайте переменнуюval avObj = ArrayBuffer[objReg]()
и при обходе по позициям документа (черезrefreshByParent
) заполнитеavObj
объектами изcase class
с данными по таблице ниже. После обхода позиций вызовите метод отражения в регистр по данным заполненного спискаLbr_RegisterMovApi().wrtByObj(avObj.toList)
На переход состояния в >=300 и из < 300, после вызова метода с проверками, пропишите вызов метода отражения в регистр, на обратный переход пропишите вызов метода удаления из регистра.
Таблица с полями для case class
и откуда надо брать для них значения:
Имя поля в регистре |
Тип |
Значение |
---|---|---|
idBook |
NLong |
idBook из позиции |
gidSrcDoc |
NGid |
gid документа |
gidDet |
NGid |
gid позиции |
nDirection |
NNumber |
1 для приходной накладной и возврата книг, -1 для выдачи книг |
idLibrarian |
NLong |
idLibrarian из документа |
idPerson |
NLong |
idPerson из документа, если есть такое поле |
nQty |
NNumber |
Количество в позиции, если атрибута с количеством нет, то берем 1 |
dReg |
NDate |
Дата документа |
idDepOwner |
NLong |
idDepOwner из документа |
Метод проверки на отрицательные остатки#
В Lbr_RegisterMovApi
напишите метод проверки на наличие отрицательных остатков для регистра, в разрезе idBook и idDepOwner.
Для этого:
Добавьте еще один
case class
с атрибутами разреза (напримерcase class objRegVal(idBook: NLong, idDepOwner: NLong)
) уже внутриLbr_RegisterMovApi
Добавьте новый метод, на вход которого будет список из данного
case class
(напримерvalidateReg(apObjVal: List[objRegVal])
)Для упрощения написания проверки, можно использовать
for (rv <- new ASelect
с запросом по регистру, с группировкой по разрезам и условием на отрицательное количество. Для передачи в запрос данных из параметраapObjVal
, создайте массивы с типомLongPgArray
для idBook и idDepOwner (напримерval idavBook = LongPgArray(apObjVal.map(_.idBook))
) и в запрос пропишите в конструкцииwith
трансформацию массивов в таблицу со столбцами. Далее уже можно обращаться кdata
как к обычной таблице.
with data as(
select unnest(${idavBook}) idBook
,unnest(${idavDepOwner}) idDepOwner
)
Внутри
for
соберите полученные данные запроса с отрицательными остатками в форматекнига ${HL книги} - остаток ${получившееся количество} (организация ${HL организации})"
в переменную (напримерval avError = ArrayBuffer[NString]()
) объявленную доfor
и уже в конце если она не пустая, то пропишите вызов ошибки в форматеДействие невозможно, так как в регистре образовались отрицательные остатки: ${собранные в avError данные}
.Если проверка будет осуществляться через запрос, то обязательно перед
for
пропишитеsession.flush()
, чтобы в БД были актуальные данные.В методе
wrtByObj
иdeleteBySrcDoc
допишите сбор данных разрезов в переменную со спискомcase class
(напримерval avObjRegVal = ArrayBuffer[objRegVal]()
) и в конце допишите вызов метода проверкиvalidateReg(avObjRegVal.toList)
Отчет по остаткам#
Шапка#
Создайте отдельную avi
для отчета по остаткам с полями:
ISBN книги
Наименование книги
Остаток на начало периода
Возврат/поступление за период
Выдача за период
Изменение за период
Остаток на конец периода
Особенности реализации:
Данные для отчета берем по регистру
Lbr_RegisterMov
Берем данные до конца периода и фильтруем их по организации.
Для расчета количество на начало периода суммируем только те данные, дата которых меньше начала периода.
Для расчета изменений в текущем периоде суммируем только те данные, дата которых входит в наш период.
Примечание
Для того чтобы исключить данные из суммирования можно воспользоваться следующей конструкцией:
sum(case when r.dRegDate <= :flt_dBegin then <расчет количества> end)
Фильтр с подстановкой значений по умолчанию из главной выборки приложения:
Период с
редактор даты.по
редактор датыОрганизация
выпадающий список
Расположите фильтры в одну строчку (принцип размещения атрибутов на панели фильтров аналогичен размещению в карточке. Если будете делать через разметку hBox
, vBox
, то используйте тег layout
внутри тега filter
)
Примечание
В этом задании нельзя использовать макрос фильтра в тексте запроса, т.к. нам нужны данные до начала периода, чтобы посчитать количество на начало. Следует обращаться к переменным фильтра напрямую в запросе, например, :flt_dBegin
Перечень атрибутов выборки главного приложения можно посмотреть через debugger
. Для получения значения используйте метод getVar
, передав в него имя нужного атрибута с префиксом super$
Детализация#
Создайте и подключите детализацию к мастер-выборке с расшифровкой по документам:
HL документа
(для удобства заголовок можно взять изLbr_Document
)Дата
Количество с учетом направления
Примечание
Данные отчета берем по регистру
Lbr_RegisterMov
Фильтруем их по периоду, книге и организации
Группируем по документу, считаем количество
Добавьте операцию открытия документа в карточке с помощью метода открытия по gid Btk_CommonOperLib().cardEdit
Вариант 2#
Регистр движения книг#
Создание класса-журнала#
Создайте директорию
regmov
и в нем классLbr_RegisterMov
-Регистр движения книг
с типомjournal
и атрибутами:
name |
attribute-type |
caption |
Дополнительно |
---|---|---|---|
idBook |
Long |
Книга |
Ссылается на класс Lbr_Book |
gidSrcDoc |
Varchar |
Документ источник |
Атрибут переменной ссылочности ( |
gidDet |
Varchar |
Позиция источник |
Атрибут переменной ссылочности |
nDirection |
Number |
Направление |
|
idLibrarian |
Long |
Библиотекарь |
Ссылочный на объект, ссылается на класс Bs_Person |
idPerson |
Long |
Читатель |
Ссылочный на объект, Ссылается на класс Bs_Person |
nQty |
Number |
Кол-во |
|
dReg |
Date |
Дата операции |
Редактор даты |
idDepOwner |
Long |
Организация |
Ссылочный на объект, Ссылается на класс Bs_DepOwner |
Запустите кодогенерацию по данному классу
Добавьте
orm
класса вall.xml
и запустите генератор таблиц для негоДобавьте в
Lbr_MainMenuAvi
пунктРегистр движения книг
подТесты и отладка
, в котором пропишите открытие умол. списка дляLbr_RegisterMovAvi
Отражение в регистр и удаление из него#
В Lbr_RegisterMovApi
напишите логику для отражения и удаления из регистра:
Для универсальности и изоляции логики регистра объявите
case class
(для удобства можно объявить передclass Lbr_RegisterMovApi
, например назватьobjReg
) с полями из таблицы нижеСоздайте метод отражения в регистр по списку объектов данного
case class
(напримерwrtByObj(apObj: List[objReg]
). В нем напишите обход (например черезforeach
) по списку объектовapObj
и создание записей в регистре по данным из них, при установке количества, можно записывать сразу с учетом nDirection, чтобы в дальнейшем при вычислении остатков не писать nQty*nDirection.Напишите метод удаления из регистра по полю
gidSrcDoc
, на вход будет gid документа (напримерdeleteBySrcDoc(gipSrcDoc: NGid)
). Вместо запросов можно использовать транзакционный индекс. Руководство разработчика: Взаимодействие с базой данных # Транзакционный индекс.
В Api
документов:
Напишите метод отражения в регистр по позициям документа, на вход будет rop документа (например
wrtToReg(rop: ApiRop)
). Для этого создайте переменнуюval avObj = ArrayBuffer[objReg]()
и при обходе по позициям документа (черезrefreshByParent
) заполнитеavObj
объектами изcase class
с данными по таблице ниже. После обхода позиций вызовите метод отражения в регистр по данным заполненного спискаLbr_RegisterMovApi().wrtByObj(avObj.toList)
На переход состояния в >=300 и из < 300, после вызова метода с проверками, пропишите вызов метода отражения в регистр, на обратный переход пропишите вызов метода удаления из регистра.
Таблица с полями для case class
и откуда надо брать для них значения:
Имя поля в регистре |
Тип |
Значение |
---|---|---|
idBook |
NLong |
idBook из позиции |
gidSrcDoc |
NGid |
gid документа |
gidDet |
NGid |
gid позиции |
nDirection |
NNumber |
1 для приходной накладной и возврата книг, -1 для выдачи книг |
idLibrarian |
NLong |
idLibrarian из документа |
idPerson |
NLong |
idPerson из документа, если есть такое поле |
nQty |
NNumber |
Количество в позиции, если атрибута с количеством нет, то берем 1 |
dReg |
NDate |
Дата документа |
idDepOwner |
NLong |
idDepOwner из документа |
Метод проверки на отрицательные остатки#
В Lbr_RegisterMovApi
напишите метод проверки на наличие отрицательных остатков для регистра, в разрезе idBook и idDepOwner.
Для этого:
Добавьте еще один
case class
с атрибутами разреза (напримерcase class objRegVal(idBook: NLong, idDepOwner: NLong)
) уже внутриLbr_RegisterMovApi
Добавьте новый метод, на вход которого будет список из данного
case class
(напримерvalidateReg(apObjVal: List[objRegVal])
)Для упрощения написания проверки, можно использовать
for (rv <- new ASelect
с запросом по регистру, с группировкой по разрезам и условием на отрицательное количество. Для передачи в запрос данных из параметраapObjVal
, создайте массивы с типомLongPgArray
для idBook и idDepOwner (напримерval idavBook = LongPgArray(apObjVal.map(_.idBook))
) и в запрос пропишите в конструкцииwith
трансформацию массивов в таблицу со столбцами. Далее уже можно обращаться кdata
как к обычной таблице.
with data as(
select unnest(${idavBook}) idBook
,unnest(${idavDepOwner}) idDepOwner
)
Внутри
for
соберите полученные данные запроса с отрицательными остатками в форматекнига ${HL книги} - остаток ${получившееся количество} (организация ${HL организации})"
в переменную (напримерval avError = ArrayBuffer[NString]()
) объявленную доfor
и уже в конце если она не пустая, то пропишите вызов ошибки в форматеДействие невозможно, так как в регистре образовались отрицательные остатки: ${собранные в avError данные}
.Если проверка будет осуществляться через запрос, то обязательно перед
for
пропишитеsession.flush()
, чтобы в БД были актуальные данные.В методе
wrtByObj
иdeleteBySrcDoc
допишите сбор данных разрезов в переменную со спискомcase class
(напримерval avObjRegVal = ArrayBuffer[objRegVal]()
) и в конце допишите вызов метода проверкиvalidateReg(avObjRegVal.toList)
Отчет по остаткам#
Главная форма#
Создайте отдельную avi
для отчета по остаткам с полями:
ISBN книги
Наименование книги
HL документа
Дата документа
Номер документа
Количество с учетом направления
Особенности реализации:
Данные для отчета берем по регистру
Lbr_RegisterMov
Поля, которые относятся к документу можно взять из миксина
Lbr_Document
Фильтруем их по периоду, организации и документу
Рабочий период определяется от даты в фильтре +- 30 дн.
Группируем по документу, считаем количество
Фильтры:
Дата
Текущая дата.Организация
выпадающий список. Значение берется из главной выборки приложенияДокумент
Фильтр с тремя точками. Позволяет открыть список объектов миксинаLbr_Document
.
Фильтры дата
и Организация
расположите в одной строчке.
Фильтр Документ
в отдельной строке
(принцип размещения атрибутов на панели фильтров аналогичен размещению в карточке. Если будете делать через разметку hBox
, vBox
, то используйте тег layout
внутри тега filter
)
Примечание
Перечень атрибутов выборки главного приложения можно посмотреть через debugger
. Для получения значения используйте метод getVar
, передав в него имя нужного атрибута с префиксом super$
Текущую дату можно получить через NDate.now()
Добавьте операцию открытия документа в карточке с помощью метода открытия по gid Btk_CommonOperLib().cardEdit
Форма с остатками#
В главной форме добавьте операцию на тулбар, которая будет по выделенной строке регистра выводить информацию об остатках по книгам, по которым было движение в указанном периоде.
Для этого необходимо:
Создать еще одно отображение в вышей выборке, которая будет отображать информацию с остатками
Из операции главной формы необходимо открывать форму с остатками, передав туда параметры о текущем выбранном периоде, организации, и документе в выделенной строке.
В форме-расшифровке реализуйте вывод следующих полей:
ISBN книги
Наименование книги
Остаток на начало периода
Возврат/поступление за период
Выдача за период
Изменение за период
Остаток на конец периода
Особенности реализации:
Данные для отчета берем по регистру
Lbr_RegisterMov
Берем данные до конца периода и фильтруем их по организации (они переданы через параметры в форму).
Берем только книги, по которым было движение в переданном документе.
Рабочий период определяется от переданной даты +- 30 дн.
Для расчета количество на начало периода суммируем только те данные, дата которых меньше начала периода.
Для расчета изменений в текущем периоде суммируем только те данные, дата которых входит в наш период.
Примечание
Следует обращаться к переданным параметрам напрямую в запросе, например, :dDate_dz
Для того чтобы исключить данные из суммирования можно воспользоваться следующей конструкцией:
sum(case when r.dRegDate <= :dDate_dz - interval '30 days' then <расчет количества> end)