create or replace package UDO_PKG_EQUIPDS_BASE as
 
  /* Константы - состояния "Выборки данных оборудования (классы оборудования, файлы данных)" */
  NCMFL_STATUS_REGISTERED   constant PKG_STD.TNUMBER := 0; -- Зарегистрирован
  NCMFL_STATUS_UPLOADING    constant PKG_STD.TNUMBER := 1; -- Загружается на сервер
  NCMFL_STATUS_UPLOADED     constant PKG_STD.TNUMBER := 2; -- Успешно загружен на сервер
  NCMFL_STATUS_UPLOAD_ERR   constant PKG_STD.TNUMBER := 3; -- Ошибка загрузки на сервер
  NCMFL_STATUS_SENDING      constant PKG_STD.TNUMBER := 4; -- Загружается во внешнюю систему
  NCMFL_STATUS_SENT         constant PKG_STD.TNUMBER := 5; -- Успешно загружен во внешнюю систему
  NCMFL_STATUS_SEND_ERR     constant PKG_STD.TNUMBER := 6; -- При загрузке во внешнюю систему произошла ошибка

  /* Константы - типовые задачи "Выборки данных оборудования (классы оборудования, модели)" */
  SCMML_TASK_TCF            constant PKG_STD.TSTRING := 'TCF'; -- TCF - оценка технического состояния (Technical Condition Forecast)
  SCMML_TASK_RUL            constant PKG_STD.TSTRING := 'RUL'; -- RUL - прогнозирование остаточного ресурса (Remaining Useful Life)
  SCMML_TASK_FP             constant PKG_STD.TSTRING := 'FP';  -- FP - Прогнозирование отказа (Failure Predict)
  
  /* Константы - состояния "Выборки данных оборудования (классы оборудования, модели)" */
  NCMML_STATUS_REGISTERED   constant PKG_STD.TNUMBER := 0; -- Зарегистрирована
  NCMML_STATUS_PROCESSING   constant PKG_STD.TNUMBER := 1; -- Обрабатывается внешней системой
  NCMML_STATUS_PROCESSED    constant PKG_STD.TNUMBER := 2; -- Успешно обработана внешней системой
  NCMML_STATUS_PROCESS_ERR  constant PKG_STD.TNUMBER := 3; -- При обработке внешней системой произошла ошибка

  /* Проверка прав доступа */
  function UTL_ACCESS_CHECK
  (
    SUSER                   in varchar2,      -- Пользователь
    STABLE                  in varchar2,      -- Таблица раздела
    SACTION                 in varchar2,      -- Действие в разделе
    NDOCUMENT               in number := null -- Регистрационный номер документа
  ) return                  boolean;          -- Флаг доступа (false - нет доступа, true - доступ есть)

  /* Проверка прав доступа (процедурная обёртка) */
  procedure UTL_ACCESS
  (
    STABLE                  in varchar2,     -- Таблица раздела
    SACTION                 in varchar2,     -- Действие в разделе
    NDOCUMENT               in number :=null -- Регистрационный номер документа
  );
  
  /* Считывание записи "Выборки данных оборудования" по регистрационному номеру */
  function GET
  (
    NFLAG_SMART             in number,             -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number              -- Регистрационный номер
  ) return                  UDO_T_EQUIPDS%rowtype; -- Запись выборки данных оборудования

  /* Поиск "Выборки данных оборудования" по мнемокоду */
  procedure FIND_BY_CODE
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    NRN                     out number   -- Регистрационный номер
  );
  
  /* Базовое добавление "Выборки данных оборудования" */
  procedure INS
  (
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    SNAME                   in varchar2, -- Наименование
    NRN                     out number   -- Регистрационный номер
  );

  /* Базовое исправление "Выборки данных оборудования" */
  procedure UPD
  (
    NRN                     in number,   -- Регистрационный номер
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    SNAME                   in varchar2  -- Наименование
  );

  /* Базовое удаление "Выборки данных оборудования" */
  procedure DEL
  (
    NRN                     in number,  -- Регистрационный номер
    NCOMPANY                in number   -- Организация
  );
  
  /* Считывание записи "Выборки данных оборудования (классы оборудования)" по регистрационному номеру */
  function CM_GET
  (
    NFLAG_SMART             in number,               -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCM%rowtype; -- Запись класса оборудования выборки данных

  /* Поиск "Выборки данных оборудования (классы оборудования)" по классу оборудования */
  procedure CM_FIND_BY_EQOBJKIND
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NPRN                    in number,   -- Родитель
    SEQOBJKIND              in varchar2, -- Класс оборудования
    NRN                     out number   -- Регистрационный номер
  );
  
  /* Разыменование словарей "Выборки данных оборудования (классы оборудования)" */
  procedure CM_JOINS
  (
    NCOMPANY                in number,   -- Организация
    SEQOBJKIND              in varchar2, -- Класс оборудования
    SDICMUNTS               in varchar2, -- Единица измерения выборки
    SUSERPROCS_DATA         in varchar2, -- Процедура формирования
    SEXSSERVICE_UPLOAD      in varchar2, -- Сервис обмена для выгрузки данных
    SEXSSERVICEFN_UPLOAD    in varchar2, -- Функция обмена для выгрузки данных
    SEXSSERVICE_SEND_MD     in varchar2, -- Сервис обмена для передачи внешней системе
    SEXSSERVICEFN_SEND_MD   in varchar2, -- Функция обмена для передачи внешней системе
    SEXSSERVICE_SEND_RQ     in varchar2, -- Сервис обмена для обработки внешней системой
    SEXSSERVICEFN_SEND_RQ   in varchar2, -- Функция обмена для обработки внешней системой
    NEQOBJKIND              out number,  -- Рег. номер класса оборудования
    NDICMUNTS               out number,  -- Рег. номер единицы измерения выборки
    NUSERPROCS_DATA         out number,  -- Рег. номер процедуры формирования
    NEXSSERVICEFN_UPLOAD    out number,  -- Рег. номер функции обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   out number,  -- Рег. номер Функции обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   out number   -- Рег. номер функции обмена для обработки внешней системой
  );
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования)" */
  procedure CM_INS
  (
    NPRN                    in number,  -- Родитель
    NEQOBJKIND              in number,  -- Класс оборудования
    NDICMUNTS               in number,  -- Единица измерения выборки
    NUSERPROCS_DATA         in number,  -- Процедура формирования
    NEXSSERVICEFN_UPLOAD    in number,  -- Функция обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   in number,  -- Функция обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   in number,  -- Функция обмена для обработки внешней системой
    NRN                     out number  -- Регистрационный номер
  );
  
  /* Базовое исправление "Выборки данных оборудования (классы оборудования)" */  
  procedure CM_UPD
  (
    NRN                     in number,  -- Регистрационный номер
    NEQOBJKIND              in number,  -- Класс оборудования
    NDICMUNTS               in number,  -- Единица измерения выборки    
    NUSERPROCS_DATA         in number,  -- Процедура формирования
    NEXSSERVICEFN_UPLOAD    in number,  -- Функция обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   in number,  -- Функция обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   in number   -- Функция обмена для обработки внешней системой
  );
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования)" */
  procedure CM_DEL
  (
    NRN                     in number   -- Регистрационный номер
  );
  
  /* Базовая установка описания структуры выборки "Выборки данных оборудования (классы оборудования)" */  
  procedure CM_SET_DATA_CONFIG
  (
    NRN                     in number,  -- Регистрационный номер
    BDATA_CONFIG            in clob     -- Описание структуры выборки
  );
  
  /* Считывание записи "Выборки данных оборудования (классы оборудования, файлы данных)" по регистрационному номеру */
  function CMFL_GET
  (
    NFLAG_SMART             in number,                 -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                  -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCMFL%rowtype; -- Запись файла данных класса оборудования выборки данных
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, файлы данных)" */
  procedure CMFL_INS
  (
    NPRN                    in number,   -- Родитель
    SFILE_NAME              in varchar2, -- Имя файла
    SDESCR                  in varchar2, -- Описание
    BDATASET                in blob,     -- Данные выборки    
    NRN                     out number   -- Регистрационный номер
  );
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования, файлы данных)" */
  procedure CMFL_DEL
  (
    NRN                     in number   -- Регистрационный номер
  );  

  /* Базовая установка имени файла "Выборки данных оборудования (классы оборудования, файлы данных)" */  
  procedure CMFL_SET_FILE_NAME
  (
    NRN                     in number,  -- Регистрационный номер
    SFILE_NAME              in varchar2 -- Имя файла
  );
  
  /* Базовая установка состояния "Выборки данных оборудования (классы оборудования, файлы данных)" */  
  procedure CMFL_SET_STATUS
  (
    NRN                     in number,           -- Регистрационный номер
    NSTATUS                 in number,           -- Состояние (см. константы NCMFL_STATUS_*)
    SQUEUE_ID               in varchar2 := null, -- Идентификатор очереди обработки
    SERR                    in varchar2 := null  -- Сообщение об ошибке
  );

  /* Считывание записи "Выборки данных оборудования (классы оборудования, модели)" по регистрационному номеру */
  function CMML_GET
  (
    NFLAG_SMART             in number,                 -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                  -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCMML%rowtype; -- Запись модели класса оборудования выборки данных
  
  /* Поиск "Выборки данных оборудования (классы оборудования, модели)" по задаче */
  procedure CMML_FIND_BY_TASK
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NPRN                    in number,   -- Родитель
    STASK                   in varchar2, -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number,   -- Точность (план)
    NRN                     out number   -- Регистрационный номер
  );
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_INS
  (
    NPRN                    in number,   -- Родитель
    STASK                   in varchar2, -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number,   -- Точность (план)
    NRN                     out number   -- Регистрационный номер
  );
  
  /* Базовое исправление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_UPD
  (
    NRN                     in number,   -- Регистрационный номер
    STASK                   in varchar2, -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number    -- Точность (план)
  );
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_DEL
  (
    NRN                     in number   -- Регистрационный номер
  );  

  /* Базовая установка фактической точности "Выборки данных оборудования (классы оборудования, модели)" */  
  procedure CMML_SET_PRECISION_F
  (
    NRN                     in number,  -- Регистрационный номер
    NPRECISION_F            in number   -- Точность (факт)
  );
  
  /* Базовая установка состояния "Выборки данных оборудования (классы оборудования, модели)" */  
  procedure CMML_SET_STATUS
  (
    NRN                     in number,           -- Регистрационный номер
    NSTATUS                 in number,           -- Состояние (см. константы NCMML_STATUS_*)
    SQUEUE_ID               in varchar2 := null, -- Идентификатор очереди обработки
    SERR                    in varchar2 := null  -- Сообщение об ошибке
  );
  
  /* Формирование наименования для задачи "Выборки данных оборудования (классы оборудования, модели)" */
  function CMML_TASK_NAME
  (
    STASK                   in varchar2 -- Задача (см. константы SCMML_TASK_*) */
  ) return                  varchar2;   -- Наименование задачи
  
  /* Формирование подсказки для задачи "Выборки данных оборудования (классы оборудования, модели)" */
  function CMML_TASK_HINT
  return                    varchar2;   -- Подсказка для задачи

  /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */  
  function CMML_RUL_BREAKDOWN_PROB
  (
    NFORECAST               in number,  -- RUL-прогноз (интервалов до перехода в предельное состояние)
    DFORECAST_DATE          in date,    -- Дата прогноза
    DDATE                   in date     -- Дата на
  ) return                  number;     -- Значение вероятности
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
  procedure CMMLH_INS
  (
    NPRN                    in number,   -- Родитель
    NEQCONFIG               in number,   -- Рег. номер технического объекта
    SRQ_AUTHID              in varchar2, -- Пользователь, выполнивший запрос
    DRQ_DATE                in date,     -- Дата/время запроса
    BRQ                     in blob,     -- Параметры запроса
    NRN                     out number   -- Регистрационный номер
  );

  /* Базовое удаление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
  procedure CMMLH_DEL
  (
    NRN                     in number   -- Регистрационный номер
  );
  
  /* Базовая установка данных прогноза "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */  
  procedure CMMLH_SET_FORECAST
  (
    NRN                     in number,  -- Регистрационный номер
    BFORECAST               in blob     -- Данные прогноза
  );

  /* Базовая установка идентификатора очереди обмена "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */  
  procedure CMMLH_SET_EXSQUEUE
  (
    NRN                     in number,  -- Регистрационный номер
    NEXSQUEUE               in number   -- Идентификатор очереди обмена
  );

end UDO_PKG_EQUIPDS_BASE;
/
create or replace package body UDO_PKG_EQUIPDS_BASE as

  /*Константы - мнемокод роли администратора, разрешающей обучение моделей */
  SROLE_ML_ADMIN            constant PKG_STD.TSTRING := 'ML_ADMIN';
  
  /* Проверка прав доступа */
  function UTL_ACCESS_CHECK
  (
    SUSER                   in varchar2,      -- Пользователь
    STABLE                  in varchar2,      -- Таблица раздела
    SACTION                 in varchar2,      -- Действие в разделе
    NDOCUMENT               in number := null -- Регистрационный номер документа
  ) return                  boolean           -- Флаг доступа (false - нет доступа, true - доступ есть)
  is
  begin
    /* Проверим наличие роли администратора у пользователя */
    for C in (select UR.RN
                from USERROLES UR,
                     ROLES     R,
                     USERLIST  UL
               where UR.ROLEID = R.RN
                 and UR.AUTHID = UL.AUTHID
                 and UL.AUTHID = SUSER
                 and R.ROLENAME = SROLE_ML_ADMIN)
    loop
      /* Роль есть */
      return true;
    end loop;
    /* Прав доступа нет */
    return false;
  end UTL_ACCESS_CHECK;
  
  /* Проверка прав доступа (процедурная обёртка) */
  procedure UTL_ACCESS
  (
    STABLE                  in varchar2,     -- Таблица раздела
    SACTION                 in varchar2,     -- Действие в разделе
    NDOCUMENT               in number :=null -- Регистрационный номер документа
  )
  is
  begin
    if (not UDO_PKG_EQUIPDS_BASE.UTL_ACCESS_CHECK(SUSER     => UTILIZER(),
                                                  STABLE    => STABLE,
                                                  SACTION   => SACTION,
                                                  NDOCUMENT => NDOCUMENT)) then
      P_EXCEPTION(0,
                  'У вас нет прав доступа для выполнения действия "%s" в таблице "%s".',
                  SACTION,
                  STABLE);
    end if;
  end UTL_ACCESS;
  
  /* Считывание записи "Выборки данных оборудования" по регистрационному номеру */
  function GET
  (
    NFLAG_SMART             in number,             -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number              -- Регистрационный номер
  ) return                  UDO_T_EQUIPDS%rowtype  -- Запись выборки данных оборудования
  is
    RES                     UDO_T_EQUIPDS%rowtype; -- Буфер для результата
  begin
    /* Считывание записи */
    begin
      select T.* into RES from UDO_T_EQUIPDS T where T.RN = NRN;
    exception
      when NO_DATA_FOUND then
        PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => NFLAG_SMART, NDOCUMENT => NRN, SUNIT_TABLE => 'UDO_T_EQUIPDS');
    end;
    /* Возврат результата */
    return RES;
  end GET;
  
  /* Поиск "Выборки данных оборудования" по мнемокоду */
  procedure FIND_BY_CODE
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Поиск записи */
    begin
      select RN
        into NRN
        from UDO_T_EQUIPDS T
       where T.COMPANY = NCOMPANY
         and T.CODE = SCODE;
    exception
      when NO_DATA_FOUND then
        P_EXCEPTION(NFLAG_SMART,
                    'Выборка данных оборудования "%s" не определёна.',
                    SCODE);
    end;
  end FIND_BY_CODE;
  
  /* Базовое добавление "Выборки данных оборудования" */
  procedure INS
  (
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    SNAME                   in varchar2, -- Наименование
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Формируем рег. номер */
    NRN := GEN_ID();
    /* Добавляем запись */
    insert into UDO_T_EQUIPDS (RN, COMPANY, CODE, name) values (NRN, NCOMPANY, SCODE, SNAME);
  end INS;

  /* Базовое исправление "Выборки данных оборудования" */
  procedure UPD
  (
    NRN                     in number,   -- Регистрационный номер
    NCOMPANY                in number,   -- Организация
    SCODE                   in varchar2, -- Мнемокод
    SNAME                   in varchar2  -- Наименование
  )
  is
  begin
    /* Исправим данные */
    update UDO_T_EQUIPDS T
       set T.CODE = SCODE,
           T.NAME = SNAME
     where T.RN = NRN
       and T.COMPANY = NCOMPANY;
  end UPD;

  /* Базовое удаление "Выборки данных оборудования" */
  procedure DEL
  (
    NRN                     in number,  -- Регистрационный номер
    NCOMPANY                in number   -- Организация
  )
  is
  begin
    /* Удалим запись */
    delete from UDO_T_EQUIPDS T
     where T.RN = NRN
       and T.COMPANY = NCOMPANY;
  end DEL;
  
  /* Считывание записи "Выборки данных оборудования (классы оборудования)" по регистрационному номеру */
  function CM_GET
  (
    NFLAG_SMART             in number,               -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCM%rowtype  -- Запись класса оборудования выборки данных
  is
    RES                     UDO_T_EQUIPDSCM%rowtype; -- Буфер для результата
  begin
    /* Считывание записи */
    begin
      select T.* into RES from UDO_T_EQUIPDSCM T where T.RN = NRN;
    exception
      when NO_DATA_FOUND then
        PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => NFLAG_SMART, NDOCUMENT => NRN, SUNIT_TABLE => 'UDO_T_EQUIPDSCM');
    end;
    /* Возврат результата */
    return RES;
  end CM_GET;

  /* Поиск "Выборки данных оборудования (классы оборудования)" по классу оборудования */
  procedure CM_FIND_BY_EQOBJKIND
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NPRN                    in number,   -- Родитель
    SEQOBJKIND              in varchar2, -- Класс оборудования
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Поиск записи */
    begin
      select T.RN
        into NRN
        from UDO_T_EQUIPDSCM T,
             EQOBJKIND       OK
       where T.PRN = NPRN
         and T.EQOBJKIND = OK.RN
         and OK.CODE = SEQOBJKIND;
    exception
      when NO_DATA_FOUND then
        P_EXCEPTION(NFLAG_SMART,
                    'Класс оборудования "%s" в выборке данных "%s" не определён.',
                    SEQOBJKIND,
                    TO_CHAR(NPRN));
    end;
  end CM_FIND_BY_EQOBJKIND;
  
  /* Разыменование словарей "Выборки данных оборудования (классы оборудования)" */
  procedure CM_JOINS
  (
    NCOMPANY                in number,   -- Организация
    SEQOBJKIND              in varchar2, -- Класс оборудования
    SDICMUNTS               in varchar2, -- Единица измерения выборки
    SUSERPROCS_DATA         in varchar2, -- Процедура формирования
    SEXSSERVICE_UPLOAD      in varchar2, -- Сервис обмена для выгрузки данных
    SEXSSERVICEFN_UPLOAD    in varchar2, -- Функция обмена для выгрузки данных
    SEXSSERVICE_SEND_MD     in varchar2, -- Сервис обмена для передачи внешней системе
    SEXSSERVICEFN_SEND_MD   in varchar2, -- Функция обмена для передачи внешней системе
    SEXSSERVICE_SEND_RQ     in varchar2, -- Сервис обмена для обработки внешней системой
    SEXSSERVICEFN_SEND_RQ   in varchar2, -- Функция обмена для обработки внешней системой
    NEQOBJKIND              out number,  -- Рег. номер класса оборудования
    NDICMUNTS               out number,  -- Рег. номер единицы измерения выборки
    NUSERPROCS_DATA         out number,  -- Рег. номер процедуры формирования
    NEXSSERVICEFN_UPLOAD    out number,  -- Рег. номер функции обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   out number,  -- Рег. номер Функции обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   out number   -- Рег. номер функции обмена для обработки внешней системой
  )
  is
    NEXSSERVICE             PKG_STD.TREF; -- Рег. номер сервиса обмена
  begin
    /* Класс оборудования */
    FIND_EQOBJKIND_FULLCODE(NFLAG_SMART  => 0,
                            NFLAG_OPTION => 0,
                            NCOMPANY     => NCOMPANY,
                            SCODE        => SEQOBJKIND,
                            NRN          => NEQOBJKIND);
    /* Единица измерения */
    FIND_DICMUNTS_CODE(NFLAG_SMART  => 0,
                       NFLAG_OPTION => 0,
                       NCOMPANY     => NCOMPANY,
                       SMEAS_MNEMO  => SDICMUNTS,
                       NRN          => NDICMUNTS);
    /* Процедура формирования */
    if (SUSERPROCS_DATA is not null) then
      FIND_USERPROCS_CODE(NFLAG_SMART => 0, SCODE => SUSERPROCS_DATA, NRN => NUSERPROCS_DATA);
    else
      P_EXCEPTION(0, 'Не указана процедура формирования данных выборки.');
    end if;
    /* Функция обмена для выгрузки данных */
    FIND_EXSSERVICE_CODE(NFLAG_SMART => 0, NFLAG_OPTION => 0, SCODE => SEXSSERVICE_UPLOAD, NRN => NEXSSERVICE);
    FIND_EXSSERVICEFN_CODE(NFLAG_SMART  => 0,
                           NFLAG_OPTION => 0,
                           NEXSSERVICE  => NEXSSERVICE,
                           SCODE        => SEXSSERVICEFN_UPLOAD,
                           NRN          => NEXSSERVICEFN_UPLOAD);
    /* Функция обмена для передачи внешней системе */
    FIND_EXSSERVICE_CODE(NFLAG_SMART => 0, NFLAG_OPTION => 0, SCODE => SEXSSERVICE_SEND_MD, NRN => NEXSSERVICE);
    FIND_EXSSERVICEFN_CODE(NFLAG_SMART  => 0,
                           NFLAG_OPTION => 0,
                           NEXSSERVICE  => NEXSSERVICE,
                           SCODE        => SEXSSERVICEFN_SEND_MD,
                           NRN          => NEXSSERVICEFN_SEND_MD);
    /* Функция обмена для обработки внешней системой */
    FIND_EXSSERVICE_CODE(NFLAG_SMART => 0, NFLAG_OPTION => 0, SCODE => SEXSSERVICE_SEND_RQ, NRN => NEXSSERVICE);
    FIND_EXSSERVICEFN_CODE(NFLAG_SMART  => 0,
                           NFLAG_OPTION => 0,
                           NEXSSERVICE  => NEXSSERVICE,
                           SCODE        => SEXSSERVICEFN_SEND_RQ,
                           NRN          => NEXSSERVICEFN_SEND_RQ);
  end CM_JOINS;
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования)" */
  procedure CM_INS
  (
    NPRN                    in number,  -- Родитель
    NEQOBJKIND              in number,  -- Класс оборудования
    NDICMUNTS               in number,  -- Единица измерения выборки
    NUSERPROCS_DATA         in number,  -- Процедура формирования
    NEXSSERVICEFN_UPLOAD    in number,  -- Функция обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   in number,  -- Функция обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   in number,  -- Функция обмена для обработки внешней системой
    NRN                     out number  -- Регистрационный номер
  )
  is
  begin
    /* Формируем рег. номер */
    NRN := GEN_ID();
    /* Добавляем запись */    
    insert into UDO_T_EQUIPDSCM
      (RN,
       PRN,
       EQOBJKIND,
       DICMUNTS,
       DATA_CONFIG,
       USERPROCS_DATA,
       EXSSERVICEFN_UPLOAD,
       EXSSERVICEFN_SEND_MD,
       EXSSERVICEFN_SEND_RQ)
    values
      (NRN,
       NPRN,
       NEQOBJKIND,
       NDICMUNTS,
       null,
       NUSERPROCS_DATA,
       NEXSSERVICEFN_UPLOAD,
       NEXSSERVICEFN_SEND_MD,
       NEXSSERVICEFN_SEND_RQ);
  end CM_INS;
  
  /* Базовое исправление "Выборки данных оборудования (классы оборудования)" */  
  procedure CM_UPD
  (
    NRN                     in number,  -- Регистрационный номер
    NEQOBJKIND              in number,  -- Класс оборудования
    NDICMUNTS               in number,  -- Единица измерения выборки    
    NUSERPROCS_DATA         in number,  -- Процедура формирования
    NEXSSERVICEFN_UPLOAD    in number,  -- Функция обмена для выгрузки данных
    NEXSSERVICEFN_SEND_MD   in number,  -- Функция обмена для передачи внешней системе
    NEXSSERVICEFN_SEND_RQ   in number   -- Функция обмена для обработки внешней системой
  )
  is
  begin
    /* Исправим данные */
    update UDO_T_EQUIPDSCM T
       set T.EQOBJKIND            = NEQOBJKIND,
           T.DICMUNTS             = NDICMUNTS,
           T.USERPROCS_DATA       = NUSERPROCS_DATA,
           T.EXSSERVICEFN_UPLOAD  = NEXSSERVICEFN_UPLOAD,
           T.EXSSERVICEFN_SEND_MD = NEXSSERVICEFN_SEND_MD,
           T.EXSSERVICEFN_SEND_RQ = NEXSSERVICEFN_SEND_RQ
     where T.RN = NRN;
  end CM_UPD;
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования)" */
  procedure CM_DEL
  (
    NRN                     in number   -- Регистрационный номер
  )
  is
  begin
    /* Удалим файлы */
    for C in (select T.RN from UDO_T_EQUIPDSCMFL T where T.PRN = NRN)
    loop
      CMFL_DEL(NRN => C.RN);
    end loop;
    /* Удалим модели */
    for C in (select T.RN from UDO_T_EQUIPDSCMML T where T.PRN = NRN)
    loop
      CMML_DEL(NRN => C.RN);
    end loop;
    /* Удалим запись */
    delete from UDO_T_EQUIPDSCM T where T.RN = NRN;
  end CM_DEL;
  
  /* Базовая установка описания структуры выборки "Выборки данных оборудования (классы оборудования)" */  
  procedure CM_SET_DATA_CONFIG
  (
    NRN                     in number,  -- Регистрационный номер
    BDATA_CONFIG            in clob     -- Описание структуры выборки
  )
  is
  begin
    /* Установим описание структуры выборки */
    update UDO_T_EQUIPDSCM T set T.DATA_CONFIG = BDATA_CONFIG where T.RN = NRN;
  end CM_SET_DATA_CONFIG;
  
  /* Считывание записи "Выборки данных оборудования (классы оборудования, файлы данных)" по регистрационному номеру */
  function CMFL_GET
  (
    NFLAG_SMART             in number,                 -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                  -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCMFL%rowtype  -- Запись файла данных класса оборудования выборки данных
  is
    RES                     UDO_T_EQUIPDSCMFL%rowtype; -- Буфер для результата
  begin
    /* Считывание записи */
    begin
      select T.* into RES from UDO_T_EQUIPDSCMFL T where T.RN = NRN;
    exception
      when NO_DATA_FOUND then
        PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => NFLAG_SMART, NDOCUMENT => NRN, SUNIT_TABLE => 'UDO_T_EQUIPDSCMFL');
    end;
    /* Возврат результата */
    return RES;
  end CMFL_GET;
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, файлы данных)" */
  procedure CMFL_INS
  (
    NPRN                    in number,   -- Родитель
    SFILE_NAME              in varchar2, -- Имя файла
    SDESCR                  in varchar2, -- Описание
    BDATASET                in blob,     -- Данные выборки
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Формируем рег. номер */
    NRN := GEN_ID();
    /* Добавляем запись */
    insert into UDO_T_EQUIPDSCMFL
      (RN, PRN, FILE_NAME, DESCR, QUEUE_ID, STATUS, ERR, DATASET)
    values
      (NRN, NPRN, SFILE_NAME, SDESCR, null, NCMFL_STATUS_REGISTERED, null, BDATASET);
  end CMFL_INS;
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования, файлы данных)" */
  procedure CMFL_DEL
  (
    NRN                     in number                  -- Регистрационный номер
  )
  is
    RREC                    UDO_T_EQUIPDSCMFL%rowtype; -- Обрабатываемая запись
  begin
    /* Считаем запись */
    RREC := CMFL_GET(NFLAG_SMART => 0, NRN => NRN);
    /* Можно удалять только в статусах: зарегистрирован, успешно загружен на сервер, ошибка загрузки на сервер, успешно загружен во внешнюю систему, при загрузке во внешнюю систему произошла ошибка */
    if (RREC.STATUS not in
       (NCMFL_STATUS_REGISTERED, NCMFL_STATUS_UPLOADED, NCMFL_STATUS_UPLOAD_ERR, NCMFL_STATUS_SENT, NCMFL_STATUS_SEND_ERR)) then
      P_EXCEPTION(0, 'Файл данных обрабатывается, удаление невозможно.');
    end if;
    /* Удалим запись */
    delete from UDO_T_EQUIPDSCMFL T where T.RN = NRN;
  end CMFL_DEL;

  /* Базовая установка имени файла "Выборки данных оборудования (классы оборудования, файлы данных)" */  
  procedure CMFL_SET_FILE_NAME
  (
    NRN                     in number,  -- Регистрационный номер
    SFILE_NAME              in varchar2 -- Имя файла
  )
  is
  begin
    /* Установим имя файла */
    update UDO_T_EQUIPDSCMFL T set T.FILE_NAME = SFILE_NAME where T.RN = NRN;
  end CMFL_SET_FILE_NAME;
  
  /* Базовая установка состояния "Выборки данных оборудования (классы оборудования, файлы данных)" */  
  procedure CMFL_SET_STATUS
  (
    NRN                     in number,                    -- Регистрационный номер
    NSTATUS                 in number,                    -- Состояние (см. константы NCMFL_STATUS_*)
    SQUEUE_ID               in varchar2 := null,          -- Идентификатор очереди обработки
    SERR                    in varchar2 := null           -- Сообщение об ошибке
  )
  is
    SQUEUE_ID_              PKG_STD.TSTRING := SQUEUE_ID; -- Буфер для идентификатора очереди обработки
    SERR_                   PKG_STD.TSTRING := SERR;      -- Буфер для сообщения об ошибке
  begin
    /* Проверим идентификатор очереди */
    if ((NSTATUS in (NCMFL_STATUS_SENDING, NCMFL_STATUS_SENT)) and (SQUEUE_ID_ is null)) then
      P_EXCEPTION(0,
                  'Идентификатор очереди обработки обязателен для перевода файла данных в состояния "Загружается во внешнюю систему", "Успешно загружен во внешнюю систему".');
    end if;
    /* Проверим сообщение об ошибке */
    if ((NSTATUS in (NCMFL_STATUS_UPLOAD_ERR, NCMFL_STATUS_SEND_ERR)) and (SERR_ is null)) then
      P_EXCEPTION(0,
                  'Текст сообщения об ошибке обязателен для перевода файла данных в состояния "Ошибка загрузки на сервер", "Ошибка загрузки во внешнюю систему".');
    end if;
    /* Удалим идентификатор очереди обработки и сообщение об ошибке для тех статусов, где они не нужны */
    if (NSTATUS not in (NCMFL_STATUS_SENDING, NCMFL_STATUS_SENT)) then
      SQUEUE_ID_ := null;
    end if;
    if (NSTATUS not in (NCMFL_STATUS_UPLOAD_ERR, NCMFL_STATUS_SEND_ERR)) then
      SERR_ := null;
    end if;
    /* Установим состояние и сопутствующие ему атрибуты */
    update UDO_T_EQUIPDSCMFL T
       set T.STATUS   = NSTATUS,
           T.QUEUE_ID = SQUEUE_ID_,
           T.ERR      = SERR_
     where T.RN = NRN;
  end CMFL_SET_STATUS;

  /* Считывание записи "Выборки данных оборудования (классы оборудования, модели)" по регистрационному номеру */
  function CMML_GET
  (
    NFLAG_SMART             in number,                 -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)
    NRN                     in number                  -- Регистрационный номер
  ) return                  UDO_T_EQUIPDSCMML%rowtype  -- Запись модели класса оборудования выборки данных
  is
    RES                     UDO_T_EQUIPDSCMML%rowtype; -- Буфер для результата
  begin
    /* Считывание записи */
    begin
      select T.* into RES from UDO_T_EQUIPDSCMML T where T.RN = NRN;
    exception
      when NO_DATA_FOUND then
        PKG_MSG.RECORD_NOT_FOUND(NFLAG_SMART => NFLAG_SMART, NDOCUMENT => NRN, SUNIT_TABLE => 'UDO_T_EQUIPDSCMML');
    end;
    /* Возврат результата */
    return RES;
  end CMML_GET;
  
  /* Поиск "Выборки данных оборудования (классы оборудования, модели)" по задаче */
  procedure CMML_FIND_BY_TASK
  (
    NFLAG_SMART             in number,   -- Признак выдачи сообщения об ошибке (0 - выдавать, 1 - не выдавать)  
    NPRN                    in number,   -- Родитель
    STASK                   in varchar2, -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number,   -- Точность (план)
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Поиск записи */
    begin
      select T.RN
        into NRN
        from UDO_T_EQUIPDSCMML T
       where T.PRN = NPRN
         and T.TASK = STASK
         and T.PRECISION_P = NPRECISION_P;
    exception
      when NO_DATA_FOUND then
        P_EXCEPTION(NFLAG_SMART,
                    'Модель с задачей "%s" и точностью "%s" в классе оборудования "%s" не определёна.',
                    STASK,
                    TO_CHAR(NPRECISION_P),
                    TO_CHAR(NPRN));
    end;
  end CMML_FIND_BY_TASK;
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_INS
  (
    NPRN                    in number,   -- Родитель
    STASK                   in varchar2, -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number,   -- Точность (план)
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Формируем рег. номер */
    NRN := GEN_ID();
    /* Добавляем запись */
    insert into UDO_T_EQUIPDSCMML
      (RN, PRN, TASK, PRECISION_P, PRECISION_F, QUEUE_ID, STATUS, ERR)
    values
      (NRN, NPRN, STASK, NPRECISION_P, null, null, NCMML_STATUS_REGISTERED, null);
  end CMML_INS;
  
  /* Базовое исправление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_UPD
  (
    NRN                     in number,                 -- Регистрационный номер
    STASK                   in varchar2,               -- Задача (см. константы SCMML_TASK_*) */
    NPRECISION_P            in number                  -- Точность (план)
  )
  is
    RREC                    UDO_T_EQUIPDSCMML%rowtype; -- Обрабатываемая запись
  begin
    /* Считаем запись */
    RREC := CMML_GET(NFLAG_SMART => 0, NRN => NRN);
    /* Можно изменять только в статусах: зарегистрирована, при обработке внешней системой произошла ошибка */
    if (RREC.STATUS not in (NCMML_STATUS_REGISTERED, NCMML_STATUS_PROCESS_ERR)) then
      P_EXCEPTION(0,
                  'Модель обрабатывается или уже успешно обработана, изменение невозможно.');
    end if;
    /* Исправим данные */
    update UDO_T_EQUIPDSCMML T
       set T.TASK        = STASK,
           T.PRECISION_P = NPRECISION_P
     where T.RN = NRN;
  end CMML_UPD;
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования, модели)" */
  procedure CMML_DEL
  (
    NRN                     in number                  -- Регистрационный номер
  )
  is
    RREC                    UDO_T_EQUIPDSCMML%rowtype; -- Обрабатываемая запись
  begin
    /* Считаем запись */
    RREC := CMML_GET(NFLAG_SMART => 0, NRN => NRN);
    /* Можно удалять только в статусах: зарегистрирована, успешно обработана внешней системой, при обработке внешней системой произошла ошибка */
    if (RREC.STATUS not in (NCMML_STATUS_REGISTERED, NCMML_STATUS_PROCESSED, NCMML_STATUS_PROCESS_ERR)) then
      P_EXCEPTION(0, 'Модель обрабатывается, удаление невозможно.');
    end if;
    /* Удалим историю */
    for C in (select T.RN from UDO_T_EQUIPDSCMMLH T where T.PRN = NRN)
    loop
      CMMLH_DEL(NRN => C.RN);
    end loop;
    /* Удалим запись */
    delete from UDO_T_EQUIPDSCMML T where T.RN = NRN;
  end CMML_DEL;

  /* Базовая установка фактической точности "Выборки данных оборудования (классы оборудования, модели)" */  
  procedure CMML_SET_PRECISION_F
  (
    NRN                     in number,  -- Регистрационный номер
    NPRECISION_F            in number   -- Точность (факт)
  )
  is
  begin
    /* Установим фактическую точность */
    update UDO_T_EQUIPDSCMML T set T.PRECISION_F = NPRECISION_F where T.RN = NRN;
  end CMML_SET_PRECISION_F;
  
  /* Базовая установка состояния "Выборки данных оборудования (классы оборудования, модели)" */  
  procedure CMML_SET_STATUS
  (
    NRN                     in number,                    -- Регистрационный номер
    NSTATUS                 in number,                    -- Состояние (см. константы NCMML_STATUS_*)
    SQUEUE_ID               in varchar2 := null,          -- Идентификатор очереди обработки
    SERR                    in varchar2 := null           -- Сообщение об ошибке
  )
  is
    SQUEUE_ID_              PKG_STD.TSTRING := SQUEUE_ID; -- Буфер для идентификатора очереди обработки
    SERR_                   PKG_STD.TSTRING := SERR;      -- Буфер для сообщения об ошибке
  begin
    /* Проверим идентификатор очереди */
    if ((NSTATUS in (NCMML_STATUS_PROCESSING, NCMML_STATUS_PROCESSED)) and (SQUEUE_ID_ is null)) then
      P_EXCEPTION(0,
                  'Идентификатор очереди обработки обязателен для перевода модели в состояния "Обрабатывается внешней системой", "Успешно обработана внешней системой".');
    end if;
    /* Проверим сообщение об ошибке */
    if ((NSTATUS in (NCMML_STATUS_PROCESS_ERR)) and (SERR_ is null)) then
      P_EXCEPTION(0,
                  'Текст сообщения об ошибке обязателен для перевода модели в состояние "Ошибка обработки внешней системой".');
    end if;
    /* Удалим идентификатор очереди обработки и сообщение об ошибке для тех статусов, где они не нужны */
    if (NSTATUS not in (NCMML_STATUS_PROCESSING, NCMML_STATUS_PROCESSED)) then
      SQUEUE_ID_ := null;
    end if;
    if (NSTATUS not in (NCMML_STATUS_PROCESS_ERR)) then
      SERR_ := null;
    end if;
    /* Установим состояние и сопутствующие ему атрибуты */
    update UDO_T_EQUIPDSCMML T
       set T.STATUS   = NSTATUS,
           T.QUEUE_ID = SQUEUE_ID_,
           T.ERR      = SERR_
     where T.RN = NRN;
  end CMML_SET_STATUS;
  
  /* Формирование наименования для задачи "Выборки данных оборудования (классы оборудования, модели)" */
  function CMML_TASK_NAME
  (
    STASK                   in varchar2 -- Задача (см. константы SCMML_TASK_*) */
  ) return                  varchar2    -- Наименование задачи
  is
  begin
    case STASK
      when SCMML_TASK_TCF then
        return 'Оценка технического состояния';
      when SCMML_TASK_RUL then
        return 'Прогноз остаточного ресурса';
      when SCMML_TASK_FP then
        return 'Прогноз отказа';
      else
        return 'Вид задачи оценки не поддерживается';
    end case;
  end CMML_TASK_NAME;
  
  /* Формирование подсказки для задачи "Выборки данных оборудования (классы оборудования, модели)" */
  function CMML_TASK_HINT
  return                    varchar2    -- Подсказка для задачи
  is
  begin
    return '<b>TCF</b> - ' || CMML_TASK_NAME(STASK => SCMML_TASK_TCF) || ' (<b>T</b>echnical <b>C</b>ondition <b>F</b>orecast)<br>' ||
           '<b>RUL</b> - ' || CMML_TASK_NAME(STASK => SCMML_TASK_RUL) || ' (<b>R</b>emaining <b>U</b>seful <b>L</b>ife)<br>' ||
           '<b>FP</b> - ' || CMML_TASK_NAME(STASK => SCMML_TASK_FP) || ' (<b>F</b>ailure <b>P</b>redict)';
  end CMML_TASK_HINT;
  
  /* Вычисление вероятности выхода из строя на дату по RUL-прогнозу */  
  function CMML_RUL_BREAKDOWN_PROB
  (
    NFORECAST               in number,       -- RUL-прогноз (интервалов до перехода в предельное состояние)
    DFORECAST_DATE          in date,         -- Дата прогноза
    DDATE                   in date          -- Дата на
  ) return                  number           -- Значение вероятности
  is
    NRES                    PKG_STD.TNUMBER; -- Буфер для результата
  begin
    /* Проверим параметры */
    if ((NFORECAST is null) or (DFORECAST_DATE is null) or (DDATE is null) or (DDATE < DFORECAST_DATE) or
       (DFORECAST_DATE > sysdate) or (DDATE < sysdate)) then
      return null;
    end if;
    /* Проверяем пограничные значения */
    if (NFORECAST = 0) or ((DDATE - sysdate) = 0) then
      return 100;
    end if;
    if (sysdate + NFORECAST > DDATE) then
      return 0;
    end if;
    /* Вычисляем */
    NRES := 100 - ROUND((NFORECAST - (TRUNC(sysdate) - TRUNC(DFORECAST_DATE))) / (DDATE - sysdate) * 100);
    /* Корректируем флуктуации */
    if (NRES > 100) then
      NRES := 100;
    end if;
    if (NRES < 0) then
      NRES := 0;
    end if;
    /* Возвращаем результат */
    return NRES;
  end CMML_RUL_BREAKDOWN_PROB;
  
  /* Базовое добавление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
  procedure CMMLH_INS
  (
    NPRN                    in number,   -- Родитель
    NEQCONFIG               in number,   -- Рег. номер технического объекта
    SRQ_AUTHID              in varchar2, -- Пользователь, выполнивший запрос
    DRQ_DATE                in date,     -- Дата/время запроса
    BRQ                     in blob,     -- Параметры запроса
    NRN                     out number   -- Регистрационный номер
  )
  is
  begin
    /* Формируем рег. номер */
    NRN := GEN_ID();
    /* Добавляем запись */
    insert into UDO_T_EQUIPDSCMMLH
      (RN, PRN, EQCONFIG, RQ_AUTHID, RQ_DATE, RQ, FORECAST, EXSQUEUE)
    values
      (NRN, NPRN, NEQCONFIG, SRQ_AUTHID, DRQ_DATE, BRQ, null, null);
  end CMMLH_INS;
  
  /* Базовое удаление "Выборки данных оборудования (классы оборудования, модели, история запросов)" */
  procedure CMMLH_DEL
  (
    NRN                     in number   -- Регистрационный номер
  )
  is
  begin
    /* Удалим запись */
    delete from UDO_T_EQUIPDSCMMLH T where T.RN = NRN;
  end CMMLH_DEL;
  
  /* Базовая установка данных прогноза "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */  
  procedure CMMLH_SET_FORECAST
  (
    NRN                     in number,  -- Регистрационный номер
    BFORECAST               in blob     -- Данные прогноза
  )
  is
  begin
    /* Установим данные ответа */
    update UDO_T_EQUIPDSCMMLH T set T.FORECAST = BFORECAST where T.RN = NRN;
  end CMMLH_SET_FORECAST;
  
  /* Базовая установка идентификатора очереди обмена "Выборки данных оборудования (классы оборудования, файлы данных, история запросов)" */  
  procedure CMMLH_SET_EXSQUEUE
  (
    NRN                     in number,  -- Регистрационный номер
    NEXSQUEUE               in number   -- Идентификатор очереди обмена
  )
  is
  begin
    /* Установим идентификатор очереди обмена */
    update UDO_T_EQUIPDSCMMLH T set T.EXSQUEUE = NEXSQUEUE where T.RN = NRN;
  end CMMLH_SET_EXSQUEUE;

end UDO_PKG_EQUIPDS_BASE;
/
