Это старая версия документа.


Автоматические устанавливаемые резервы

Дополнительная доработка функционала вызвана тем, что:

  1. Практически для всех докторов необходимо выставлять веб-резерв, для возможности записи пациентов через сайт (и др. внешние источники) и инфокиоск.
  2. Необходимо выставлять резерв на все доступное свободное время, одним интервалом.
    если выставлять несколькими - запись на услуги, которые требуют больше отведенного времени будет не возможна
  3. Необходима возможность выставить резерв на первый и/или последний интервал работы доктора, без привязки ко времени.

Справочники

Правила задания при автоматической постановке резервов задается через Классификатор НСИ. Классификатор содержит 3 справочника:

  1. «Автоматическое добавление резервов [-10010088]»
  2. «Автоматическое добавление резервов. Ограничения [-10010087]»
  3. «Автоматическое добавление резервов. Ограничения. Справ [-10010086]»

Резервы

Название Соответствие таблицы
DICINFO
Назначение
IDdicid
Резервrekvint1резерв (schedmarks)
СортировкаdicorderУказывается порядок применения резервов к расписанию
филиалrekvint2Указание в каком филиале применяется постановка резерва.
Если резерв применяется в частифилиалов, то указывается «Во всех» и дополнительно настраиваются ограничения
Кратно интерваламrekvint4Признак. Размер времени установки резерва будет кратен интервалу в расписании доктора
Интервалrekvint5Указание интервала постановки, если он не привязан ко времени (перв, посл)
время
постановки
резерва
час началаrekvint6
мин началаrekvint7
час окончанияrekvint8
мин окончанияrekvint9
На все времяrekvint3Признак. Резерв ставится на все возможное свободное время
Применять, если рабочее время более …rekvint10
Не применять после …disdateДата окончания действия правила для установки резерва. После указанной даты правило не применяется

Ограничения

Название Соответствие таблицы
DICINFO
Назначение
идентификатор записиdicid
резервparentdicidУказатель на резерв DICINFO.DICID
тип ограниченияrekvint3Идентификатор типа ограничения. Идентификатор вычисляется от абсолютного числа, при этом, положительный идентификатор обозначает разрешающее ограничение, отрицательный - запрещающее
значение ограниченияrekvint1Указывается идентификатор из соответствующей таблицы, для его разрешения/запрещения применения к установке данного резерва.
Например, для ограничения по филиалам используется таблица FILIALS и идентификаторы филиалов берутся оттуда

Типы ограничений

Название Соответствие таблицы
DICINFO
идентификатор записиdicid
тип ограниченияrekvint3
назначение типа ограниченияsimplename

Отчетность по резервам

Для компоновки данные по устанавливаемому резерву и накладываемым на него ограничениям сформирована отчетная форма.
Отчетная форма расположена в генераторе отчетов, с названием «АвтоРезервы расписания».

Триггер

CREATE OR ALTER TRIGGER USER$DOCTSHEDULE_RESERVE_SET FOR DOCTSHEDULE
active after INSERT POSITION 5
AS
BEGIN
  IF (NEW.daytype=1 AND NEW.schedtype=1 AND
      EXISTS(SELECT * FROM repl$getaccess WHERE repl$access = 'USER')) THEN
  BEGIN
    EXECUTE PROCEDURE USER$schedule_reserve_set(NEW.schedident);
  END
END

Процедура

CREATE OR ALTER PROCEDURE USER$SCHEDULE_RESERVE_SET
(
  SCHEDIDENT TYPE OF COLUMN DOCTSHEDULE.SCHEDIDENT
)
AS
DECLARE a_btime TICODE;
DECLARE a_ftime TICODE;
-- данные по графику
DECLARE filial TYPE OF COLUMN doctshedule.filial;
DECLARE rzd TYPE OF COLUMN razdel.razdid;
DECLARE depnum TYPE OF COLUMN doctshedule.depnum;
DECLARE dcode TYPE OF COLUMN doctshedule.dcode;
DECLARE chair TYPE OF COLUMN doctshedule.chair;
DECLARE weeknum INT;
DECLARE wdate TYPE OF COLUMN doctshedule.wdate;
DECLARE ds_btime TICODE;
DECLARE ds_ftime TICODE;
DECLARE shinterv TYPE OF COLUMN doctshedule.shinterv;
--
DECLARE restricted INT;
-- данные по резерву
DECLARE rsid TYPE OF COLUMN dicinfo.dicid;
DECLARE tmstatus TYPE OF COLUMN dicinfo.rekvint1;
DECLARE shinterv_krat TYPE OF COLUMN dicinfo.rekvint4;
DECLARE rs_btime TICODE;
DECLARE rs_ftime TICODE;
DECLARE interv TYPE OF COLUMN dicinfo.rekvint5;
DECLARE all_free_time TYPE OF COLUMN dicinfo.rekvint3;
DECLARE enable_by_hour_more TYPE OF COLUMN dicinfo.rekvint10;
-- данные по расписанию
DECLARE sc_btime TICODE;
DECLARE sc_ftime TICODE;
-- процедура поиска свободного времени
DECLARE PROCEDURE prc_freetime (
  schedident TYPE OF COLUMN DOCTSHEDULE.SCHEDIDENT
)
RETURNS (
  btime TICODE,
  ftime TICODE
)
AS
DECLARE obtime TICODE;
DECLARE ftimen TICODE;
BEGIN
  obtime = 0;
  FOR SELECT bhour*60+bmin, fhour*60+fmin,
             lead(bhour*60+bmin) OVER (ORDER BY bhour*60+bmin)
        FROM SCHED_INTERVALS(:schedident, 0)
       WHERE atype IN (4,5)
  INTO btime,ftime,ftimen do
  BEGIN
    IF (ftime = ftimen) THEN
    BEGIN
      IF (obtime = 0) THEN
        obtime = btime;
    END
    ELSE
    BEGIN
      IF (obtime != 0) THEN
        btime = obtime;
      obtime = 0;
      suspend;
    END
  END
END
--  end procedure               prc_freetime
-- функция проверки общих ограничений
DECLARE FUNCTION prc_restrict_all (
  -- время предполагаемого резерва
  btime INT,
  ftime INT,
  -- время по графику работы
  ds_btime INT,
  ds_ftime INT,
  -- время по авто-резерву
  rs_btime INT,
  rs_ftime INT,
  enable_by_hour_more INT
)
RETURNS INTEGER
AS
DECLARE restricted INT;
BEGIN
  restricted = 0;
  IF (btime = ftime) THEN
    restricted = 1;
  IF (btime IS NULL OR ftime IS NULL) THEN
    restricted = 1;
  IF (COALESCE(enable_by_hour_more,0)>0 AND ds_ftime-ds_btime<enable_by_hour_more*60) THEN
    restricted = 1;
  --
  RETURN restricted;
END
--  end function                prc_restrict_all
-- функция проверки заданных ограничений
DECLARE FUNCTION prc_restrict (
  rsid   TYPE OF COLUMN dicinfo.dicid,
  filial TYPE OF COLUMN filials.filid,
  rzdid  TYPE OF COLUMN razdel.razdid,
  depnum TYPE OF COLUMN departments.depnum,
  dcode  TYPE OF COLUMN doctor.dcode,
  chid   TYPE OF COLUMN chairs.chid,
  weeknum INT,
  btime INT,
  ftime INT
)
RETURNS INTEGER
AS
DECLARE restricted INT;
DECLARE cur_type INT;
DECLARE cur_val INT;
--
DECLARE cur cursor FOR (SELECT
         sign(SUM(CASE WHEN rekvint3>0 THEN 1 ELSE 0 END)) exists_allow,
         sign(SUM(CASE WHEN rekvint3<0 THEN 1 ELSE 0 END)) exists_deny,
         sign(SUM(CASE WHEN rekvint3>0 AND rekvint1= :cur_val THEN 1 ELSE 0 END)) is_allow,
         sign(SUM(CASE WHEN rekvint3<0 AND rekvint1= :cur_val THEN 1 ELSE 0 END)) is_deny
    FROM dicinfo rd
   WHERE rd.refid=-10010087 AND rd.parentdicid = :rsid AND abs(rd.rekvint3) = :cur_type );
--
BEGIN
  restricted = 0;
  /* правила в ограничениях:
        явное разрешение                            allow
        явное запрещение                            deny
        есть разрешения, но данное не разрешено     deny
        есть зпрещения, но данное не запрещено      allow
  */
  -- филиал           [1]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 1;
    cur_val = filial;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- раздел медицины  [2]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 2;
    cur_val = rzdid;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- отделение        [3]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 3;
    cur_val = depnum;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- доктор           [4]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 4;
    cur_val = dcode;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- кресло           [5]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 5;
    cur_val = chid;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- день недели      [6]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 6;
    cur_val = weeknum;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- час начала       [8]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 8;
    cur_val = btime/60;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  -- час окончания    [9]
  IF (restricted = 0) THEN
  BEGIN
    cur_type = 9;
    cur_val = ftime/60;
    OPEN cur;
    fetch NEXT FROM cur;
    IF ((cur.is_deny = 1) OR (cur.exists_allow = 1 AND cur.is_allow != 1)) THEN
      restricted = 1;
    close cur;
  END
  --
  RETURN restricted;
END
--  end function                prc_restrinct
-- функция задания резерва
DECLARE FUNCTION prc_newrec (
  schedident   TYPE OF COLUMN schedule.schedident,
  filial TYPE OF COLUMN filials.filid,
  dcode  TYPE OF COLUMN doctor.dcode,
  chid   TYPE OF COLUMN chairs.chid,
  wdate  TYPE OF COLUMN schedule.workdate,
  btime INT,
  ftime INT,
  tmstatus  TYPE OF COLUMN schedule.tmstatus
)
RETURNS INTEGER
AS
DECLARE restricted INT;
DECLARE spresult INT;
DECLARE bhour INT;
DECLARE bmin INT;
DECLARE fhour INT;
DECLARE fmin INT;
DECLARE uid TYPE OF COLUMN doctor.dcode;
BEGIN
  bhour = btime/60;
  bmin  = btime-(btime/60)*60;
  fhour = ftime/60;
  fmin  = ftime-(ftime/60)*60;
  uid = rdb$get_context('USER_SESSION', 'USER_ID');
  --
  SELECT schedid FROM schednewrec (:dcode, :wdate, :chid, :filial,
         :bhour, :bmin, :fhour, :fmin, NULL, :uid, NULL, :tmstatus,
         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
         EXTRACT(HOUR FROM CURRENT_TIMESTAMP), 'now', NULL, NULL, NULL, 1,
         :filial, NULL, NULL, NULL, :schedident, 0, NULL, NULL, NULL, NULL)
    INTO :spresult;
  --
  RETURN 0;
END
--  end function                prc_newrec
BEGIN
  /* описание структуры:
            резервы
        dicid       идентификатор записи
        refid       идентификатор справочника в системе
        dicorder    порядок применения
        disdate     дата отмены действия
        rekvint1    резерв (schedmarks)
        rekvint2    филиал
        rekvint3    признак: на все свободное время
        rekvint4    признак: кратно интервалам
        rekvint5    признак интервал постановки (перв, посл)
        rekvint6    время постановки резерва: час начала
        rekvint7                              мин начала
        rekvint8                              час окончания
        rekvint9                              мин окончания
        rekvint10   применять, если график более чем ... часов
            ограничения
        dicid       идентификатор записи
        refid       идентификатор справочника в системе
        parentdicid идентификатор записи резерва
        rekvint3    тип ограничения ("+" разр / "-" запр)
        rekvint1    значение ограничения
            справочник типов ограничений
        dicid       идентификатор записи
        refid       идентификатор справочника в системе
        rekvint3    тип ограничения
        simplename  назначение типа ограничения
 
  */
  -- получаем данные
  SELECT ds.filial, dep.razdel, ds.depnum, ds.dcode, ds.chair, EXTRACT(weekday FROM ds.wdate) week,
         ds.wdate,ds.beghour*60+ds.begmin,ds.endhour*60+ds.endmin,ds.shinterv
    FROM doctshedule ds
    LEFT JOIN departments dep ON dep.depnum= ds.depnum
   WHERE ds.schedident = :schedident
    INTO filial,rzd,depnum,dcode,chair,weeknum,wdate,ds_btime,ds_ftime,shinterv;
 
  IF (rzd IS NOT NULL) THEN
  BEGIN
    -- смотрим возможные резервы
    FOR SELECT dicid,rekvint1,rekvint4,rekvint5,rekvint3,rekvint10,rekvint6*60+rekvint7,rekvint8*60+rekvint9
          FROM dicinfo r
         WHERE r.refid=-10010088 AND :filial = COALESCE(r.rekvint2, :filial) AND COALESCE(disdate,:wdate)>= :wdate
         ORDER BY dicorder
    INTO rsid,tmstatus,shinterv_krat,interv,all_free_time,enable_by_hour_more,rs_btime,rs_ftime do
    BEGIN
      a_btime = NULL;
      a_ftime = NULL;
 
      -- проверяем время + корректируем время
      -- на первый интервал
      IF (interv = 1) THEN
      BEGIN
        SELECT FIRST 1 btime, ftime FROM prc_freetime(:schedident) ORDER BY btime ASC
          INTO a_btime, a_ftime;
        IF (shinterv_krat=1) THEN
        BEGIN
          a_ftime = minvalue(a_ftime, a_btime+shinterv);
        END
        ELSE
        BEGIN
          a_ftime = minvalue(a_ftime, COALESCE(rs_ftime,0));
        END
        -- проверяем общие ограничения
        restricted = prc_restrict_all(:a_btime,:a_ftime,:ds_btime,:ds_ftime,:rs_btime,:rs_ftime,:enable_by_hour_more);
        -- проверяем ограничения на резерв
        IF (restricted = 0) THEN
          restricted = prc_restrict(:rsid,:filial,:rzd,:depnum,:dcode,:chair,:weeknum,:a_btime,:a_ftime);
        -- ставим резерв
        IF (restricted = 0) THEN
          restricted = prc_newrec(:schedident,:filial,:dcode,:chair,:wdate,:a_btime,:a_ftime,:tmstatus);
      END
 
      -- на последний интервал
      ELSE IF (interv = -1) THEN
      BEGIN
        SELECT FIRST 1 btime, ftime FROM prc_freetime(:schedident) ORDER BY btime DESC
          INTO a_btime, a_ftime;
        IF (shinterv_krat=1) THEN
        BEGIN
          a_btime = maxvalue(a_btime, a_ftime-shinterv);
        END
        ELSE
        BEGIN
          a_btime = maxvalue(a_btime, COALESCE(rs_btime,0));
        END
        -- проверяем общие ограничения
        restricted = prc_restrict_all(:a_btime,:a_ftime,:ds_btime,:ds_ftime,:rs_btime,:rs_ftime,:enable_by_hour_more);
        -- проверяем ограничения на резерв
        IF (restricted = 0) THEN
          restricted = prc_restrict(:rsid,:filial,:rzd,:depnum,:dcode,:chair,:weeknum,:a_btime,:a_ftime);
        -- ставим резерв
        IF (restricted = 0) THEN
          restricted = prc_newrec(:schedident,:filial,:dcode,:chair,:wdate,:a_btime,:a_ftime,:tmstatus);
      END
 
      -- указано время постановки
      ELSE IF (COALESCE(rs_btime,0)>0 AND COALESCE(rs_ftime,0)>0) THEN
      BEGIN
        -- время резерва за пределами графика работы
        IF (rs_ftime <= ds_btime OR rs_btime>=ds_ftime) THEN
        BEGIN
          continue;
        END
 
        -- время резерва попадает в график (?частично)
        ELSE
        BEGIN
          FOR SELECT btime, ftime FROM prc_freetime(:schedident)
               WHERE NOT (btime > :rs_ftime OR ftime < :rs_btime)
          INTO a_btime, a_ftime do
          BEGIN
            restricted = 0;
            a_btime = maxvalue(a_btime, rs_btime);
            a_ftime = minvalue(a_ftime, rs_ftime);
 
            -- проверяем общие ограничения
            restricted = prc_restrict_all(:a_btime,:a_ftime,:ds_btime,:ds_ftime,:rs_btime,:rs_ftime,:enable_by_hour_more);
            -- проверяем ограничения на резерв
            IF (restricted = 0) THEN
              restricted = prc_restrict(:rsid,:filial,:rzd,:depnum,:dcode,:chair,:weeknum,:a_btime,:a_ftime);
            -- ставим резерв
            IF (restricted = 0) THEN
              restricted = prc_newrec(:schedident,:filial,:dcode,:chair,:wdate,:a_btime,:a_ftime,:tmstatus);
            --
          END
        END
      END
 
      -- на все свободное
      ELSE IF (all_free_time=1) THEN
      BEGIN
        -- при этом пункте игнорируем все остальные настройки, кроме ограничений
        FOR SELECT btime, ftime FROM prc_freetime(:schedident)
        INTO a_btime, a_ftime do
        BEGIN
          -- проверяем общие ограничения
          restricted = prc_restrict_all(:a_btime,:a_ftime,:ds_btime,:ds_ftime,:rs_btime,:rs_ftime,:enable_by_hour_more);
          -- проверяем ограничения на резерв
          IF (restricted = 0) THEN
            restricted = prc_restrict(:rsid,:filial,:rzd,:depnum,:dcode,:chair,:weeknum,:a_btime,:a_ftime);
          -- ставим резерв
          IF (restricted = 0) THEN
            restricted = prc_newrec(:schedident,:filial,:dcode,:chair,:wdate,:a_btime,:a_ftime,:tmstatus);
        END
      END
      ELSE
      BEGIN
        -- не указано нормально варианта постановки
        continue;
      END
    END
  END
END

расширенная.настройка/расписание/резервы.1533134275.txt.gz · Последние изменения: 2018/08/01 17:37 (внешнее изменение)