Блокировка периода (постановка)

Материал из GedeminWiki
(Различия между версиями)
Перейти к: навигация, поиск
 
(не показаны 42 промежуточные версии 2 участников)
Строка 1: Строка 1:
Изначально, блокировка периода распространялась на все документы и всех пользователей системы. Позже, была добавлена возможность исключить некоторые группы пользователей из блокировки и, наконец, мы добавили возможность исключать некоторые типы документов.
+
Кто-то, что-то, где-то может изменить и это большая проблема для базы данных. Хорошо, если расхождение обнаружено по горячим следам, а если прошло несколько месяцев? Если неверные данные привели к неверным расчетам по налогам?
  
=== Существующий механизм блокировки периода ===
+
Изначально, в Гедымине мы предусмотрели простой механизм блокировки на триггерах:
  
За определение: подпадает конкретный тип под блокировку или нет, отвечает процедура [[gd_p_exclude_block_dt]], которая возвращает 1, если переданный идентификатор типа документа не блокируется и 0 в противном случае. Процедура формируется в окне [[Tgd_dlgOptions]] при выборе типов документов исключаемых из блокировки. Системными составляющими механизма блокировки периода являются генераторы [[gd_g_block]] и [[gd_g_block_group]]. Первый хранит дату, до которой документы считаются заблокированными, а второй -- битовую маску групп пользователей, на которых распространяется блокировка. Механизм реализуется с помощью 12 триггеров, по три на каждую из четырех таблиц: [[gd_document]], [[ac_entry]], [[ac_record]] и [[inv_movement]]. Существующий триггер блокировки периода выглядит следующим образом:
+
* Защищались только четыре основных таблицы: документы, проводки и складское движение.
 +
* Защита управлялась единственным параметром: датой, до которой блокировались все изменения.
  
 +
Позже, мы добавили возможность указать группы пользователей, на которых распространяется блокировка, и список типов документов.
  
На сегодняшний день у некоторых из наших клиентов возникла необходимость устанавливать разные периоды блокировки для разных типов документов. Предлагается модифицировать механизм блокировки следующим образом:
+
Такие возможности не удовлетворяют текущим потребностям наших клиентов. Необходим следующий функционал:
 +
 
 +
* Управление доступом не только к документам/проводкам, но и к любым данным (таблицам). Например, запретить пользователю менять справочник клиентов или товаров.
 +
* Условное разграничение доступа к записям таблицы на основе данных. Например, запретить пользователю менять клиентов только из Брестской области, или запретить создавать складские документы с товаром из группы Спецтовары, или запретить менять документы, которые приводят к созданию/изменению проводок по 20-му счету. При этом, при вычислении правила можно обращаться к:
 +
** Полям таблицы
 +
** Полям связанных таблиц
 +
** Встроенным функциям (например CURRENT_DATE)
 +
** Глобальным переменным
 +
** На поля типа дата (частный случай -- дата документа или дата проводки) могут накладываться условия: за n дней (например, запретить редактирование документов старше 30 дней), до 1 числа текущего месяца, до 1 числа предыдущего месяца, до 1 числа квартала, года и т.п.
 +
* Разграничение доступа для всех, групп пользователей, списка учетных записей, единственной учетной записи.
 +
* Разграничение доступа по времени суток. Например, запретить создание накладных вне рабочего дня с 8:00 до 17:00.
 +
* Разграничение доступа по компьютеру (ip адресу). Например, создание платежных документов только с рабочего место ответственного бухгалтера.
 +
* Разграничение доступа к отдельным полям.
 +
* Правила доступа должны быть бизнес-объектами и переноситься с базы на базу посредством ПИ.
 +
* Блокировка должна быть реализована на уровне БД посредством триггеров.
 +
 
 +
Приведем несколько наиболее востребованных типовых сценариев ограничения доступа к данным:
 +
 
 +
* Бухгалтерия закрывает месяц и считает налоги до 20-го числа следующего месяца. После этой даты документы должны быть заблокированы на изменение.
 +
* Зарплата начисляется до 10-го числа последующего месяца. После этой даты изменение в документах прошлого периода должно быть запрещено.
 +
* Оператор, принимающий заявки на отгрузку готовой продукции, должен иметь возможность редактировать заявки только в течение одной своей рабочей смены.
 +
* Сотрудник сырьевого отдела может изменять данные в справочнике клиентов только для записей, входящих в папку Поставщики.
 +
* и т.п.
 +
 
 +
Ниже представлены эскизы и предварительные наброски по системе блокировки и разграничения:
  
 
=== Интерфейс пользователя ===
 
=== Интерфейс пользователя ===
  
Изменение параметров блокировки возможно только под учетной записью [[Administrator]]. Если зашли под другой учетной записью, то скрываем все и пишем пояснительное сообщение.
+
Ниже приведен вариант организации пользовательского интерфейса:
  
Предусмотрим чек-бокс "Блокировка включена". Если он выключен, то больше в разделе ничего не показывается. Если включен, то появляется два чек-бокса и таблица с тремя колонками. Высота строк таблицы не фиксирована и зависит от содержимого первой и третей колонок. Чек-боксы:
+
http://gsbelarus.com/gs/images/gs/2007/block.png
* '''Для всех типов документов'''. Если установлен, то в таблице отображается только одна строка, причем в первой колонке выводится надпись "Все".
+
 
* '''Для всех групп пользователей'''. Если установлен, то в таблице третью колонку редактировать нельзя и в ней выводится надпись "Все".
+
* '''Типы документов'''. Вверху клетки находится группа радиокнопок: Все, Указанные, Кроме указанных. Под ними отображается список наименований типов документов через запятую. В правой части ячейки находится кнопка "..." для выбора типов документов (изменения списка).  
Таблица:
+
 
* '''Тип документа'''. Содержит список наименований типов документов через запятую. В правой части находится кнопка "..." для выбора типов документов.  
+
* '''Дата блокировки'''. Дата, до которой будут заблокированы документы указанных типов. При сравнении дат действует операция строгого неравенства меньше, т.е. сам указанный день блокировки не включается в период блокировки. Можно вводить как фиксированную дату, так и относительную.
* '''Дата блокировки'''. Дата, до которой будут заблокированы документы. Действует операция меньше. т.е. сам указанный день блокировки не включается в период блокировки. Кроме ввода непосредственных дат можно воспользоваться метапеременными:
+
 
** Месяц -- первое число текущего месяца;
+
* '''Блокировка распространяется на группы пользователей'''. Вверху клетки находится группа радиокнопок: Все, Указанные, Кроме указанных. Под ними выводится строкой, через запятую список групп пользователей. Справа выводится кнопка "...", которая позволяет открыть окно для изменения списка.  
** ПредМесяц -- первое число предыдущего месяца;
+
 
** Квартал -- первое число текущего квартала;
+
Возможно, для отображения таблицы стоит использовать компонент [[TScrollBox]], на котором в зависимости от выбора пользователя динамически располагать компоненты.
** ПредКвартал -- первое число предыдущего квартала;
+
 
** Год -- первое число текущего года;
+
=== Хранение информации о блокировке ===
** ПредГод -- первое число предыдущего года.
+
 
* '''Группы пользователей'''. Выводится строкой, через запятую список групп пользователей, на которых распространяется блокировка. Справа выводится кнопка "...", которая позволяет открыть окно для изменения списка.
+
Информацию о параметрах блокировки планируется хранить в таблице [[GD_BLOCK_RULE]].
Возможно, для этих целей стоит использовать компонент [[TListView]].
+
  
 
=== Метаданные ===
 
=== Метаданные ===
  
  
 +
  CREATE PROCEDURE gd_p_block (DocDate DATE, DocType INTEGER)
 +
  AS
 +
    DECLARE VARIABLE IG INTEGER;
 +
  BEGIN
 +
 +
    ...
 +
   
 +
    // такой блок кода повторяется для каждой группы типов документов
 +
    IF (DocType IN (12345, 67890, ...)) THEN
 +
    BEGIN
 +
      // если блокировка распространяется на все группы
 +
      // пользователей без исключений, то проверим дату
 +
      // и, при нарушении, вызовем исключение
 +
      IF (DocDate < date `01.01.2001`) THEN
 +
        EXCEPTION gd_e_block;
 +
 +
      // если указаны группы, на которые не распространяется блокировка,
 +
      // сначала проверяем дату, а затем не попадает ли пользователь
 +
      // в список исключенных групп
 +
      IF (DocDate < date `01.01.2001`) THEN
 +
      BEGIN
 +
        SELECT ingroup FROM gd_user WHERE ibname = CURRENT_USER
 +
          INTO :IG;
 +
        IF (BIN_AND(12345, :IG) = 0) THEN
 +
          EXCEPTION gd_e_block;
 +
      END
 +
 +
      // для ФБ 2.0 можно попробовать избежать лишних чтений из таблицы
 +
      // и кэшировать значение битовой маски в контекстной переменной
 +
      IF (DocDate < date `01.01.2001`) THEN
 +
      BEGIN
 +
        IF (RDB$GET_CONTEXT(`USER_SESSION`, `INGROUP`) = ``) THEN
 +
        BEGIN
 +
          SELECT ingroup FROM gd_user WHERE ibname = CURRENT_USER
 +
            INTO :IG;
 +
          RDB$SET_CONTEXT(`USER_SESSION`, `INGROUP`, :IG);
 +
        END ELSE       
 +
          IG = RDB$GET_CONTEXT(`USER_SESSION`, `INGROUP`);
 +
 +
        IF (BIN_AND(12345, :IG) = 0) THEN
 +
          EXCEPTION gd_e_block;
 +
      END
 +
 +
      // если при задании условия блокировки использовались метапеременные
 +
      // то вычисляем соответствующую им дату. Например, задана переменная
 +
      // ПредМесяц
 +
      M = EXTRACT(MONTH FROM CURRENT_DATE) - 1;
 +
      IF (M = 0) THEN M = 12;
 +
      IF (DocDate < CAST('01.' || M || '.' || EXTRACT(YEAR FROM CURRENT_DATE) AS DATE)) THEN
 +
        EXCEPTION gd_e_block;
 +
 +
    END
 +
 +
    ...
 +
  END
  
 
[[Category:Постановка]]
 
[[Category:Постановка]]
 +
 +
__NOTOC__

Текущая версия на 18:42, 17 октября 2017

Кто-то, что-то, где-то может изменить и это большая проблема для базы данных. Хорошо, если расхождение обнаружено по горячим следам, а если прошло несколько месяцев? Если неверные данные привели к неверным расчетам по налогам?

Изначально, в Гедымине мы предусмотрели простой механизм блокировки на триггерах:

  • Защищались только четыре основных таблицы: документы, проводки и складское движение.
  • Защита управлялась единственным параметром: датой, до которой блокировались все изменения.

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

Такие возможности не удовлетворяют текущим потребностям наших клиентов. Необходим следующий функционал:

  • Управление доступом не только к документам/проводкам, но и к любым данным (таблицам). Например, запретить пользователю менять справочник клиентов или товаров.
  • Условное разграничение доступа к записям таблицы на основе данных. Например, запретить пользователю менять клиентов только из Брестской области, или запретить создавать складские документы с товаром из группы Спецтовары, или запретить менять документы, которые приводят к созданию/изменению проводок по 20-му счету. При этом, при вычислении правила можно обращаться к:
    • Полям таблицы
    • Полям связанных таблиц
    • Встроенным функциям (например CURRENT_DATE)
    • Глобальным переменным
    • На поля типа дата (частный случай -- дата документа или дата проводки) могут накладываться условия: за n дней (например, запретить редактирование документов старше 30 дней), до 1 числа текущего месяца, до 1 числа предыдущего месяца, до 1 числа квартала, года и т.п.
  • Разграничение доступа для всех, групп пользователей, списка учетных записей, единственной учетной записи.
  • Разграничение доступа по времени суток. Например, запретить создание накладных вне рабочего дня с 8:00 до 17:00.
  • Разграничение доступа по компьютеру (ip адресу). Например, создание платежных документов только с рабочего место ответственного бухгалтера.
  • Разграничение доступа к отдельным полям.
  • Правила доступа должны быть бизнес-объектами и переноситься с базы на базу посредством ПИ.
  • Блокировка должна быть реализована на уровне БД посредством триггеров.

Приведем несколько наиболее востребованных типовых сценариев ограничения доступа к данным:

  • Бухгалтерия закрывает месяц и считает налоги до 20-го числа следующего месяца. После этой даты документы должны быть заблокированы на изменение.
  • Зарплата начисляется до 10-го числа последующего месяца. После этой даты изменение в документах прошлого периода должно быть запрещено.
  • Оператор, принимающий заявки на отгрузку готовой продукции, должен иметь возможность редактировать заявки только в течение одной своей рабочей смены.
  • Сотрудник сырьевого отдела может изменять данные в справочнике клиентов только для записей, входящих в папку Поставщики.
  • и т.п.

Ниже представлены эскизы и предварительные наброски по системе блокировки и разграничения:

[править] Интерфейс пользователя

Ниже приведен вариант организации пользовательского интерфейса:

block.png

  • Типы документов. Вверху клетки находится группа радиокнопок: Все, Указанные, Кроме указанных. Под ними отображается список наименований типов документов через запятую. В правой части ячейки находится кнопка "..." для выбора типов документов (изменения списка).
  • Дата блокировки. Дата, до которой будут заблокированы документы указанных типов. При сравнении дат действует операция строгого неравенства меньше, т.е. сам указанный день блокировки не включается в период блокировки. Можно вводить как фиксированную дату, так и относительную.
  • Блокировка распространяется на группы пользователей. Вверху клетки находится группа радиокнопок: Все, Указанные, Кроме указанных. Под ними выводится строкой, через запятую список групп пользователей. Справа выводится кнопка "...", которая позволяет открыть окно для изменения списка.

Возможно, для отображения таблицы стоит использовать компонент TScrollBox, на котором в зависимости от выбора пользователя динамически располагать компоненты.

[править] Хранение информации о блокировке

Информацию о параметрах блокировки планируется хранить в таблице GD_BLOCK_RULE.

[править] Метаданные

 CREATE PROCEDURE gd_p_block (DocDate DATE, DocType INTEGER)
 AS
   DECLARE VARIABLE IG INTEGER;
 BEGIN

   ...
   
   // такой блок кода повторяется для каждой группы типов документов
   IF (DocType IN (12345, 67890, ...)) THEN
   BEGIN
     // если блокировка распространяется на все группы
     // пользователей без исключений, то проверим дату
     // и, при нарушении, вызовем исключение
     IF (DocDate < date `01.01.2001`) THEN
       EXCEPTION gd_e_block;

     // если указаны группы, на которые не распространяется блокировка, 
     // сначала проверяем дату, а затем не попадает ли пользователь
     // в список исключенных групп
     IF (DocDate < date `01.01.2001`) THEN
     BEGIN
       SELECT ingroup FROM gd_user WHERE ibname = CURRENT_USER
         INTO :IG;
       IF (BIN_AND(12345, :IG) = 0) THEN
         EXCEPTION gd_e_block;
     END

     // для ФБ 2.0 можно попробовать избежать лишних чтений из таблицы
     // и кэшировать значение битовой маски в контекстной переменной
     IF (DocDate < date `01.01.2001`) THEN
     BEGIN
       IF (RDB$GET_CONTEXT(`USER_SESSION`, `INGROUP`) = ``) THEN
       BEGIN
         SELECT ingroup FROM gd_user WHERE ibname = CURRENT_USER
           INTO :IG;
         RDB$SET_CONTEXT(`USER_SESSION`, `INGROUP`, :IG);
       END ELSE        
         IG = RDB$GET_CONTEXT(`USER_SESSION`, `INGROUP`);

       IF (BIN_AND(12345, :IG) = 0) THEN
         EXCEPTION gd_e_block;
     END

     // если при задании условия блокировки использовались метапеременные
     // то вычисляем соответствующую им дату. Например, задана переменная
     // ПредМесяц
     M = EXTRACT(MONTH FROM CURRENT_DATE) - 1;
     IF (M = 0) THEN M = 12;
     IF (DocDate < CAST('01.' || M || '.' || EXTRACT(YEAR FROM CURRENT_DATE) AS DATE)) THEN
       EXCEPTION gd_e_block;

   END

   ...
 END
Персональные инструменты
Пространства имён

Варианты
Действия
Навигация
Инструменты