create or replace package UDO_PKG_EQUIPTCF as /* Формирование дерева состава оборудования */ procedure EQCONFIG_HIER ( NEQPARENT in number, -- Рег. номер родительского узла состава оборудования COUT out clob -- Сериализованное XML-представление дерева ); /* Условия отбора технических объектов */ procedure EQCONFIG_THOBJ_LIST_COND; /* Формирование списка технических объектов для выбранного узла состава оборудования */ procedure EQCONFIG_THOBJ_LIST ( NEQPARENT in number, -- Рег. номер родительского узла состава оборудования NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0) NPAGE_SIZE in number, -- Количество записей на странице (0 - все) CFILTERS in clob, -- Фильтры CORDERS in clob, -- Сортировки NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ COUT out clob -- Сериализованная таблица данных ); /* Получение даты следующего технического обслуживания технического объекта */ function EQCONFIG_THOBJ_GET_NXTEQTCHSRV ( NEQCONFIG in number, -- Рег. номер технического объекта NSTATE in number := null -- Состояние (null - любое) ) return date; -- Дата следующего технического обслуживания /* Выбор графиков технического обслуживания и ремонта технического объекта */ procedure EQCONFIG_THOBJ_SELECT_EQTCHSRV ( NEQTCHSRV in number := null, -- Рег. номер графика ТО и ремонтов (null - любой) NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) NSTATE in number := null, -- Состояние (null - любое) NIDENT out number -- Идентификатор списка ); /* Получение даты следующего ремонта по ремонтной ведомости технического объекта */ function EQCONFIG_THOBJ_GET_NXTEQRPSHT ( NEQCONFIG in number, -- Рег. номер технического объекта NSTATE in number := null -- Состояние (null - любое) ) return date; -- Дата следующего ремонта по ведомости /* Выбор ремонтных ведомостей технического объекта */ procedure EQCONFIG_THOBJ_SELECT_EQRPSHT ( NEQRPSHEETS in number := null, -- Рег. номер ремонтной ведосочти (null - любой) NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) NSTATE in number := null, -- Состояние (null - любое) NIDENT out number -- Идентификатор списка ); /* Получение даты следующего ремонта по ремонтной ведомости или графику ТО и ремонтов (что раньше) технического объекта */ function EQCONFIG_THOBJ_GEN_NXTRPR ( NEQCONFIG in number -- Рег. номер технического объекта ) return date; -- Дата ближайшего ремонта /* Формирование карточки технического объекта */ procedure EQCONFIG_THOBJ_CARD ( NEQCONFIG in number, -- Рег. номер технического объекта COUT out clob -- Сериализованная карточка ); /* Подчистка буферов после исполнения запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_BCLR ( NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number -- Идентификатор буфера описания запроса ); /* Подготовка запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_PRLG ( NEQUIPDSCMML in number, -- Рег. номер модели NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number, -- Идентификатор буфера описания запроса SURL out varchar2, -- Адрес для запроса SAUTH_TOKEN out varchar2, -- Токен аутентификации для запроса SDATASET_ID out varchar2, -- Идентификатор выборки данных запроса CDATASET_CONFIG out clob, -- Описание данных о наработках SDATASET_URL out varchar2, -- Адрес для получения данных о наработках SCLASS_MACHINE out varchar2, -- Код класса оборудования для запроса STASK out varchar2 -- Задача для запроса (см. константы UDO_PKG_EQUIPDS_BASE.SCMML_TASK_*) ); /* Финализация исполнения запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_EPLG ( NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number, -- Идентификатор буфера описания запроса NEQCONFIG in number := null, -- Рег. номер технического объекта NEQUIPDSCMML in number := null, -- Рег. номер модели CFORECAST in clob := null -- Данные прогноза ); /* Вероятность выхода единицы оборудования из строя с учётом графика ТО и ремонтов и RUL-прогноза */ function EQCONFIG_THOBJ_TCHSRV_BRKDPROB ( NEQCONFIG in number -- Рег. номер технического объекта ) return number; -- Вероятность выхода из строя /* Модификация графика ТО и ремонтов для технического объекта */ procedure EQCONFIG_THOBJ_CHNG_EQTCHSRV ( NEQCONFIG in number, -- Рег. номер технического объекта NEQTCHSRV in number, -- Рег. номер графика ТО и ремонтов DPLANDATE_FROM in date -- Уточнённая плановая дата начала ремонта ); /* Формирование ремонтной ведомости для технического объекта */ procedure EQCONFIG_THOBJ_MAKE_EQRPSHEET ( NEQCONFIG in number, -- Рег. номер технического объекта SACATALOG in varchar2, -- Каталог размещения ведомости SEQTECSRVKIND in varchar2, -- Вид ремонта DPLANDATE_FROM in date, -- Плановая дата начала ремонта NIDENT out number -- Идентификатор списка сформированных ведомостей ); end UDO_PKG_EQUIPTCF; / create or replace package body UDO_PKG_EQUIPTCF as /* TODO: owner="root" created="02.08.2024" text="Проверка прав доступа при формировании таблицы и карточки ТО" */ /* Константы - адреса API фреймворка прогнозирования */ SFW_API_ROOT constant PKG_STD.TSTRING := '/API'; -- Корень API SFW_API_FORECAST constant PKG_STD.TSTRING := '/forecast/metadata'; -- Адрес функции прогнозирования (относительно корня) /* Формирование ветки дерева состава оборудования */ function EQCONFIG_HIER_NODE ( NCUR in integer, -- Курсор документа для результата NCOMPANY in number, -- Рег. номер организации NEQPARENT in number -- Рег. номер родительского узла состава оборудования ) return PKG_XMAKE.TNODE -- XML-описание веток дерева is XLEAF PKG_XMAKE.TNODE; -- Текущий лист XCHILD PKG_XMAKE.TNODE; -- Дочерние листы текущего XRES PKG_XMAKE.TNODE; -- Буфер для результата begin /* Обходим состав оборудования с заданного корня */ for C in (select M.RN NRN, M.EQPARENT NHRN, DECODE(M.FICT_REC, 0, M.NAME, DECODE(OL.RN, null, M.NAME, OL.NAME)) SNAME, case when exists (select null from EQCONFIG C where C.EQPARENT = M.RN and exists (select null from V_USERPRIV_HIER_SINGL UP where UP.HIERARCHY = C.RN)) then 1 else 0 end NHASCHILDREN, M.OBJ_KIND NOBJ_KIND from EQCONFIG M, EQOBJLEVEL OL where M.PR_OBJ_LEVEL = OL.RN(+) and ((M.FICT_REC = 0) or ((M.FICT_REC = 1) and (CMP_VC2(M.NAME, F_EQCONFIG_EXTRANAME(0)) = 1))) and exists (select null from V_USERPRIV_HIER_SINGL UP where UP.HIERARCHY = M.RN) and COALESCE(M.EQPARENT, 0) = NEQPARENT and M.COMPANY = NCOMPANY order by 3) loop /* Если есть дочерние ветки */ if (C.NHASCHILDREN = 1) then /* Добавим фиктивную дочернюю запись для индикации наличия дочерних на клиенте */ XCHILD := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'children', RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'id', SVALUE => C.NRN || '_loader'), RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'label', SVALUE => 'Минуточку...'))); /* Соберём лист */ XLEAF := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'children', RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'id', SVALUE => C.NRN), RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'label', SVALUE => C.SNAME)), RNODE00 => XCHILD); /* Соберём листы в ветку */ XRES := PKG_XMAKE.CONCAT(ICURSOR => NCUR, RNODE00 => XRES, RNODE01 => XLEAF); end if; end loop; /* Вернём собранное */ return XRES; end EQCONFIG_HIER_NODE; /* Формирование дерева состава оборудования */ procedure EQCONFIG_HIER ( NEQPARENT in number, -- Рег. номер родительского узла состава оборудования COUT out clob -- Сериализованное XML-представление дерева ) is NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Рег. номер организации NCUR integer; -- Курсор документа для результата XDOC PKG_XMAKE.TNODE; -- Документ для результата begin /* Открываем документ */ NCUR := PKG_XMAKE.OPEN_CURSOR(); /* Формируем XML-представление ветки для запрошенного родителя */ XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => EQCONFIG_HIER_NODE(NCUR => NCUR, NCOMPANY => NCOMPANY, NEQPARENT => NEQPARENT)); /* Конвертируем в CLOB */ COUT := PKG_XMAKE.SERIALIZE_TO_CLOB(ICURSOR => NCUR, ITYPE => PKG_XMAKE.CONTENT_, RNODE => XDOC, RHEADER => PKG_XHEADER.WRAP_ALL(SVERSION => PKG_XHEADER.VERSION_1_0_, SENCODING => PKG_XHEADER.ENCODING_UTF_, SSTANDALONE => PKG_XHEADER.STANDALONE_YES_)); /* Закрываем документ */ PKG_XMAKE.CLOSE_CURSOR(ICURSOR => NCUR); end EQCONFIG_HIER; /* Условия отбора технических объектов */ procedure EQCONFIG_THOBJ_LIST_COND is begin /* Установка главной таблицы */ PKG_COND_BROKER.SET_TABLE(STABLE_NAME => 'EQCONFIG'); /* Обозначение */ PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'CODE', SCONDITION_NAME => 'SCODEFrom'); /* Наименование */ PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'NAME', SCONDITION_NAME => 'SNAMEFrom'); /* Дата ввода в эксплуатацию */ PKG_COND_BROKER.ADD_CONDITION_BETWEEN(SCOLUMN_NAME => 'OPER_DATE', SCONDITION_NAME_FROM => 'DOPER_DATEFrom', SCONDITION_NAME_TO => 'DOPER_DATETo'); /* Состояние */ PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'CODE', SCONDITION_NAME => 'SUSE_KINDFrom', SJOINS => 'HLSTATETYPES <- RN;HLSTATETYPES'); /* Класс */ PKG_COND_BROKER.ADD_CONDITION_CODE(SCOLUMN_NAME => 'NAME', SCONDITION_NAME => 'SOBJ_KINDFrom', SJOINS => 'OBJ_KIND <- RN;EQOBJKIND'); /* Действия с моделями прогнозирования */ if (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NCMML_STATUSFrom') = 1) then PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_STATUS_BY_EQCONFIG') || '(RN) = :NCMML_STATUS'); PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NCMML_STATUS', SVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NCMML_STATUSFrom')); end if; /* Вероятность выхода из строя */ if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 1) and (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 0)) then PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || '(RN) >= :NBREAKDOWN_PROBFrom'); PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBFrom', NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom')); end if; if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 1) and (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 0)) then PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || '(RN) <= :NBREAKDOWN_PROBTo'); PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBTo', NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBTo')); end if; if ((PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom') = 1) and (PKG_COND_BROKER.CONDITION_EXISTS(SCONDITION_NAME => 'NBREAKDOWN_PROBTo') = 1)) then PKG_COND_BROKER.ADD_CLAUSE(SCLAUSE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || '(RN) between :NBREAKDOWN_PROBFrom and :NBREAKDOWN_PROBTo'); PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBFrom', NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBFrom')); PKG_COND_BROKER.BIND_VARIABLE(SVARIABLE_NAME => 'NBREAKDOWN_PROBTo', NVALUE => PKG_COND_BROKER.GET_CONDITION_NUM(SCONDITION_NAME => 'NBREAKDOWN_PROBTo')); end if; end EQCONFIG_THOBJ_LIST_COND; /* Формирование списка технических объектов для выбранного узла состава оборудования */ procedure EQCONFIG_THOBJ_LIST ( NEQPARENT in number, -- Рег. номер родительского узла состава оборудования NPAGE_NUMBER in number, -- Номер страницы (игнорируется при NPAGE_SIZE=0) NPAGE_SIZE in number, -- Количество записей на странице (0 - все) CFILTERS in clob, -- Фильтры CORDERS in clob, -- Сортировки NINCLUDE_DEF in number, -- Признак включения описания колонок таблицы в ответ COUT out clob -- Сериализованная таблица данных ) is NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Организация сеанса NIDENT PKG_STD.TREF := GEN_IDENT(); -- Идентификатор отбора RF PKG_P8PANELS_VISUAL.TDG_FILTERS; -- Фильтры RO PKG_P8PANELS_VISUAL.TDG_ORDERS; -- Сортировки RDG PKG_P8PANELS_VISUAL.TDG; -- Описание таблицы RDG_ROW PKG_P8PANELS_VISUAL.TDG_ROW; -- Строка таблицы RCOL_VALS PKG_P8PANELS_VISUAL.TDG_COL_VALS; -- Предопределённые значения столбцов NROW_FROM PKG_STD.TREF; -- Номер строки с NROW_TO PKG_STD.TREF; -- Номер строки по CSQL clob; -- Буфер для запроса ICURSOR integer; -- Курсор для исполнения запроса NBREAKDOWN_PROB PKG_STD.TNUMBER; -- Вероятность выхода единицы оборудования из строя begin /* Читаем фильтры */ RF := PKG_P8PANELS_VISUAL.TDG_FILTERS_FROM_XML(CFILTERS => CFILTERS); /* Читаем сортировки */ RO := PKG_P8PANELS_VISUAL.TDG_ORDERS_FROM_XML(CORDERS => CORDERS); /* Преобразуем номер и размер страницы в номер строк с и по */ PKG_P8PANELS_VISUAL.UTL_ROWS_LIMITS_CALC(NPAGE_NUMBER => NPAGE_NUMBER, NPAGE_SIZE => NPAGE_SIZE, NROW_FROM => NROW_FROM, NROW_TO => NROW_TO); /* Инициализируем таблицу данных */ RDG := PKG_P8PANELS_VISUAL.TDG_MAKE(); /* Добавляем в таблицу описание колонок */ PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'NRN', SCAPTION => 'Рег. номер', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, BVISIBLE => false); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SCODE', SCAPTION => 'Обозначение', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BORDER => true, BFILTER => true); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SNAME', SCAPTION => 'Наименование', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BORDER => true, BFILTER => true); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'DOPER_DATE', SCAPTION => 'Дата ввода в эксплуатацию', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_DATE, BORDER => true, BFILTER => true); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SUSE_KIND', SCAPTION => 'Состояние', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BORDER => true, BFILTER => true); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'NOBJ_KIND', SCAPTION => 'Рег. номер класса технического объекта', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, BVISIBLE => false); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SOBJ_KIND', SCAPTION => 'Класс', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BORDER => true, BFILTER => true); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SOBJ_KIND_FULL_CODE', SCAPTION => 'Класс (полный иерархический код)', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BVISIBLE => false); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SUMEAS_RES', SCAPTION => 'Единица измерения ресурса', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BVISIBLE => false); PKG_P8PANELS_VISUAL.TDG_COL_VALS_ADD(RCOL_VALS => RCOL_VALS, NVALUE => 0, BCLEAR => true); PKG_P8PANELS_VISUAL.TDG_COL_VALS_ADD(RCOL_VALS => RCOL_VALS, NVALUE => 1); PKG_P8PANELS_VISUAL.TDG_COL_VALS_ADD(RCOL_VALS => RCOL_VALS, NVALUE => 2); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'NCMML_STATUS', SCAPTION => 'Модель', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, BORDER => true, BFILTER => true, RCOL_VALS => RCOL_VALS); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'NBREAKDOWN_PROB', SCAPTION => 'Вероятность выхода из строя', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_NUMB, BORDER => true, BFILTER => true, SHINT => UDO_PKG_EQUIPDS.CMMLH_FORECAST_COLOR(NMODE => 0)); PKG_P8PANELS_VISUAL.TDG_ADD_COL_DEF(RDATA_GRID => RDG, SNAME => 'SBREAKDOWN_PROB_COLOR', SCAPTION => 'Цвет вероятности выхода из строя', SDATA_TYPE => PKG_P8PANELS_VISUAL.SDATA_TYPE_STR, BVISIBLE => false); /* Обходим данные */ begin /* Добавляем подсказку совместимости */ CSQL := PKG_SQL_BUILD.COMPATIBLE(SSQL => CSQL); /* Формируем запрос */ PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => 'select *'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select D.*,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.SQLROWNUM() || ' NROW'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from (select C.RN NRN,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.CODE SCODE,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C."NAME" SNAME,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OPER_DATE DOPER_DATE,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' ST.CODE SUSE_KIND,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' C.OBJ_KIND NOBJ_KIND,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' OK.NAME SOBJ_KIND,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' FORMAT_HIER_NAME(OK.COMPANY, null, OK.FULLCODE) SOBJ_KIND_FULL_CODE,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' DM.MEAS_MNEMO SUMEAS_RES,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPDS.CMML_STATUS_BY_EQCONFIG') || '(C.RN) NCMML_STATUS,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_TCHSRV_BRKDPROB') || '(C.RN) NBREAKDOWN_PROB'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' from EQCONFIG C'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' left outer join HLSTATETYPES ST on C.HLSTATETYPES = ST.RN'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' left outer join DICMUNTS DM on C.UMEAS_RES = DM.RN,'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' EQOBJKIND OK'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where C.EQPARENT = :NEQPARENT'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and C.OBJ_KIND = OK.RN'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' and C.RN in (select ID from COND_BROKER_IDSMART where IDENT = :NIDENT) %ORDER_BY%) D) F'); PKG_SQL_BUILD.APPEND(SSQL => CSQL, SELEMENT1 => ' where F.NROW between :NROW_FROM and :NROW_TO'); /* Учтём сортировки */ PKG_P8PANELS_VISUAL.TDG_ORDERS_SET_QUERY(RDATA_GRID => RDG, RORDERS => RO, SPATTERN => '%ORDER_BY%', CSQL => CSQL); /* Учтём фильтры */ PKG_P8PANELS_VISUAL.TDG_FILTERS_SET_QUERY(NIDENT => NIDENT, NCOMPANY => NCOMPANY, SUNIT => 'EquipConfiguration', SPROCEDURE => PKG_SQL_BUILD.PKG_NAME(SNAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_LIST_COND'), RDATA_GRID => RDG, RFILTERS => RF); /* Разбираем его */ ICURSOR := PKG_SQL_DML.OPEN_CURSOR(SWHAT => 'SELECT'); PKG_SQL_DML.PARSE(ICURSOR => ICURSOR, SQUERY => CSQL); /* Делаем подстановку параметров */ PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NEQPARENT', NVALUE => NEQPARENT); PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NIDENT', NVALUE => NIDENT); PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_FROM', NVALUE => NROW_FROM); PKG_SQL_DML.BIND_VARIABLE_NUM(ICURSOR => ICURSOR, SNAME => 'NROW_TO', NVALUE => NROW_TO); /* Описываем структуру записи курсора */ PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 1); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 2); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 3); PKG_SQL_DML.DEFINE_COLUMN_DATE(ICURSOR => ICURSOR, IPOSITION => 4); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 5); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 6); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 7); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 8); PKG_SQL_DML.DEFINE_COLUMN_STR(ICURSOR => ICURSOR, IPOSITION => 9); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 10); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 11); PKG_SQL_DML.DEFINE_COLUMN_NUM(ICURSOR => ICURSOR, IPOSITION => 12); /* Делаем выборку */ if (PKG_SQL_DML.EXECUTE(ICURSOR => ICURSOR) = 0) then null; end if; /* Обходим выбранные записи */ while (PKG_SQL_DML.FETCH_ROWS(ICURSOR => ICURSOR) > 0) loop /* Добавляем колонки с данными */ PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLN(RROW => RDG_ROW, SNAME => 'NRN', ICURSOR => ICURSOR, NPOSITION => 1, BCLEAR => true); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SCODE', ICURSOR => ICURSOR, NPOSITION => 2); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SNAME', ICURSOR => ICURSOR, NPOSITION => 3); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLD(RROW => RDG_ROW, SNAME => 'DOPER_DATE', ICURSOR => ICURSOR, NPOSITION => 4); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SUSE_KIND', ICURSOR => ICURSOR, NPOSITION => 5); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLN(RROW => RDG_ROW, SNAME => 'NOBJ_KIND', ICURSOR => ICURSOR, NPOSITION => 6); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SOBJ_KIND', ICURSOR => ICURSOR, NPOSITION => 7); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SOBJ_KIND_FULL_CODE', ICURSOR => ICURSOR, NPOSITION => 8); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLS(RROW => RDG_ROW, SNAME => 'SUMEAS_RES', ICURSOR => ICURSOR, NPOSITION => 9); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_CUR_COLN(RROW => RDG_ROW, SNAME => 'NCMML_STATUS', ICURSOR => ICURSOR, NPOSITION => 10); PKG_SQL_DML.COLUMN_VALUE_NUM(ICURSOR => ICURSOR, IPOSITION => 11, NVALUE => NBREAKDOWN_PROB); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'NBREAKDOWN_PROB', NVALUE => NBREAKDOWN_PROB); PKG_P8PANELS_VISUAL.TDG_ROW_ADD_COL(RROW => RDG_ROW, SNAME => 'SBREAKDOWN_PROB_COLOR', SVALUE => UDO_PKG_EQUIPDS.CMMLH_FORECAST_COLOR(NMODE => 1, NVALUE => NBREAKDOWN_PROB)); /* Добавляем строку в таблицу */ PKG_P8PANELS_VISUAL.TDG_ADD_ROW(RDATA_GRID => RDG, RROW => RDG_ROW); end loop; /* Освобождаем курсор */ PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR); exception when others then PKG_SQL_DML.CLOSE_CURSOR(ICURSOR => ICURSOR); raise; end; /* Сериализуем описание */ COUT := PKG_P8PANELS_VISUAL.TDG_TO_XML(RDATA_GRID => RDG, NINCLUDE_DEF => NINCLUDE_DEF); end EQCONFIG_THOBJ_LIST; /* Получение даты следующего технического обслуживания технического объекта */ function EQCONFIG_THOBJ_GET_NXTEQTCHSRV ( NEQCONFIG in number, -- Рег. номер технического объекта NSTATE in number := null -- Состояние (null - любое) ) return date -- Дата следующего технического обслуживания is DRES PKG_STD.TLDATE; -- Буфер для результата begin /* Найдем график ТО и ремонтов, в заданном состоянии, с минимальной датой по данному тех. объекту */ select min(T.DATEPRD_BEG) into DRES from EQTCHSRV T where T.EQCONFIG_TECH = NEQCONFIG and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE))) and T.DATEPRD_BEG >= sysdate; /* Вернём результат */ return DRES; exception when others then return null; end EQCONFIG_THOBJ_GET_NXTEQTCHSRV; /* Выбор графиков технического обслуживания и ремонта технического объекта */ procedure EQCONFIG_THOBJ_SELECT_EQTCHSRV ( NEQTCHSRV in number := null, -- Рег. номер графика ТО и ремонтов (null - любой) NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) NSTATE in number := null, -- Состояние (null - любое) NIDENT out number -- Идентификатор списка ) is NTMP PKG_STD.TREF; -- Рег. номер записи буфера отобранных begin /* Обходим графики по тех. объекту */ for C in (select T.RN from EQTCHSRV T where ((NEQTCHSRV is null) or ((NEQTCHSRV is not null) and (T.RN = NEQTCHSRV))) and ((NEQCONFIG is null) or ((NEQCONFIG is not null) and (T.EQCONFIG_TECH = NEQCONFIG))) and ((NEQTCHSRV is not null) or ((NEQTCHSRV is null) and (T.DATEPRD_BEG >= sysdate))) and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE)))) loop /* Формируем идентификатор списка если необходимо */ if (NIDENT is null) then NIDENT := GEN_IDENT(); end if; /* Добавляем отобранное в список */ P_SELECTLIST_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, SUNITCODE => 'EquipTechServices', NRN => NTMP); end loop; end EQCONFIG_THOBJ_SELECT_EQTCHSRV; /* Получение даты следующего ремонта по ремонтной ведомости технического объекта */ function EQCONFIG_THOBJ_GET_NXTEQRPSHT ( NEQCONFIG in number, -- Рег. номер технического объекта NSTATE in number := null -- Состояние (null - любое) ) return date -- Дата следующего ремонта по ведомости is DRES PKG_STD.TLDATE; -- Буфер для результата begin /* Найдем график ТО и ремонтов, в заданном состоянии, с минимальной датой по данному тех. объекту */ select min(T.DATEPLAN_BEG) into DRES from EQRPSHEETS T where T.EQCONFIG = NEQCONFIG and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE))) and T.DATEPLAN_BEG >= sysdate; /* Вернём результат */ return DRES; exception when others then return null; end EQCONFIG_THOBJ_GET_NXTEQRPSHT; /* Выбор ремонтных ведомостей технического объекта */ procedure EQCONFIG_THOBJ_SELECT_EQRPSHT ( NEQRPSHEETS in number := null, -- Рег. номер ремонтной ведосочти (null - любой) NEQCONFIG in number := null, -- Рег. номер технического объекта (null - любой) NSTATE in number := null, -- Состояние (null - любое) NIDENT out number -- Идентификатор списка ) is NTMP PKG_STD.TREF; -- Рег. номер записи буфера отобранных begin /* Обходим графики по тех. объекту */ for C in (select T.RN from EQRPSHEETS T where ((NEQRPSHEETS is null) or ((NEQRPSHEETS is not null) and (T.RN = NEQRPSHEETS))) and ((NEQCONFIG is null) or ((NEQCONFIG is not null) and (T.EQCONFIG = NEQCONFIG))) and ((NEQRPSHEETS is not null) or ((NEQRPSHEETS is null) and (T.DATEPLAN_BEG >= sysdate))) and ((NSTATE is null) or ((NSTATE is not null) and (T.STATE = NSTATE)))) loop /* Формируем идентификатор списка если необходимо */ if (NIDENT is null) then NIDENT := GEN_IDENT(); end if; /* Добавляем отобранное в список */ P_SELECTLIST_INSERT(NIDENT => NIDENT, NDOCUMENT => C.RN, SUNITCODE => 'EquipRepairSheets', NRN => NTMP); end loop; end EQCONFIG_THOBJ_SELECT_EQRPSHT; /* Получение даты следующего ремонта по ремонтной ведомости или графику ТО и ремонтов (что раньше) технического объекта */ function EQCONFIG_THOBJ_GEN_NXTRPR ( NEQCONFIG in number -- Рег. номер технического объекта ) return date -- Дата ближайшего ремонта is DNXTEQTCHSRV PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта по графику DNXTEQRPSHT PKG_STD.TLDATE; -- Дата ближайшего ТО или ремонта по ремонтным ведомостям DRES PKG_STD.TLDATE; -- Буфер для результата begin /* Определим дату ближайшего ТО или ремонта */ DNXTEQTCHSRV := EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => NEQCONFIG); /* Определим дату ближайшей ремонтной ведомости */ DNXTEQRPSHT := EQCONFIG_THOBJ_GET_NXTEQRPSHT(NEQCONFIG => NEQCONFIG); /* Берм меньшую */ if ((DNXTEQRPSHT is not null) and (DNXTEQTCHSRV is not null)) then if (DNXTEQRPSHT < DNXTEQTCHSRV) then DRES := DNXTEQRPSHT; else DRES := DNXTEQTCHSRV; end if; else DRES := COALESCE(DNXTEQTCHSRV, DNXTEQRPSHT); end if; /* Вернём результат */ return DRES; end EQCONFIG_THOBJ_GEN_NXTRPR; /* Формирование карточки технического объекта */ procedure EQCONFIG_THOBJ_CARD ( NEQCONFIG in number, -- Рег. номер технического объекта COUT out clob -- Сериализованная карточка ) is NCUR integer; -- Курсор документа для результата XDOC PKG_XMAKE.TNODE; -- Документ для результата XCARD PKG_XMAKE.TNODE; -- XML-карточка begin /* Открываем документ */ NCUR := PKG_XMAKE.OPEN_CURSOR(); /* Обратимся к данным технического объекта */ for C in (select T.RN NRN, T.CODE SCODE, T.NAME SNAME, T.OPER_DATE DOPER_DATE, OK.NAME SEQOBJKIND from EQCONFIG T, EQOBJKIND OK where T.RN = NEQCONFIG and T.OBJ_KIND = OK.RN) loop /* Соберем карточку */ XCARD := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'techObj', RATTRIBUTES => PKG_XMAKE.ATTRIBUTES(ICURSOR => NCUR, RATTRIBUTE00 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'NRN', NVALUE => C.NRN), RATTRIBUTE01 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'SCODE', SVALUE => C.SCODE), RATTRIBUTE02 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'SNAME', SVALUE => C.SNAME), RATTRIBUTE03 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'DOPER_DATE', DVALUE => C.DOPER_DATE), RATTRIBUTE04 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'DNEXT_EQTCHSRV', SVALUE => TO_CHAR(EQCONFIG_THOBJ_GET_NXTEQTCHSRV(NEQCONFIG => C.NRN), 'dd.mm.yyyy hh24:mi:ss')), RATTRIBUTE05 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'DNEXT_EQRPSHEET', SVALUE => TO_CHAR(EQCONFIG_THOBJ_GET_NXTEQRPSHT(NEQCONFIG => C.NRN), 'dd.mm.yyyy hh24:mi:ss')), RATTRIBUTE06 => PKG_XMAKE.ATTRIBUTE(ICURSOR => NCUR, SNAME => 'SEQOBJKIND', SVALUE => C.SEQOBJKIND))); end loop; /* Формируем XML-представление документа ответа */ XDOC := PKG_XMAKE.ELEMENT(ICURSOR => NCUR, SNAME => 'XDATA', RNODE00 => XCARD); /* Сериализуем документ */ COUT := PKG_XMAKE.SERIALIZE_TO_CLOB(ICURSOR => NCUR, ITYPE => PKG_XMAKE.CONTENT_, RNODE => XDOC, RHEADER => PKG_XHEADER.WRAP_ALL(SVERSION => PKG_XHEADER.VERSION_1_0_, SENCODING => PKG_XHEADER.ENCODING_UTF_, SSTANDALONE => PKG_XHEADER.STANDALONE_YES_)); /* Закрываем документ */ PKG_XMAKE.CLOSE_CURSOR(ICURSOR => NCUR); end EQCONFIG_THOBJ_CARD; /* Подчистка буферов после исполнения запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_BCLR ( NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number -- Идентификатор буфера описания запроса ) is begin /* Очистим данные в файловом буфере */ P_FILE_BUFFER_CLEAR(NIDENT => NDATASET_IDENT); P_FILE_BUFFER_CLEAR(NIDENT => NDATASET_CONFIG_IDENT); P_FILE_BUFFER_CLEAR(NIDENT => NREQUEST_CONFIG_IDENT); end EQCONFIG_THOBJ_FORECAST_BCLR; /* Подчистка буферов после исполнения запроса на формирование прогноза технического объекта (в автономной транзакции) */ procedure EQCONFIG_THOBJ_FORECAST_BCLRAT ( NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number -- Идентификатор буфера описания запроса ) is RPROC_PARAMS PKG_CONTPRMLOC.TCONTAINER; -- Параметры процедуры begin /* Очищаем контейнер с параметрами */ PKG_CONTPRMLOC.PURGE(RCONTAINER => RPROC_PARAMS); /* Собираем параметры процедуры */ PKG_CONTPRMLOC.PUTN(RCONTAINER => RPROC_PARAMS, SNAME => 'NDATASET_IDENT', NVALUE => NDATASET_IDENT, NIN_OUT => PKG_STD.PARAM_TYPE_IN()); PKG_CONTPRMLOC.PUTN(RCONTAINER => RPROC_PARAMS, SNAME => 'NDATASET_CONFIG_IDENT', NVALUE => NDATASET_CONFIG_IDENT, NIN_OUT => PKG_STD.PARAM_TYPE_IN()); PKG_CONTPRMLOC.PUTN(RCONTAINER => RPROC_PARAMS, SNAME => 'NREQUEST_CONFIG_IDENT', NVALUE => NREQUEST_CONFIG_IDENT, NIN_OUT => PKG_STD.PARAM_TYPE_IN()); /* Подчищаем (в автономной транзакции) */ PKG_SQL_CALL.EXECUTE_STORED_AT(SSTORED_NAME => 'UDO_PKG_EQUIPTCF.EQCONFIG_THOBJ_FORECAST_BCLR', RPARAM_CONTAINER => RPROC_PARAMS, BOVERLOAD_ENV => true); /* Очищаем контейнер с параметрами */ PKG_CONTPRMLOC.PURGE(RCONTAINER => RPROC_PARAMS); end EQCONFIG_THOBJ_FORECAST_BCLRAT; /* Подготовка запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_PRLG ( NEQUIPDSCMML in number, -- Рег. номер модели NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number, -- Идентификатор буфера описания запроса SURL out varchar2, -- Адрес для запроса SAUTH_TOKEN out varchar2, -- Токен аутентификации для запроса SDATASET_ID out varchar2, -- Идентификатор выборки данных запроса CDATASET_CONFIG out clob, -- Описание данных о наработках SDATASET_URL out varchar2, -- Адрес для получения данных о наработках SCLASS_MACHINE out varchar2, -- Код класса оборудования для запроса STASK out varchar2 -- Задача для запроса (см. константы UDO_PKG_EQUIPDS_BASE.SCMML_TASK_*) ) is REQUIPDSCMML UDO_T_EQUIPDSCMML%rowtype; -- Запись модели REQUIPDSCM UDO_T_EQUIPDSCM%rowtype; -- Запись класса оборудования выборки данных, родительской для модели REXSSERVICEFN_SEND_RQ EXSSERVICEFN%rowtype; -- Запись функции обмена для обучения модели REXSSERVICE_SEND_RQ EXSSERVICE%rowtype; -- Запись сервиса обмена для обучения модели REXSSERVICEFN_FRCST_MD EXSSERVICEFN%rowtype; -- Запись функции обмена для публикации сведений о наработке единицы оборудования при получении прогноза REXSSERVICE_FRCST_MD EXSSERVICE%rowtype; -- Запись сервиса обмена для публикации сведений о наработке единицы оборудования при получении прогноза NAPI_ROOT_INDEX PKG_STD.TNUMBER; -- Символ вхождения корня API в адрес сервера внешней системы NCNT PKG_STD.TNUMBER; -- Буфер для количества файлов данных begin /* Определим адрес сервера приложений */ SDATASET_URL := GET_OPTIONS_STR(SCODE => 'EXSService_AppServer'); if (SDATASET_URL is null) then P_EXCEPTION(0, 'В настройках Системы не задан параметр "Адрес сервера приложений (сервисы обмена)" (номер - 1929, код - "EXSService_AppServer").'); end if; /* Проверим данные о наработках */ begin select count(T.RN) into NCNT from FILE_BUFFER T where T.IDENT = NDATASET_IDENT and T.BDATA is not null; exception when others then P_EXCEPTION(0, 'Не удалось проверить набор данных о наработках.'); end; if (NCNT > 1) then P_EXCEPTION(0, 'Набор данных о наработках определён неоднозначно.'); end if; if (NCNT = 0) then P_EXCEPTION(0, 'Набор данных о наработках не определён.'); end if; /* Читаем описание данных о наработках */ for C in (select T.DATA CDATA from FILE_BUFFER T where T.IDENT = NDATASET_CONFIG_IDENT) loop if (CDATASET_CONFIG is not null) then P_EXCEPTION(0, 'Описание набора данных о наработках определёно неоднозначно.'); end if; CDATASET_CONFIG := C.CDATA; end loop; if (CDATASET_CONFIG is null) then P_EXCEPTION(0, 'Описание набора данных о наработках не определёно.'); end if; /* Проверим данные конфигурации запроса */ begin select count(T.RN) into NCNT from FILE_BUFFER T where T.IDENT = NREQUEST_CONFIG_IDENT and T.DATA is not null; exception when others then P_EXCEPTION(0, 'Не удалось проверить параметры запроса на прогнозирование.'); end; if (NCNT > 1) then P_EXCEPTION(0, 'Параметры запроса на прогнозирование определёны неоднозначно.'); end if; if (NCNT = 0) then P_EXCEPTION(0, 'Параметры запроса на прогнозирование не определёны.'); end if; /* Читаем запись модели */ REQUIPDSCMML := UDO_PKG_EQUIPDS_BASE.CMML_GET(NFLAG_SMART => 0, NRN => NEQUIPDSCMML); if (REQUIPDSCMML.STATUS <> UDO_PKG_EQUIPDS_BASE.NCMML_STATUS_PROCESSED) then P_EXCEPTION(0, 'Модель (регистрационный номер %s) находится в состоянии отличном от "Обучена".', TO_CHAR(REQUIPDSCMML.RN)); end if; /* Читаем запись её родительского класса оборудования */ REQUIPDSCM := UDO_PKG_EQUIPDS_BASE.CM_GET(NFLAG_SMART => 0, NRN => REQUIPDSCMML.PRN); /* Читаем функию и сервис обмена, применяемые для обучения модели */ REXSSERVICEFN_SEND_RQ := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0, NRN => REQUIPDSCM.EXSSERVICEFN_SEND_RQ); REXSSERVICE_SEND_RQ := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN_SEND_RQ.PRN); /* Формируем URL для запроса */ NAPI_ROOT_INDEX := INSTR(REXSSERVICE_SEND_RQ.SRV_ROOT, SFW_API_ROOT); if (NAPI_ROOT_INDEX = 0) then P_EXCEPTION(0, 'Неожиданный формат адреса внешней системы "%s" - не удалось определить корень API ("%s").', REXSSERVICE_SEND_RQ.SRV_ROOT, SFW_API_ROOT); end if; SURL := SUBSTR(REXSSERVICE_SEND_RQ.SRV_ROOT, 1, NAPI_ROOT_INDEX - 1) || SFW_API_ROOT || SFW_API_FORECAST; /* Формируем токен для аутентификации */ SAUTH_TOKEN := TO_CHAR(BASE64_ENCODE(CLOB2BLOB(REXSSERVICE_SEND_RQ.SRV_USER || ':' || BLOB2CLOB(BASE64_DECODE(REXSSERVICE_SEND_RQ.SRV_PASS))))); /* Формируем идентификатор выборки данных для запроса (в данном случае - просто уникальный идентификатор выборки, ссылка на которую будет передана в "data_url" с запросом на прогноз) */ SDATASET_ID := TO_CHAR(NDATASET_IDENT); /* Читаем функию и сервис обмена, применяемые для публикации данных наработки модели */ REXSSERVICEFN_FRCST_MD := GET_EXSSERVICEFN_ID(NFLAG_SMART => 0, NRN => REQUIPDSCM.EXSSERVICEFN_FRCST_MD); REXSSERVICE_FRCST_MD := GET_EXSSERVICE_ID(NFLAG_SMART => 0, NRN => REXSSERVICEFN_FRCST_MD.PRN); /* Формируем адрес для получения фреймворком данных о наработках (по ним будет строиться прогоз, их мы готовили предварительно, вызовом ПП) */ if ((SUBSTR(SDATASET_URL, -1) <> '/') and (SUBSTR(REXSSERVICE_FRCST_MD.SRV_ROOT, 1, 1) <> '/')) then SDATASET_URL := SDATASET_URL || '/'; end if; SDATASET_URL := SDATASET_URL || REXSSERVICE_FRCST_MD.SRV_ROOT; if ((SUBSTR(SDATASET_URL, -1) <> '/') and (SUBSTR(REXSSERVICEFN_FRCST_MD.FN_URL, 1, 1) <> '/')) then SDATASET_URL := SDATASET_URL || '/'; end if; SDATASET_URL := SDATASET_URL || REXSSERVICEFN_FRCST_MD.FN_URL || '?NDATASET_IDENT=' || TO_CHAR(NDATASET_IDENT); /* Код класса оборудования для запроса */ begin select T.CODE into SCLASS_MACHINE from EQOBJKIND T where T.RN = REQUIPDSCM.EQOBJKIND; exception when NO_DATA_FOUND then PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => REQUIPDSCM.EQOBJKIND, SUNIT_TABLE => 'EQOBJKIND'); end; /* Задача для запроса */ STASK := REQUIPDSCMML.TASK; exception when others then /* Подчистим буферы */ EQCONFIG_THOBJ_FORECAST_BCLRAT(NDATASET_IDENT => NDATASET_IDENT, NDATASET_CONFIG_IDENT => NDATASET_CONFIG_IDENT, NREQUEST_CONFIG_IDENT => NREQUEST_CONFIG_IDENT); /* Пробросим ошибку */ raise; end EQCONFIG_THOBJ_FORECAST_PRLG; /* Финализация исполнения запроса на формирование прогноза технического объекта */ procedure EQCONFIG_THOBJ_FORECAST_EPLG ( NDATASET_IDENT in number, -- Идентификатор буфера данных NDATASET_CONFIG_IDENT in number, -- Идентификатор буфера описания данных NREQUEST_CONFIG_IDENT in number, -- Идентификатор буфера описания запроса NEQCONFIG in number, -- Рег. номер технического объекта NEQUIPDSCMML in number, -- Рег. номер модели CFORECAST in clob -- Данные прогноза ) is NEQUIPDSCMMLH PKG_STD.TREF; -- Рег. номер истории запросов модели CRQ clob; -- Описание параметров запроса на прогноз DFORECAST_DATE PKG_STD.TLDATE; -- Дата прогноза (последняя) NFORECAST_DAYS PKG_STD.TNUMBER; -- Прогноз (дней до выхода из строя на дату прогноза) DBEG PKG_STD.TLDATE; -- Дата окончания интервала сбора данных для прогноза DEND PKG_STD.TLDATE; -- Дата начала интервала сбора данных для прогноза NINTERVAL PKG_STD.TLNUMBER; -- Размер (в днях) интервала измерения XFORECAST PKG_XPATH.TDOCUMENT; -- XML-документ прогноза XROOT PKG_XPATH.TNODE; -- Корневой элемент документа прогноза XFCTS PKG_XPATH.TNODES; -- Массив предсказаний XLAST_FCT PKG_XPATH.TNODE; -- Последний элемент массива предсказаний NLAST PKG_STD.TNUMBER; -- Номер последней позиции массива предсказаний NLAST_INTERVALS PKG_STD.TLNUMBER; -- Значение (количество интервалов измерения до выхода из строя) последней записи массива предсказаний begin /* Считаем параметры сделанного запроса */ begin select T.DATA into CRQ from FILE_BUFFER T where T.IDENT = NREQUEST_CONFIG_IDENT and T.DATA is not null; exception when NO_DATA_FOUND then P_EXCEPTION(0, 'Параметры запроса на прогнозирование не определёны.'); when TOO_MANY_ROWS then P_EXCEPTION(0, 'Параметры запроса на прогнозирование определёны неоднозначно.'); end; /* Добавляем запись истории запросов */ UDO_PKG_EQUIPDS_BASE.CMMLH_INS(NPRN => NEQUIPDSCMML, NEQCONFIG => NEQCONFIG, SRQ_AUTHID => UTILIZER(), DRQ_DATE => sysdate, BRQ => CLOB2BLOB(LCDATA => CRQ), NRN => NEQUIPDSCMMLH); /* Пробуем разобрать прогноз */ begin /* Читаем параметры с которыми делался прогноз */ UDO_PKG_EQUIPDS_BASE.UTL_FORECAST_RQ_PARSE_CFG(CRQ_CFG => CRQ, DBEG => DBEG, DEND => DEND, NINTERVAL => NINTERVAL); /* Разбираем данные прогноза */ XFORECAST := PKG_XPATH.PARSE_FROM_BLOB(LBXML => BASE64_DECODE(LCSRCE => CFORECAST)); XROOT := PKG_XPATH.ROOT_NODE(RDOCUMENT => XFORECAST); XFCTS := PKG_XPATH.LIST_NODES(RPARENT_NODE => XROOT, SPATTERN => 'XDATA/XFORECAST'); /* Читаем последнее значение из массива предсказаний (оно соответствует дате окончания из параметров прогноза) */ NLAST := PKG_XPATH.COUNT_NODES(RNODES => XFCTS); XLAST_FCT := PKG_XPATH.ITEM_NODE(RNODES => XFCTS, INUMBER => NLAST); NLAST_INTERVALS := PKG_XPATH.VALUE_NUM(RNODE => XLAST_FCT, SPATTERN => 'VALUE'); if (NLAST_INTERVALS < 0) then NLAST_INTERVALS := 0; end if; /* Освобождаем документ */ PKG_XPATH.FREE(RDOCUMENT => XFORECAST); /* Сформируем дату прогноза и количество дней до выхода из строя на эту дату */ DFORECAST_DATE := DEND; NFORECAST_DAYS := NINTERVAL * NLAST_INTERVALS; exception when others then null; end; /* Сохраним данные прогноза */ UDO_PKG_EQUIPDS_BASE.CMMLH_SET_FORECAST(NRN => NEQUIPDSCMMLH, BFORECAST => BASE64_DECODE(LCSRCE => CFORECAST), DFORECAST_DATE => DFORECAST_DATE, NFORECAST_DAYS => NFORECAST_DAYS); /* Подчистим буферы */ EQCONFIG_THOBJ_FORECAST_BCLR(NDATASET_IDENT => NDATASET_IDENT, NDATASET_CONFIG_IDENT => NDATASET_CONFIG_IDENT, NREQUEST_CONFIG_IDENT => NREQUEST_CONFIG_IDENT); exception when others then /* Подчистим буферы */ EQCONFIG_THOBJ_FORECAST_BCLRAT(NDATASET_IDENT => NDATASET_IDENT, NDATASET_CONFIG_IDENT => NDATASET_CONFIG_IDENT, NREQUEST_CONFIG_IDENT => NREQUEST_CONFIG_IDENT); /* Пробросим ошибку */ raise; end EQCONFIG_THOBJ_FORECAST_EPLG; /* Вероятность выхода единицы оборудования из строя с учётом графика ТО и ремонтов и RUL-прогноза */ function EQCONFIG_THOBJ_TCHSRV_BRKDPROB ( NEQCONFIG in number -- Рег. номер технического объекта ) return number -- Вероятность выхода из строя is NRES PKG_STD.TNUMBER; -- Буфер для результата DFORECAST_DATE PKG_STD.TLDATE; -- Дата прогноза NFORECAST_DAYS PKG_STD.TNUMBER; -- Значение самго свежего прогноза модели DCALC_DATE PKG_STD.TLDATE; -- Дата расчета вероятности begin /* Определим дату ближайшего ТО или ремонта */ DCALC_DATE := EQCONFIG_THOBJ_GEN_NXTRPR(NEQCONFIG => NEQCONFIG); /* Вынем самый свежий прогноз */ for C in (select T.FORECAST_DATE DFORECAST_DATE, T.FORECAST_DAYS NFORECAST_DAYS from UDO_T_EQUIPDSCMMLH T, UDO_T_EQUIPDSCMML CMML where T.EQCONFIG = NEQCONFIG and T.PRN = CMML.RN and CMML.TASK = UDO_PKG_EQUIPDS_BASE.SCMML_TASK_RUL order by T.RQ_DATE desc) loop DFORECAST_DATE := C.DFORECAST_DATE; NFORECAST_DAYS := C.NFORECAST_DAYS; exit; end loop; /* Если есть прогноз */ if ((DFORECAST_DATE is not null) and (NFORECAST_DAYS is not null)) then /* Если и дата ТО есть */ if (DCALC_DATE is not null) then /* Вычислим вероятность */ NRES := UDO_PKG_EQUIPDS_BASE.CMMLH_RUL_BREAKDOWN_PROB(DFORECAST_DATE => DFORECAST_DATE, NFORECAST_DAYS => NFORECAST_DAYS, DDATE => DCALC_DATE); else /* Запланированных ремонтов или ТО нет, но прогноз есть - значит точно выйдет из строя */ NRES := 100; end if; end if; /* Вернём то, что собрали */ return NRES; end EQCONFIG_THOBJ_TCHSRV_BRKDPROB; /* Модификация графика ТО и ремонтов для технического объекта */ procedure EQCONFIG_THOBJ_CHNG_EQTCHSRV ( NEQCONFIG in number, -- Рег. номер технического объекта NEQTCHSRV in number, -- Рег. номер графика ТО и ремонтов DPLANDATE_FROM in date -- Уточнённая плановая дата начала ремонта ) is REQTCHSRV EQTCHSRV%rowtype; -- Запись графика ТО и ремонтов RDSCMMLH UDO_T_EQUIPDSCMMLH%rowtype; -- Запись истории прогнозов NDIFF PKG_STD.TNUMBER; -- Отклонение старой и новой дат DDATEPRD_BEG PKG_STD.TLDATE; -- Новая дата начала DDATEPRD_END PKG_STD.TLDATE; -- Новая дата окончания SNOTE PKG_STD.TSTRING; -- Новое примечание begin /* Считаем график */ begin select T.* into REQTCHSRV from EQTCHSRV T where T.RN = NEQTCHSRV; exception when NO_DATA_FOUND then PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEQTCHSRV, SUNIT_TABLE => 'EquipTechServices'); end; /* Считаем запись истории прогнозов */ begin select T.* into RDSCMMLH from UDO_T_EQUIPDSCMMLH T where T.RN = (select max(TT.RN) from UDO_T_EQUIPDSCMMLH TT where TT.EQCONFIG = NEQCONFIG); exception when others then P_EXCEPTION(0, 'Не удалось определить запись-основание истории прогнозов модели.'); end; /* Проверим, что из графика не сформирована ремонтная ведомость */ if (F_DOCLINKS_LINK_OUT_DOC(SIN_UNITCODE => 'EquipTechServices', NIN_DOCUMENT => REQTCHSRV.RN, SOUT_UNITCODE => 'EquipRepairSheets') is not null) then P_EXCEPTION(0, 'Из графика ТО и ремонтов (RN: %s) уже создана ремонтная ведомость.', TO_CHAR(REQTCHSRV.RN)); end if; /* Проверим, что есть на что менять */ if (TRUNC(DPLANDATE_FROM) = TRUNC(REQTCHSRV.DATEPRD_BEG)) then P_EXCEPTION(0, 'Выбранный график ТО и ремонтов уже запланирован на %s', TO_CHAR(DPLANDATE_FROM, 'dd.mm.yyyy')); end if; /* Сбросим состояние графика */ if (REQTCHSRV.STATE <> 0) then P_EQTCHSRV_SET_STATE(NCOMPANY => REQTCHSRV.COMPANY, NRN => REQTCHSRV.RN, NSTATE => 0, DDATE => sysdate); end if; /* Определим отклонение и новые даты графика */ NDIFF := DPLANDATE_FROM - REQTCHSRV.DATEPRD_BEG; DDATEPRD_BEG := REQTCHSRV.DATEPRD_BEG + NDIFF; DDATEPRD_END := REQTCHSRV.DATEPRD_END + NDIFF; /* Формируем новое примечание */ SNOTE := 'Автоматически перенесён с "' || TO_CHAR(REQTCHSRV.DATEPRD_BEG, 'dd.mm.yyyy hh24:mi:ss') || '" на "' || TO_CHAR(DDATEPRD_BEG, 'dd.mm.yyyy hh24:mi:ss') || '" на основании прогноза от "' || TO_CHAR(RDSCMMLH.RQ_DATE, 'dd.mm.yyyy hh24:mi:ss') || '" (RN: ' || TO_CHAR(RDSCMMLH.RN) || ', пользователь: ' || RDSCMMLH.RQ_AUTHID || ').'; /* Изменим заголовок графика */ update EQTCHSRV T set T.DATEPRD_BEG = DDATEPRD_BEG, T.DATEPRD_END = DDATEPRD_END, T.NOTE = SNOTE where T.RN = REQTCHSRV.RN; /* Сдвинем работы */ P_EQTCHSRV_MOVE_WORK(NCOMPANY => REQTCHSRV.COMPANY, NRN => REQTCHSRV.RN, NDUP_RN => null, DDATEPRD_BEG => DDATEPRD_BEG, DOLD_DATEPRD_BEG => REQTCHSRV.DATEPRD_BEG, DDATEPRD_END => DDATEPRD_END, NPERIOD => null, NMODE => 1); /* Восстановим состояние графика */ if (REQTCHSRV.STATE <> 0) then P_EQTCHSRV_SET_STATE(NCOMPANY => REQTCHSRV.COMPANY, NRN => REQTCHSRV.RN, NSTATE => REQTCHSRV.STATE, DDATE => sysdate); end if; end EQCONFIG_THOBJ_CHNG_EQTCHSRV; /* Формирование ремонтной ведомости для технического объекта */ procedure EQCONFIG_THOBJ_MAKE_EQRPSHEET ( NEQCONFIG in number, -- Рег. номер технического объекта SACATALOG in varchar2, -- Каталог размещения ведомости SEQTECSRVKIND in varchar2, -- Вид ремонта DPLANDATE_FROM in date, -- Плановая дата начала ремонта NIDENT out number -- Идентификатор списка сформированных ведомостей ) is NCOMPANY PKG_STD.TREF := GET_SESSION_COMPANY(); -- Рег. номер организации NCRN PKG_STD.TREF; -- Рег. номер каталога размещения ведомости SJURPERSONS PKG_STD.TSTRING; -- Юридическая принадлежность технического объекта SCURRENCY PKG_STD.TSTRING; -- Валюта ведомости SDOCTYPES PKG_STD.TSTRING; -- Тип документа ведомости SPREF PKG_STD.TSTRING; -- Префикс ведосмости SNUMB PKG_STD.TSTRING; -- Номер ведомости NEQRPSHEET PKG_STD.TREF; -- Рег. номер сформированной ведомости begin /* Определяем юридическую принадлежность технического объекта */ begin select JP.CODE into SJURPERSONS from EQCONFIG T, JURPERSONS JP where T.RN = NEQCONFIG and T.JUR_PERS = JP.RN; exception when NO_DATA_FOUND then PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => 0, NDOCUMENT => NEQCONFIG, SUNIT_TABLE => 'EquipConfiguration'); end; /* Читаем валюту документа по-умолчанию из параметров */ SCURRENCY := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_Currency'); /* Читаем тип документа по-умолчанию из параметров */ SDOCTYPES := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_DocType'); /* Читаем префикс документа по-умолчанию из параметров */ SPREF := GET_OPTIONS_STR(SCODE => 'Equip_RepairSheets_DocPref'); /* Формируем очередной номер документа */ P_EQRPSHEETS_GETNEXTNUMB(NCOMPANY => NCOMPANY, SPREF => SPREF, SDOCTYPES => SDOCTYPES, SNUMB => SNUMB); /* Определяем каталог размещения */ FIND_ACATALOG_NAME(NFLAG_SMART => 0, NCOMPANY => NCOMPANY, NVERSION => null, SUNITCODE => 'EquipRepairSheets', SNAME => SACATALOG, NRN => NCRN); /* Формируем ведомость */ P_EQRPSHEETS_MAKE_EQRPSHEET(NCOMPANY => NCOMPANY, NCRN => NCRN, SDOCTYPES => SDOCTYPES, SPREF => SPREF, SNUMB => SNUMB, DDOCDATE => sysdate, SJURPERSONS => SJURPERSONS, DPLANDATE_FROM => TRUNC(DPLANDATE_FROM), DPLANDATE_TO => (TRUNC(DPLANDATE_FROM) + 1) - 1/24/60, SCURRENCY => SCURRENCY, NCOURSE => 1, SEQTECSRVKIND => SEQTECSRVKIND, NPR_OBJ => null, NTECH_OBJ => NEQCONFIG, STECH_SRV_DIV => null, SRESP_DIV => null, SPERF_DIV => null, SPERFORM_AGN => null, SLEVEL => null, SEQOBJKIND => null, NRN => NEQRPSHEET); /* Добавим ведомость в список */ EQCONFIG_THOBJ_SELECT_EQRPSHT(NEQRPSHEETS => NEQRPSHEET, NIDENT => NIDENT); end EQCONFIG_THOBJ_MAKE_EQRPSHEET; end UDO_PKG_EQUIPTCF; /