Разработка функциональных отчетов

Материал из RSB-Doc
Перейти к: навигация, поиск

Содержание

Схема работы функционального отчёта

Функциональный отчёт (в дальнейшем просто отчёт) можно разделить на три основных части (рис. 1), как при работе, так и при разработке:

  1. Выбор параметров
  2. Отбор данных
  3. Отображение данных

Pict1.jpg

Рис. 1. Схема работы функционального отчёта, где: ФИ – форма инициализации; ЭФ – экранная форма; ПФ – печатная форма.

Форма инициализации или выбор параметров

Вызов отчета без формы инициализации

Можно сказать, что за выбор параметров всегда отвечает форма инициализации, но это не совсем так. Мы можем вызвать отчет и из какого-нибудь диалога, причем, не открывая форму инициализации, например из диалога документа: Разработка функциональных отчетов

var inParams = CReportInputParams();
var objSpec = m_dsData.RSObject.SubObjects("Спецификация");
 
if(objSpec.Run("ValidPosition"))
  inParams.SetValue("Номенклатура", objSpec.Fields("Номенклатура по документу").Value);
  RunFuncReportByName(m_objOwner, "История закупок товара", inParams, true);
else
  MsgBox("Не выбрана позиция спецификации документа");
end;

Но все же основным вариантом подготовки параметров для отчета служит форма инициализации.

Форма инициализации

Формы инициализации могут быть простыми или сложными. Сейчас они как можно более стандартизированы, и в дальнейшем будут стандартизироваться. Что это значит? Многие элементы на различных формах похожи и даже не просто похожи – они одинаковы, да и не только элементы, а целые блоки элементов. (см. Блоки для форм инициализации)

Форма

FastDevReportOnRSReport 2.jpg

Рис. 2. Пример формы инициализации

FastDevReportOnRSReport 3.jpg

Рис. 3. Внешний вид формы инициализации в Designer'е

Т.о. образом получается, что нет необходимости описывать логику работы элементов на формах инициализации, достаточно просто добавить блоки на форму. Прямоугольники на форме Designer'е – это слоты, скажем так, места для форм, сами формы будут привязаны к ним в макросе.

Внимание! Начиная со сборки 3.25.27.0, реализована возможность создавать ФИ с изменяемыми размерами. Для этого необходимо заполнить свойства MinWidth и MinHeight у формы. Для всех остальных ФИ эти свойства необходимо оставлять равными нулю. В формах, в которых эти свойства уже заполнены, а изменение размеров не требуется, свойства необходимо обнулить.

Макрос

Теперь посмотрим, как выглядит код этой формы инициализации:

cpwin;
import COrptBaseForm;
 
CLASS (CReportInitForm) CCOrptInitForm284 (_oOwner: Object, _sName: String, _oInputParams: CReportInputParams)
  InitCReportInitForm(_oOwner, _sName, _oInputParams);
  setTemplate("COrptInitForm.lbr", "F0000082");
 
  m_objSetting.Add("Настройки по задачам\\Отчетность\\Поле артикула",     "ПолеА");
  m_objSetting.Add("Настройки по задачам\\Отчетность\\Поле номенклатуры", "ПолеН");
 
  var objPeriod = CCOrptBaseForm_Period(_oInputParams);
  BindSlot(objPeriod, "slotPeriod");
 
  var objGrDocs = CCOrptBaseForm_GrDocs(_oInputParams, "\"Объект группы\" = '"+ GetObjectGUIDByName("Товарный документ") +"' AND \"Состояние\" = 'действует'");
      objGrDocs.SetRequired();
  BindSlot(objGrDocs, "slotGrDocs");
 
  var objWare = CCOrptBaseForm_StdElem_SmartGrid(_oInputParams, CStructStdElem("Номенклатура", TYPE_STD_ELEM_ALL_SUB), NULL, NULL,
                                                 MakeTArray("Код", "Артикул", "Наименование краткое"));
  BindSlot(objWare, "slotWare");
 
  var objInSubj = CCOrptBaseForm_InSubj_SmartGrid(_oInputParams);
  BindSlot(objInSubj, "slotInSubj");
 
  var fldWithoutMove = TControl(this, "fldWithoutMove");
  var fldGetTransfer = TControl(this, "fldGetTransfer");
 
  Macro SetControlsProperties (_oContainerForm: Object)
    SetControlsProperties(_oContainerForm);
    objGrDocs.MoveControlsToNewStyle();
  End;
END;

Разберем код этого макроса.

cpwin;

Эта строка нужна обязательно во всех макросах – она говорит, что текст макроса написан с использованием кодировки Windows.

import COrptBaseForm;

В этой строке говорится, что мы будем пользоваться чем-нибудь из этого макроса. Импорт макроса COrptBaseForm.mac обязателен, так как именно в нём описаны все стандартные классы для форм инициализации отчётов.

Теперь само имя класса должно быть “C”+<имя макроса>. Т.е.

CLASS (CReportInitForm) CCOrptInitForm284 (_oOwner: Object, _sName: String, _oInputParams: CReportInputParams)

означает, что текущий макрос называется COrptInitForm284.mac.

Наследоваться класс должен от CReportInitForm.

  InitCReportInitForm(_oOwner, _sName, _oInputParams);

Этой строчкой вызывается конструктор базового класса.

  setTemplate("COrptInitForm.lbr", "F0000082");

Эта строчка сопоставляет данный класс с указанной формой.

  m_objSetting.Add("Настройки по задачам\\Отчетность\\Поле артикула",     "ПолеА");
  m_objSetting.Add("Настройки по задачам\\Отчетность\\Поле номенклатуры", "ПолеН");

Эти строки добавляют в массив обязательные для заполнения настройки Утилиты администратора, которые будут считаны при подъеме формы инициализации. Используется свойство m_objSetting (экземпляр класса CReportSettingManger).

  var objPeriod = CCOrptBaseForm_Period(_oInputParams);
  BindSlot(objPeriod, "slotPeriod");
 
  var objGrDocs = CCOrptBaseForm_GrDocs(_oInputParams, "\"Объект группы\" = '"+ GetObjectGUIDByName("Товарный документ") +"' AND \"Состояние\" = 'действует'");
      objGrDocs.SetRequired();
  BindSlot(objGrDocs, "slotGrDocs");
 
  var objWare = CCOrptBaseForm_StdElem_SmartGrid(_oInputParams, CStructStdElem("Номенклатура", TYPE_STD_ELEM_ALL_SUB), NULL, NULL,
                                                 MakeTArray("Код", "Артикул", "Наименование краткое"));
  BindSlot(objWare, "slotWare");
 
  var objInSubj = CCOrptBaseForm_InSubj_SmartGrid(_oInputParams);
  BindSlot(objInSubj, "slotInSubj");

А этими строками мы создаем формы для блоков периода, группы документов, номенклатуры и внутренних субъектов, и связываем их со слотами формы инициализации. Если немного по-подробнее, то

  var objPeriod = CCOrptBaseForm_Period(_oInputParams);

этой строкой создается форма (объект) для блока "Период", а

  BindSlot(objPeriod, "slotPeriod");

в этой строке, функцией BindSlot этот созданный объект связывается со слотом "slotPeriod".

А далее идет инициализация двух полей посредством класса "TControl" и изменение параметров формы группы документов.

  var fldWithoutMove = TControl(this, "fldWithoutMove");
  var fldGetTransfer = TControl(this, "fldGetTransfer");
 
  Macro SetControlsProperties (_oContainerForm: Object)
    SetControlsProperties(_oContainerForm);
    objGrDocs.MoveControlsToNewStyle();
  End;

Стандартные элементы

Теперь подробно остановимся на классах стандартных элементов форм инициализации отчётов.

Дата

CCOrptBaseForm Date.jpg

Класс CCOrptBaseForm_Date (добавлен в сборку 3.25.18.0). Правильный вариант его использования:

var objDate = CCOrptBaseForm_Date(_oInputParams);
BindSlot(objDate, "slotDate");

Особенности такие:

  1. не стоит путать с классом "CCOBaseForm_Date" (он более не используется)
  2. первым (и единственным) параметром обязательно передаём InputParams
  3. элемент загружаем именно в слот
  4. в сборках 3.20, 3.22 и 3.24 элемент используем "по-старинке"


По умолчанию блок обязателен для заполнения. Снять обязательность можно на этапе инициализации формы отчёта с помощью свойства m_bRequired. Пример:

objDate.m_bRequired = false;

Если на форме используется несколько таких блоков, то необходимо задать уникальные значения для свойства Tag контрола fldDate.

Для справки:

  1. Размеры формы: высота 694, ширина 5595
  2. Основные элементы: lblDate и fldDate
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Отступ поля fldDate от левого края формы 3055
  5. Стандартное значение свойства Tag: "Дата"
  6. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_Date_"+<Tag>
Период

CCOrptBaseForm Period 2.PNG или CCOrptBaseForm Period 2 1.PNG

Класс CCOrptBaseForm_Period (добавлен в сборку 3.25.18.0). Правильный вариант его использования:

var objPeriod = CCOrptBaseForm_Period(_oInputParams);
BindSlot(objPeriod, "slotPeriod");

Особенности такие:

  1. не стоит путать с классом "CCOBaseForm_Period" (он более не используется)
  2. первым (и единственным) параметром обязательно передаём InputParams
  3. элемент загружаем именно в слот
  4. в сборках 3.20, 3.22 и 3.24 элемент используем "по-старинке"

Начиная со сборки 3.25.93.0 увеличена ширина блока, добавлен список периодов и кнопка для выбора режима "список" или "даты".

Начиная со сборки 3.25.70.0 блок можно добавлять на форму динамически (без слота в lbr-файле) следующим образом:

AddBlock("Period", "Период");

По умолчанию блок обязателен для заполнения. Снять обязательность можно на этапе инициализации формы отчёта с помощью свойства m_bRequired. Пример:

objPeriod.m_bRequired = false;

Если на форме используется несколько таких блоков, то необходимо задать уникальные значения для свойств m_sBlockName (добавлено в сборку 3.25.70.0). Пример:

objPeriod.m_sBlockName = "Другой период";

Для справки:

  1. Размеры формы: высота 694, ширина 10195
  2. Основные элементы: lblDateFrom, fldDateFrom, lblDateTo, fldDateTo, fldList и btnList
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Отступ полей fldDateFrom и fldList от левого края формы 3055
  5. Отступ поля fldDateTo от левого края формы 6805
  6. Значения свойств Tag при стандартном имени блока (m_sBlockName = "Период"): "Период с" и "Период по"
  7. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_Period_"+<Tag>
Валюта

CCOrptBaseForm SimpleCurrency.JPG

Класс CCOrptBaseForm_SimpleCurrency (добавлен в сборку 3.25.44.0). Правильный вариант его использования:

var objCurrency = CCOrptBaseForm_SimpleCurrency(_oInputParams);
BindSlot(objCurrency, "slotCurrency");

Поле "Валюта" обязательно для заполнения.

Для справки:

  1. Размеры формы: высота 694, ширина 9345
  2. Основные элементы: lblCurrency, fldCurrency, lblRateType и fldRateType
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Отступ поля fldCurrency от левого края формы 3055
  5. Отступ поля fldRateType от левого края формы 6805
  6. Стандартные значения свойств Tag: "Валюта" и "Тип курса"
  7. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_Currency_"+<Tag>
Валюта с пересчётом

Режим №1:

CCOrptBaseForm Currency.jpg

Режим №2 (МВУ):

CCOrptBaseForm Currency 2.jpg или CCOrptBaseForm Currency 3.jpg

Класс CCOrptBaseForm_Currency (наследник класса CCOrptBaseForm_SimpleCurrency). Правильный вариант его использования:

var objCurrency = CCOrptBaseForm_Currency(_oInputParams, arrCalcRuleEnumValEx, arrCurrRuleEnumValEx);
BindSlot(objCurrency, "slotCurrency");

Особенности такие:

  1. первым параметром обязательно передаём InputParams
  2. вторым параметром (не обязательный) передаём массив дополнительных значений выпадающего списка "Правило пересчёта валюты"
  3. третьим параметром (не обязательный) передаём массив дополнительных значений выпадающего списка "Правило отбора валюты"
  4. поле "Валюта" обязательно для заполнения
  5. обязательность поля "Тип курса" зависит от признака "Пересчёт"

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

objCurrency.m_bReadOnly = true;

По умолчанию поднимается первый режим работы блока. Однако на этапе инициализации формы отчёта с помощью свойства m_bMVU возможно активировать второй режим работы, в котором становится доступна обработка Мультивалютного учета. Пример:

objCurrency.m_bMVU = true;

Массивы дополнительных значений для выпадающих списков можно заполнить после инициализации класса с помощью свойств m_arrCalcRuleEnumValEx и m_arrCurrRuleEnumValEx. Пример:

objCurrency.m_arrCalcRuleEnumValEx = MakeTArray("На дату расчета прайс-листа");
objCurrency.m_arrCurrRuleEnumValEx = MakeTArray("Валюта прайс-листа");

Для справки:

  1. Размеры формы: высота 1476, ширина 10195
  2. Основные элементы: lblCurrency, fldCurrency, lblRateType, fldRateType, fldUseCalc, fldCalcRule, btnMVU и fldCurrencyRule
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Отступ поля fldCurrency от левого края формы 3055
  5. Отступ поля fldRateType от левого края формы 6805
  6. Отступ кнопки btnMVU от левого края формы 9465
  7. Стандартные значения свойств Tag: "Валюта", "Тип курса", "Пересчёт валюты", "Правило пересчёта валюты" и "Правило отбора валюты"
  8. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_Currency_"+<Tag>
Простой базовый класс для перечислителя

CCOrptBaseForm StdEnum 2.jpg

Для блоков с полем-перечислителем разработан универсальный класс CCOrptBaseForm_SimpleStdEnum (добавлен в сборку 3.25.18.0). Пример его использования:

var objSort = CCOrptBaseForm_SimpleStdEnum(_oInputParams, CParamToStdEnum("Сортировка",
    "0=По наименованию;1=По коду;2=По артикулу;"));
BindSlot(objSort, "slotSort");

По умолчанию блок обязателен для заполнения. Снять обязательность можно на этапе инициализации формы отчёта с помощью свойства m_bRequired. Пример:

objSort.m_bRequired = false;

Класс CParamToStdEnum имеет следующие параметры:

sTag: String  // Тэг для поля (обязателен)
sEnumValues: String  // Значения перечислителя (если не заданы, то заполняются из БД по имени перечислителя)
sEnumName: String  // Имя перечислителя (необходимо, если значения перечислителя не заданы явно)
sText: String  // Текст перед полем (если не задан, то равен тэгу)
sToolTip: String  // Всплывающая подсказка для поля
sUseFlagToolTip: String  // Всплывающая подсказка для флажка "Использовать"
bHideUseFlag: Bool  // Скрыть флажок "Использовать"

Все эти параметры можно задать/изменить и на этапе инициализации формы отчёта. Они доступны через свойство m_objParam. Пример:

objSort.m_objParam.sTag = "Горючее";
objSort.m_objParam.sEnumValues = null;
objSort.m_objParam.sEnumName = "Вид топлива";

Если на форме используется несколько таких блоков, то необходимо задать уникальные значения параметра sTag

Для справки:

  1. Размеры формы: высота 694, ширина 9345
  2. Основные элементы: lblStdEnum и fldStdEnum
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Метка lblStdEnum расположена не стандартно: высота её увеличена до высоты формы и равна 694. Сделано это для того, чтобы в неё умещались две строки текста.
  5. Отступ поля fldStdEnum от левого края формы 3055
  6. Ширина поля fldStdEnum 6250
  7. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_StdEnum_"+<Tag>
Единица измерения

CCOrptBaseForm WareUnit.jpg

Класс CCOrptBaseForm_WareUnit (наследник класса CCOrptBaseForm_SimpleStdEnum). Пример его использования:

var objWareUnit = CCOrptBaseForm_WareUnit(_oInputParams);
BindSlot(objWareUnit, "slotWareUnit");

Для справки:

  1. Стандартное значение свойства Tag: "Единица измерения"
Универсальный базовый класс для перечислителя

CCOrptBaseForm StdEnum 3.jpg

Для блоков с полем-перечислителем и предобработчиком разработан универсальный класс CCOrptBaseForm_StdEnum (окончательно доработан в сборке 3.25.18.0). Пример его использования:

var objGroup = CCOrptBaseForm_StdEnum(_oInputParams, CParamToStdEnum("Группировка",
    "0=По организации;1=По складу;2=По сотруднику;"));
BindSlot(objGroup, "slotGroup");

По умолчанию блок не обязателен для заполнения. Установить обязательность можно на этапе инициализации формы отчёта с помощью свойства m_bRequired. Пример:

objGroup.m_bRequired = true;

Класс CParamToStdEnum имеет следующие параметры:

sTag: String  // Тэг для поля (обязателен)
sEnumValues: String  // Значения перечислителя (если не заданы, то заполняются из БД по имени перечислителя)
sEnumName: String  // Имя перечислителя (необходимо, если значения перечислителя не заданы явно)
sText: String  // Текст перед полем (если не задан, то равен тэгу)
sToolTip: String  // Всплывающая подсказка для поля
sUseFlagToolTip: String  // Всплывающая подсказка для флажка "Использовать"
bHideUseFlag: Bool  // Скрыть флажок "Использовать"

Все эти параметры можно задать/изменить и на этапе инициализации формы отчёта. Они доступны через свойство m_objParam. Пример:

objGroup.m_objParam.sText = "Простая группировка";
objGroup.m_objParam.bHideUseFlag = true;

Если на форме используется несколько таких блоков, то необходимо задать уникальные значения параметра sTag

Для справки:

  1. Размеры формы: высота 694, ширина 9345
  2. Основные элементы: lblStdEnum, fldUseStdEnum и fldStdEnum
  3. Отступы элементов от границы формы: по горизонтали 40, по вертикали 43
  4. Метка lblStdEnum расположена не стандартно: высота её увеличена до высоты формы и равна 694. Сделано это для того, чтобы в неё умещались две строки текста.
  5. Отступ поля fldStdEnum от левого края формы 3055
  6. Ширина поля fldStdEnum 6250
  7. Свойство Tag заполняется следующим образом: "Использовать_"+<Tag> и <Tag>
  8. Свойство LabelField заполняется следующим образом: "CCOrptBaseForm_StdEnum_Использовать_"+<Tag> и "CCOrptBaseForm_StdEnum_"+<Tag>

Настройка в справочнике

Разобрав процесс написания формы инициализации, отметим, что теперь ее достаточно выбрать в настройке создаваемого отчета (рис. 4).

FastDevReportOnRSReport 4.jpg

Рис. 4. Выбор макроса формы инициализации в настройке отчета.

Получение данных

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

Построение временного объекта, также как и его заполнение данными, происходит в серверном скрипте (а не в RSL-макросе - см. запрос #26464). Регистрация скрипта в системе и его выбор описан в !!!!!!!!.

Но все же отметим некоторые правила написания самого скрипта. За пример возьмем VBScript (его же и рекомендуется использовать).

Скрипт необходимо называть соответственно правилу ”COrptCompositionStep” + <номер отчета или имя отчета>.

Из скрипта будет вызываться функция <имя файла>+_Execute(pIn, pOut), например для получения данных в отчете 2216, вызывается функция:

Function COrptCompositionStep2216_Execute (pIn, pOut)
  …
  COrptCompositionStep2216_Execute = True
End Function

Строчка

  COrptCompositionStep2216_Execute = True

Говорит о том, что функция отработала корректно, и вставляется самым последним оператором. Приведем пример построения и заполнения временного объекта:

Dim sXML
sXML = "<Comment>Промежуточный Объект Ведомость остатков на дату</Comment>" & _
       "<Field Name = 'Идентификатор'                  Type = 'FT_Int32'   Flags = '0x1b' DBCode = 'ID'        />" & _
       "<Field Name = 'Наименование номенклатуры'      Type = 'FT_String'  Flags = '0x1'  DBCode = 'Nomen'   Size='"& SFS("Номенклатура","Наименование полное") &"' />" & _
       "<Field Name = 'Наименование единицы измерения' Type = 'FT_String'  Flags = '0x1'  DBCode = 'EdIzmer' Size='"& SFS("Единица измерения","Обозначение") &"' />" & _
       "<Field Name = 'Остаток по объему'              Type = 'FT_Decimal' Flags = '0x1'  DBCode = 'OstVolume' />" & _
       "<Field Name = 'Остаток по себестоимости'       Type = 'FT_Money'   Flags = '0x1'  DBCode = 'OstSebest' />" & _
       "<Field Name = 'Остаток по продажной стоимости' Type = 'FT_Money'   Flags = '0x1'  DBCode = 'OstCost'   />" 
 
Dim sObjName: sObjName = "OutObjectВедомость остатков на дату"
Dim sGUID   : sGUID    = "00000000-0000-FFFF-0001-000000002412"
Call g_dsRootTmp.Run("AddTmpChildObj", sObjName, "#rptFO2412", sXML, sGUID)

Т.е. в строковую переменную sXML записываем XML-описание структуры создаваемого объекта (размерность строковых полей определяем с помощью функции SFS), в переменную sObjName – имя объекта и в переменную sGUID – GUID (идентификатор) объекта. Причем в данном случае GUID сформирован по шаблону “00000000-0000-FFFF- + <номер объекта из 4-х символов> + - + <номер отчета из 12 символов>”, где символы только для цифры и A,B,C,D,E и F, т.е. числа в 16-ричном формате. Номер объекта используется в связи с тем, что для отчета может строиться несколько объектов.

И вызывая серверный метод AddTmpChildObj объекта Родитель временных объектов:

Call g_dsRootTmp.Run("AddTmpChildObj", sObjName, "#rptFO2412", sXML, sGUID)

мы создаем объект с именем sObjName, на временной таблице "#rptFO2412", со структурой sXML и идентификатором sGUID.

Это был этап создания объекта, теперь созданный объект необходимо заполнить данными. Делается это с помощью псевдо-SQL запроса. Мы называем запрос псевдо-SQL, т.к. в нем используются не имена таблиц и полей в них, а имена наших объектов и их полей.

Приведем пример построения псевдо-SQL запроса и разберем отдельные места.

Dim sQuery, sDate          
sDate = DateToSQL(pIn.Item("Дата"))
 
Dim sSQLCond 
 
sSQLCond = ""
 
sSQLCond = FilterCat(sSQLCond,MakeSQLCondition(pIn,"Номенклатура","ShotSpec.""Номенклатура по документу""" ,"Номенклатура",Empty),"AND")
 
sSQLCond = FilterCat(sSQLCond,MakeSQLCondition(pIn,"Организация",               "Card1.""Организация""",  "Организация",  Empty),"AND")
sSQLCond = FilterCat(sSQLCond,MakeSQLCondition(pIn,"Организационная структура", "Card1.""Подразделение""","Подразделение",Empty),"AND")
sSQLCond = FilterCat(sSQLCond,MakeSQLCondition(pIn,"Место хранения",            "Card1.""Склад""",        "Склад",        Empty),"AND")
sSQLCond = FilterCat(sSQLCond,MakeSQLCondition(pIn,"Сотрудник",                 "Card1.""МОЛ""",          "МОЛ",          Empty),"AND")
 
Dim tmp, sSourceCondition, sDestCondition
tmp = pIn.Item("Тип запаса")
if (TypeName(tmp) = "String") And (tmp <> vbNullString) Then
  sSQLCond = FilterCat(sSQLCond,"Card1.""Тип количества"" = '" & tmp & "' OR Card2.""Тип количества"" = '" & tmp & "'","AND")
  sSourceCondition  = "Spec.""Карточка источник"" IS NULL OR " & "Card2.""Тип количества"" <> '" & tmp & "'"
  sDestCondition    = "Spec.""Карточка приемник"" IS NULL OR " & "Card1.""Тип количества"" <> '" & tmp & "'"
else
  sSourceCondition  = "Spec.""Карточка источник"" IS NULL"
  sDestCondition    = "Spec.""Карточка приемник"" IS NULL"
end if
 
sQuery = "-- Отчет: Ведомость остатков на дату"                         & vbNewLine & _
"INSERT INTO """ & sObjName & """ "                                     & vbNewLine & _
" (""Наименование номенклатуры"", ""Наименование единицы измерения"", ""Остаток по объему"", "  & vbNewLine & _
"   ""Остаток по продажной стоимости"", ""Остаток по себестоимости"")"  & vbNewLine & _
"SELECT "                                       & vbNewLine & _
" Ware.""Наименование полное""      AS NomenName,"  & vbNewLine & _
" Unit.""Обозначение""              AS UnitName,"   & vbNewLine & _
" Itog.DestCount - Itog.SourceCount AS RestCount,"  & vbNewLine & _
" Itog.DestCost  - Itog.SourceCost  AS RestCost,"   & vbNewLine & _
" Itog.DestPrimeCost - Itog.SrcPrimeCost AS PrimeCost"  & vbNewLine & _
"FROM "                                   & vbNewLine & _
" ("                                      & vbNewLine & _
"   SELECT"                                         & vbNewLine & _
"     ShotSpec.""Номенклатура по документу""      AS WareID," & vbNewLine & _
"     ShotSpec.""Единица измерения по документу"" AS UnitID," & vbNewLine & _
"     SUM(CASE WHEN " & sSourceCondition                  & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Количество по документу"""            & vbNewLine & _
"     END) AS SourceCount,"                               & vbNewLine & _
"     SUM(CASE WHEN " & sSourceCondition                  & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Количество по документу""*Spec.""Продажная цена источника""" & vbNewLine & _
"     END) AS SourceCost,"                                & vbNewLine & _
"     SUM(CASE WHEN " & sSourceCondition                  & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Себестоимость"""                      & vbNewLine & _
"     END) AS SrcPrimeCost,"                              & vbNewLine & _
"     SUM(CASE WHEN " & sDestCondition                    & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Количество по документу"""            & vbNewLine & _
"     END) AS DestCount,"                                 & vbNewLine & _
"     SUM(CASE WHEN " & sDestCondition                    & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Количество по документу""*Spec.""Продажная цена приемника""" & vbNewLine & _
"     END) AS DestCost,"                                  & vbNewLine & _
"     SUM(CASE WHEN " & sDestCondition                    & vbNewLine & _
"       THEN 0"                                           & vbNewLine & _
"       ELSE Spec.""Себестоимость"""                      & vbNewLine & _
"     END) AS DestPrimeCost"                              & vbNewLine & _
"   FROM ""Сводная расшифровка спецификации"" Spec" & vbNewLine & _
"   INNER JOIN ""Сводная спецификация"" ShotSpec"                           & vbNewLine & _
"     ON Spec.""Ссылка на спецификацию"" = ShotSpec.""Идентификатор"""      & vbNewLine & _
"   INNER JOIN ""Товарный документ"" Doc"                                   & vbNewLine & _
"     ON Spec.""Ссылка на документ"" = Doc.""Идентификатор"""               & vbNewLine & _
"   LEFT JOIN ""Картотека складского учета"" Card1"                         & vbNewLine & _
"     ON Spec.""Карточка приемник"" = Card1.""Идентификатор"""              & vbNewLine & _
"   LEFT JOIN ""Картотека складского учета"" Card2"                         & vbNewLine & _
"     ON Spec.""Карточка источник"" = Card2.""Идентификатор"""              & vbNewLine & _
"   WHERE " & vbNewLine & _
"     ("    & vbNewLine & _
"       Doc.""Дата регистрации"" < " & sDate
 
If sSQLCond <> vbNullString Then
  sQuery = sQuery & " AND (" & sSQLCond & ")"
End If
 
sQuery =  sQuery  & vbNewLine & _
"     )"          & vbNewLine & _
"   GROUP BY ShotSpec.""Номенклатура по документу"", ShotSpec.""Единица измерения по документу"" " & vbNewLine & _
" ) AS Itog"      & vbNewLine & _
"INNER JOIN ""Номенклатура"" Ware"          & vbNewLine & _
" ON Itog.WareID = Ware.""Идентификатор"""  & vbNewLine & _
"INNER JOIN ""Единица измерения"" Unit"     & vbNewLine & _
" ON Itog.UnitID = Unit.""Идентификатор"""  & vbNewLine & _
"WHERE Itog.DestCount <> Itog.SourceCount"
 
Call RunQuery(sQuery)

Посмотрим на строку:

sDate = DateToSQL(pIn.Item("Дата"))

во-первых, мы берем значение параметра Дата, т.е. обратим внимание, что у нас есть набор входных параметров с формы инициализации (хотя сформированы они могут быть не обязательно на форме инициализации) – в нашем примере переменная pIn. Затем мы это значение, которое имеет тип ”Дата”, преобразовываем в строку, чтобы в дальнейшем использовать в запросе, но не как нам это удобно, а с помощью функции DateToSQL. Все дело в том, что дата в языке SQL записывается особым образом, кому интересно в MS SQL Server 2000 константа типа ”DateTime” в запросе будет выглядеть так:

{ ts '2017-09-28 00:00:00'}

Поэтому для удобства и используется специальная функция.

Теперь вспомним, что на формах инициализации используются стандартные блоки. И чтобы каждый раз самостоятельно не формировать строку условия (фильтр, подставляемый в раздел запроса WHERE) для нашего запроса, используется специальная функция MakeSQLCondition.

После построения строки псевдо-SQL запроса, запускаем его на выполнение:

Call RunQuery(sQuery)

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

pOut.Item("Выходной объект") = sObjName

После того, как серверный макрос отработает, из параметров, которые он вернет, будет взято имя объекта и создан сам объект. Ссылка на который будет помещена в список параметров тоже под именем “Выходной объект”, которые будут видны в печатной и экранной формах.

Отображение данных

Теперь рассмотрим отображение данных. Данные можно отображать как в экранных, так и в печатных формах. Экранная форма у отчета может быть только одна, хотя конечно ее можно менять, а вот печатных форм может быть сколько угодно.

Экранные формы

ViewFormChart1.JPG

Рис. 5.1 Пример экранной формы

В экранной форме есть возможность посмотреть диаграмму по соответствующей кнопке на панели.

ViewFormChart2.JPG

Рис. 5.2 Пример диаграммы

Параметры, используемые для построения диаграммы

Параметр Тип Назначение Примечание
Объект для отображения String Имя объекта для построения диаграммы Если не задан, используется "Выходной объект"

Если параметр "Выходной объект" тоже не задан, то кнопка вызова диаграммы скрывается с панели

Поля для отображения Array Массив отображаемых полей Если не задан, выводятся все не скрытые и не являющиеся ссылкой поля объекта

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

Для того чтобы добавить печатную форму в отчет необходимо в настройках отчета на закладке ”Формирование” добавить запись в грид ”Печатные формы”, дать название формы и указать макрос, который будет запускать форму (рис. 6).

FastDevReportOnRSReport Pict7.jpg

Рис. 6. Диалог настройки отчета, закладка ”Формирование”

Выбранный в настройках макрос отвечает за отображение печатной формы.

Из макроса печатной формы вызывается функция RunPrintForm:

// функция для вызова печатной формы отчета извне
macro RunPrintForm(_oInputParams, _bPreview)
  ... 
end;

где _oInputParams – параметры отчета, которые формируются ранее; _bPreview – режим предпросмотра.

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

  1. FastReport
  2. Excel

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

Стандарты

FastReport

Сейчас предпочтительно все печатные формы делать на FastReport. Работают такие печатные формы быстрее, есть экспорт во многие форматы – Excel, HTML, PDF… Все печатные формы, которые подразумевают большое количество страниц обязательно делать на FastReport.

Шаблон печатной формы строится в FastReport Designer (рис. 7). Для этого должна быть установлена FastReport Studio.

FastDevReportOnRSReport Pict8.jpg

Рис. 7. Внешний вид шаблона печатной формы в FastReport Desiner

При разработке самого шаблона необходимо руководствоваться документом !!!!!!!!!FastReportStudioUserManual(RU).pdf.

Здесь будут описаны только основные моменты.

Шаблон

Первое, что необходимо сделать, это создать подключение во вновь созданном шаблоне печатной формы. Для этого необходимо перейти на закладку ”Данные” (рис. 8).

Теперь на панели элементов необходимо выбрать элемент ”База данных ADO” (ADODatabase) и добавить в отчет. На рисунке это элемент ”ADODatabase1”.

FastDevReportOnRSReport Pict9.jpg

Рис. 8. Окно Desiner-а с выбранной закладкой ”Данные”

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

FastDevReportOnRSReport Pict10.jpg

Рис. 9. Окно свойств элемента ”ADODatabase”

Все, что требуется – это выбрать базу данных. На рис. 10 показан выбор поставщика данных, необходимо выбрать “OLE DB Provider for RS-Balance 3 Aplication Server”.

На закладке “Подключение” все поля оставить по умолчанию (рис. 11).

FastDevReportOnRSReport Pict11.jpg

Рис. 10. Окно выбора базы данных, закладка ”Поставщик данных”

FastDevReportOnRSReport Pict12.jpg

Рис. 11. Окно выбора базы данных, закладка ”Подключение”

При дальнейшем создании шаблона, а именно при формировании страницы, можно руководствоваться документом !!!!!!!!! FastReportStudioUserManual(RU).pdf.

ADOQuery

Внимание!

Раньше мы использовали элемент ”Таблица ADO” (ADOTable) и в качестве базы данных указывали добавленный элемент ADODatabase. А в качестве имени таблицы (свойство TableName) - имя объекта, данные которого будем выводить в таблицу. Теперь найдена возможность, использовать ADOQuery, вместо ADOTable.

FastDevReportOnRSReport Pict13.jpg

Рис. 12. Элемент "ADOQuery"

Главное преимущество использования ADOQuery - возможность работы со ссылками. Для этого необходимо вместо SQL запроса передать значение ConnectString, аналогичное нашим объектам, например:

<object all_fields = "no" all_subobjects = "no" rec_count = "100">
  <name>Отчет 2412 - Выходной объект</name>
  <field>Вес</field>  
  <field>Группа</field>  
  <field>Ид_Группа</field>  
  <field>Количество</field>
  <classifier tree = "no">
    <name>Номенклатура</name>
    <field>Артикул</field>
    <field>Код</field>
    <classifier tree = "no">
      <name>Единица измерения</name>
      <field>Обозначение</field>          
    </classifier>                
    <field>Наименование краткое</field>
    <field>Наименование полное</field>        
  </classifier>  
  <field>Объем</field>
  <field>Себестоимость</field>
  <field>Стоимость в ценах прайс-листа</field>
  <field>Цена по прайс-листу</field>
</object>

Как всё это дело работает можно посмотреть в файле COrptPrintForm2412.fr3, добавленном по запросу #26993.

Также существует упрощенный формат для указания набора необходимых полей и классификаторов. В общем виде формат выглядит так:

list
<имя объекта>
<имя поля>
...
<имя поля>

Пример:

list
Отчет 2412 - Выходной объект
Вес
Группа
Ид_Группа
Количество
Номенклатура\Артикул
Номенклатура\Код
Номенклатура\Единица измерения\Обозначение
Номенклатура\Наименование краткое
Номенклатура\Наименование полное
Объем
Себестоимость
Стоимость в ценах прайс-листа
Цена по прайс-листу
Макрос

Теперь рассмотрим сам макрос для печатной формы.

cpwin;
import COrptFR;
 
class (CFlexRepPrintFormFR) CCOrptPrintFormPackingIn_BP ()
  InitCFlexRepPrintFormFR();
 
  macro SetTemplate ()
    this.CreateObjFR("COrptPrintFormPackingIn_BP.fr3");
  end;
 
  macro SetVariables ()
    SetVariables();
 
    SetVariable("Отгрузка", false);
    SetVariable("Организация", StdElemToString("Организация", "Организация", "Наименование краткое"));
    SetVariable("Подразделение", StdElemToString("Подразделение", "Организационная структура", "Наименование краткое"));
    SetVariable("Склад", StdElemToString("Склад", "Место хранения", "Наименование краткое"));
    SetVariable("МОЛ", StdElemToString("МОЛ", "Сотрудник", "Наименование краткое"));
    SetVariable("Внешняя организация", StdElemToString("Внешняя организация", "Организация", "Наименование краткое"));
  end;
end;

Класс печатной формы FastReport должен наследоваться от класса CFlexRepPrintFormFR, который описан в файле COrptFR.mac. Поэтому необходимо сделать импорт модуля COrptFR.

import COrptFR;

В методе SetTemplate указывается какой шаблон используется:

this.CreateObjFR("COrptPrintFormPackingIn_BP.fr3");

Затем устанавливаются значения переменных шаблона. В основном, это параметры с формы инициализации. Значения переменных можно задавать напрямую вызывая метод SetVariable(<Имя переменной>, <Значение переменной>).

SetVariable("Отгрузка", false);

Значения заданные на форме инициализации в стандартных элементах проще устанавливать используя метод StdElemToString(<Имя объекта>, <Имя параметра ФИ>, <Имя поля объекта>). Например:

SetVariable("Склад", StdElemToString("Склад", "Место хранения", "Наименование краткое"));

Excel

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

Личные инструменты
Пространства имён
Варианты
Действия
Навигация
Для разработки
Инструменты