Как не сойти с ума в разработке систем управления нормативно-справочной информацией. Из истории наших проектов / Блог компании ГК ЛАНИТ / Хабр

Как не сойти с ума в разработке систем управления нормативно-справочной информацией. Из истории наших проектов / Блог компании ГК ЛАНИТ / Хабр ОБД2

Анатомия системы нси

Данная статья основана на реальных событиях,
и все проблемы в ней не вымышленные. (С)

В начале хотелось бы отметить, что статья не призвана показать изобретение велосипеда, потому как многие приёмы уже давно существуют в культуре разработки баз данных. Однако обобщить, проанализировать проблемы, которые они могут решить и показать, как с ними можно работать. А проблем хватает несмотря на то, что нормативно-справочная информация (НСИ) не относится к бизнес-логике, а скорее находится в обслуживании у неё. Стандартный процесс по рисованию очередной таблички для хранения справочника очень скоро начинает обрастать костылями или трудоёмкими переделками.

Вот и в моём случае оказалась та же картина — система стоит на продуктиве более десяти лет, строилась по тому же принципу, если что нужно, рисуем и включаем в оборот. Таким образом были созданы несколько таблиц для хранения разного рода оборудования. Но вот пришёл час Х, когда стало необходимо добавить ещё пару таблиц для нового оборудования и при этом все (включая старые) должны входить в определённую группу. Это значит, что ссылки на разные таблицы должны быть включены в кросс-таблицу между группой и всеми пятью видами оборудования, то есть для каждого своё поля с констреинтом на соответствующую таблицу. А если ещё одно добавится, менять структуру. И обработку нужно делать в зависимости от того, какие поля заполнены. Вот и возникает первая проблема, как разные таблицы обобщить, что бы с ними одинаково можно было работать и не менять структуру, если добавляется ещё одна. Замечательная мысль, создаём отдельную табличку, которая призвана хранить абстрактное понятие оборудование с указанием типа, а тогда остальные таблички ссылаются по внешнему ключу на своего родителя. На этой радостной волне мы заливаем в созданную табличку записи из одной и пытаемся тоже сделать для другой. Но что-то пошло не так, сработало ограничение первичного ключа, к чему бы это? А к тому, что на заре бурной молодости системы для каждой табличке были свои сиквенсы. Конечно, со временем это безобразие поправили, но старые ключи всё равно остались. Более того, они корнями проросли по внешним ключам с другими таблицам. Фиксируем вторую проблему, связанную со сквозной нумерацией всех справочников.

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

Вроде как с этим справились, но заказчик не дремлет, у него всегда есть наготове что-нибудь новенькое. И вот приходит требование — все справочники историчные (например, название продукта было одним, а потом его переименовали, и по документам на разные даты нужно показывать актуальное название). Само по себе требование нормальное, ничего не скажешь. А если ещё в отделе разработки есть кто-то, кто проходит испытательный срок, так вообще всё в шоколаде, можно и не заметить, что это проблема. Однако проходит всё, как обычно — с полным авралом, а тут ещё этим нужно заниматься. Создаём таблички, дублирующие таблицы соответствующих справочников для того, чтобы там хранить хронологию изменений справочника. Но, создавая эти таблицы, мы заодно создаём себе четвёртую проблему, теперь в коде нужно в зависимости от даты обращаться то ли к основной таблице, то ли к исторической.

Ну мы же молодцы, мы и это победили))) Теперь, попивая чай из своей кружки, начинаешь дискутировать с другими коллегами на тему, что им приходилось решать, и понимаешь, что список проблем пополняется. В обсуждении стоит вопрос как хранить версии одной и той же записи. Хочу оговорится, что версия, это не то, что укладывается в таблицу историчности. В историчности понятно, до такого-то числа было одно название, а начиная с этой даты актуальным становится другое. А в версионности подразумевается, что запись была сначала сохранена с ошибкой, а через несколько часов это поняли и её изменили, и нужно знать все состояния этой записи. Во-первых, здесь должно быть дробление на время, не только сутки. А во-вторых, такие следы нужны в случае разборок. Например, заполняли прайс, ошиблись, успели товар продать по такой цене, а потом поправили, но в конце дня случился дебаланс. Однако решение для таких ситуаций меня лично напрягло, предлагалась все такие изменения хранить в самой таблице. Не буду устраивать холивар на сколько так правильно, но для меня точно обозначилась пятая проблема, а именно хранение изменений записей.

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

Начиная проектировать систему с нуля, никто не может предугадать путь её развития, а значит не сможет сказать на каком уровне придётся обобщать, как в описанном примере с оборудованием. Поэтому имеет смысл сразу задать абстрактную сущность, распространяемую на все таблицы НСИ. Таким образом все справочники будут иметь прообраз в едином справочнике с разделением на типы.

CREATE TABLE nsi_type (
    nsi_type_id     NUMBER(10) NOT NULL,
    name            VARCHAR2(50) NOT NULL,
    descr           VARCHAR2(100),
    table_name      VARCHAR2(50) NOT NULL,
    CONSTRAINT nsi_type_pk PRIMARY KEY (nsi_type_id)
);

CREATE TABLE nsi (
    nsi_id      NUMBER(10) NOT NULL,
    nsi_type_id NUMBER(10) NOT NULL,
    descr       VARCHAR2(100),
    create_date DATE NOT NULL,
    modif_date  DATE NOT NULL,
    begin_date  DATE,
    CONSTRAINT nsi_nsi_type_fk FOREIGN KEY (nsi_type_id) REFERENCES nsi_type (nsi_type_id),
    CONSTRAINT nsi_uk UNIQUE(nsi_type_id, nsi_id)
);

CREATE SEQUENCE nsi_seq
  MINVALUE 1
  START WITH 1
  INCREMENT BY 1
  CACHE 20;

Таблица nsi_type системная, заполняется по мере добавления новых справочников. Таблица nsi хранит ключи и системные поля. Заодно создаём собственный сиквенс и тем самым

закрываем вторую проблему

.

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

create or replace NONEDITIONABLE PACKAGE BODY pkg_nsi
IS

    /* По названию таблицы возвращается тип НСИ
    *  @param p_table_name VARCHAR2 - название таблицы
    *  @return nsi.nsi_type_id%TYPE - тип из таблицы nsi_type
    */
    FUNCTION get_type_id(p_table_name IN VARCHAR2) 
    RETURN nsi_type.nsi_type_id%TYPE
    AS
       v_type_id 	nsi_type.nsi_type_id%TYPE; 
    BEGIN
        SELECT nsi_type_id INTO v_type_id 
        FROM nsi_type
        WHERE TRIM(LOWER(table_name)) = TRIM(LOWER(p_table_name));

        RETURN v_type_id;
    END get_type_id;

    /* Возвращает следующий id из nsi_seq
    *  @return nsi.nsi_id%TYPE - id из nsi_seq
    */
    FUNCTION get_nsi_id 
    RETURN nsi.nsi_id%TYPE
    AS
       v_id 	nsi.nsi_id%TYPE; 
    BEGIN    
        SELECT nsi_seq.NEXTVAL INTO v_id FROM DUAL;
        RETURN v_id;
    END get_nsi_id;

    /* По типу справочника возвращает наименование таблицы
    *  @param p_nsi_type_id nsi_type.nsi_type_id%TYPE - тип из таблицы nsi_type 
    *  @return nsi_type.table_name%TYPE - название таблицы
    */
    FUNCTION get_table_name(p_nsi_type_id IN nsi_type.nsi_type_id%TYPE) 
    RETURN nsi_type.table_name%TYPE
    AS
       v_table_name nsi_type.table_name%TYPE; 
    BEGIN
        SELECT table_name INTO v_table_name 
        FROM nsi_type
        WHERE nsi_type_id = p_nsi_type_id;

        RETURN v_table_name;
    END get_table_name;

    /* Для определённого справчоника возвращает описание из таблицы nsi
    *  @param p_nsi_id nsi.nsi_id%TYPE - ключ справочника 
    *  @param p_nsi_type_id nsi_type.nsi_type_id%TYPE - тип справочника 
    *  @return nsi.descr%TYPE - описание
    */
    FUNCTION get_nsi_descr (
        p_nsi_id        IN nsi.nsi_id%TYPE,
        p_nsi_type_id   IN nsi.nsi_type_id%TYPE) 
    RETURN nsi.descr%TYPE
    AS
       v_nsi_descr  nsi.descr%TYPE; 
    BEGIN
        SELECT descr 
          INTO v_nsi_descr 
          FROM nsi
         WHERE nsi_id = p_nsi_id
           AND nsi_type_id = p_nsi_type_id;

        RETURN v_nsi_descr;
    END get_nsi_descr;
...
END pkg_nsi;

Здесь пока представлены вспомогательные функции для обеспечения необходимой инфраструктуры.

Итак стоит задача создать справочник организаций, куда же без него, любое предприятие контактирует со сторонними организациями — это и поставщики, и клиенты, и партнёры. Сразу добавим соответствующий тип в таблицу nsi_type и определим таблицу nsi_organization.

CREATE TABLE nsi_organization (
    nsi_id      NUMBER(10) NOT NULL,
    name        VARCHAR2(50) NOT NULL,
    full_name   VARCHAR2(100) NOT NULL,
    inn         VARCHAR2(12) NOT NULL,
    CONSTRAINT nsi_organization_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_organization_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

INSERT INTO nsi_type (nsi_type_id, name, descr, table_name) 
VALUES (11, 'Организация', 'Акционерное общество, компания, филиал, предприятие', 'nsi_organization');

Теперь, пока не поздно, нужно вспомнить про грабли с номером «пять». Если начнём добавлять записи в созданную таблицу организаций, то это событие нужно где-то фиксировать.

CREATE TABLE nsi_log (
    nsi_log_id        NUMBER(10) NOT NULL,
    nsi_id            NUMBER(10) NOT NULL,
    table_name        VARCHAR2(100),
    oper_num          NUMBER,
    descr             CLOB,
    create_date       DATE,
    CONSTRAINT nsi_log_pk PRIMARY KEY (nsi_log_id),
    CONSTRAINT nsi_log_oper_num_ch CHECK (oper_num IN (1, 2, 3, 4, 5, 6, 7))
);

COMMENT ON TABLE nsi_log IS 'НСИ. Логирование операций';
COMMENT ON COLUMN nsi_log.nsi_log_id IS 'Ключ';
COMMENT ON COLUMN nsi_log.nsi_id IS 'Справочник';
COMMENT ON COLUMN nsi_log.table_name IS 'Наименование таблицы';
COMMENT ON COLUMN nsi_log.oper_num IS 'Номер операции (1 - создание записи, 2 - изменение записи, 3 - удаление записи, 4 - добавление атрибута, 5 - изменение атрибута, 6 - удаление атрибута, 7 - создание версии истории).';
COMMENT ON COLUMN nsi_log.descr IS 'Описание';
COMMENT ON COLUMN nsi_log.create_date IS 'Дата создания';

А так же в пакет добавлена функция логирования.

    -- Ограничение CHECK nsi_log_oper_num_ch
    NSI_LOG_OPERNUM_INSERT          NUMBER := 1;
    NSI_LOG_OPERNUM_UPDATE          NUMBER := 2;
    NSI_LOG_OPERNUM_DELETE          NUMBER := 3;
    NSI_LOG_OPERNUM_ATTR_INSERT     NUMBER := 4;
    NSI_LOG_OPERNUM_ATTR_UPDATE     NUMBER := 5;
    NSI_LOG_OPERNUM_ATTR_DELETE     NUMBER := 6;
    NSI_LOG_OPERNUM_HISTORY_PUSH    NUMBER := 7;

    /* Добавление записи логирования операций.
    *  @param p_nsi_id nsi.nsi_id%TYPE - справочник
    *  @param p_nsi_type_id nsi_type.nsi_type_id%TYPE - тип справочника
    *  @param p_oper_num NUMBER - номер операции
    *  @param p_descr VARCHAR2 - описание
    */
    PROCEDURE log_oper (
        p_nsi_id        IN nsi.nsi_id%TYPE,
        p_nsi_type_id   IN nsi_type.nsi_type_id%TYPE,
        p_oper_num      IN NUMBER,
        p_descr         IN VARCHAR2)
    AS
    BEGIN
        INSERT INTO nsi_log 
        (nsi_log_id, nsi_id, table_name, oper_num, descr, create_date)
        VALUES 
        (get_nsi_id(), p_nsi_id, get_table_name(p_nsi_type_id), p_oper_num, p_descr, Sysdate);
    END;

Таким образом

разрешена пятая проблема

, теперь для любой записи НСИ можно посмотреть, что с ней происходило.

Пытаемся добавить туда организацию.

INSERT INTO nsi_organization (nsi_id, name, full_name, inn)
VALUES (1, 'АО "Рога и копыта"', 'Акционерное общество "Рога и копыта"', '11223344');

Конечно мы нарвёмся на констраинт nsi_organization_nsi_fk. Поэтому все справочные таблицы должны быть снабжены необходимой доработкой триггеров.

CREATE OR REPLACE TRIGGER nsi_organization_trg_insert 
BEFORE INSERT ON nsi_organization FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_organization');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_descr := 'name = ''' || :NEW.name || ''', full_name = ''' || :NEW.full_name || ''', inn = ''' || :NEW.inn || ''' ';
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_organization_trg_update 
BEFORE UPDATE ON nsi_organization FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_organization');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_descr := 'name = ''' || :NEW.name || ''', full_name = ''' || :NEW.full_name || ''', inn = ''' || :NEW.inn || ''' ';
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_organization_trg_delete 
AFTER DELETE ON nsi_organization FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_organization');

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_descr := 'name = ''' || :OLD.name || ''', full_name = ''' || :OLD.full_name || ''', inn = ''' || :OLD.inn || ''' ';
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;

А теперь добавление записи пройдёт без проблем (ключ уже указывать не надо). Заодно в таблице nsi появится первая запись, а так же в таблице логирования будет зафиксировано это событие.

INSERT INTO nsi_organization (name, full_name, inn)
VALUES ('АО "Рога и копыта"', 'Акционерное общество "Рога и копыта"', '11223344');

Но пока можно заметить только дополнительные расходы на создание таблицы какого-то справочника, а никак не преимущество единого подхода. Тогда вспомним про четвёртую проблему — нам необходимо хранить историчность данных в таблицах справочника, а так же извлекать актуальное состояние на заданную дату.

CREATE TABLE nsi_history (
    nsi_history_id  NUMBER(10) NOT NULL,
    nsi_id          NUMBER(10) NOT NULL,
    nsi_type_id     NUMBER(10) NOT NULL,
    version         NUMBER(10) NOT NULL,
    content         CLOB NOT NULL,
    note            VARCHAR2(100),
    begin_date      DATE NOT NULL,
    end_date        DATE NOT NULL,     
    CONSTRAINT nsi_history_pk PRIMARY KEY (nsi_history_id),
    CONSTRAINT nsi_history_nsi_type_fk FOREIGN KEY (nsi_type_id) REFERENCES nsi_type (nsi_type_id),
    CONSTRAINT nsi_history_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id),
    CONSTRAINT nsi_history_content_json_chk CHECK (content IS JSON)
);

COMMENT ON TABLE nsi_history IS 'Историчность справочника';
COMMENT ON COLUMN nsi_history.nsi_history_id IS 'Ключ';
COMMENT ON COLUMN nsi_history.nsi_id IS 'Справочник';
COMMENT ON COLUMN nsi_history.nsi_type_id IS 'Тип справочника';
COMMENT ON COLUMN nsi_history.version IS 'Версия';
COMMENT ON COLUMN nsi_history.content IS 'Содержимое справочника';
COMMENT ON COLUMN nsi_history.note IS 'Пояснение';
COMMENT ON COLUMN nsi_history.begin_date IS 'Дата начала действия';
COMMENT ON COLUMN nsi_history.end_date IS 'Дата окончания действия';

В пакет pkg_nsi добавим функцию сохранения записи в историческую таблицу. Хранить запись будем в формате json, поэтому в пакете так же появится возможность получить json для переданного запроса.

    /* Для переданного запроса возвращается json
    *  @param p_query VARCHAR2 - запрос
    *  @return CLOB - нотация json
    */
    FUNCTION get_json(p_query IN VARCHAR2) 
    RETURN CLOB
    AS
      v_theCursor       integer default dbms_sql.open_cursor;
      v_columnValue     varchar2(4000);
      v_status          integer;
      v_descTbl         dbms_sql.desc_tab;
      v_colCnt          number;
      v_res             clob;
    BEGIN
        dbms_sql.parse(v_theCursor, p_query, dbms_sql.native);
        dbms_sql.describe_columns( v_theCursor, v_colCnt, v_descTbl);

        FOR i IN 1 .. v_colCnt LOOP
            dbms_sql.define_column(v_theCursor, i, v_columnValue, 4000);
        END LOOP;
      
        v_status := dbms_sql.execute(v_theCursor);
        WHILE ( dbms_sql.fetch_rows(v_theCursor) > 0 ) LOOP
            FOR i IN 1 .. v_colCnt LOOP
                dbms_sql.column_value( v_theCursor, i, v_columnValue );
                IF i > 1 THEN
                    v_res := v_res || ', ';
                END IF;
                v_res := v_res || '"' || v_descTbl(i).col_name || '" : "' || replace(v_columnValue, '"', '"') || '"';
            END LOOP;
            
            -- Пока что подразумеваем, что возвращается только одна запись, поэтому берём её
            -- в случае необходимости изменим логику
            EXIT;
        END LOOP;
        
        RETURN '{' || v_res || '}';
      
    exception
        when others then dbms_sql.close_cursor( v_theCursor ); RAISE;
    END get_json;

    /* Сохранение текущего состояния справочника в таблицу историчности.
    *  @param p_nsi_id nsi.nsi_id%TYPE - справочник
    *  @param p_nsi_type_id nsi_type.nsi_type_id%TYPE - тип справочника
    *  @param p_end_date nsi_history.end_date%TYPE - дата окончания текущего содержимого справочника
    *  @param p_note nsi_history.note%TYPE - пояснение причины сохранения в истории
    */
    PROCEDURE nsi_history_push (
        p_nsi_id        IN nsi.nsi_id%TYPE,
        p_nsi_type_id   IN nsi_type.nsi_type_id%TYPE,
        p_end_date      IN nsi_history.end_date%TYPE,
        p_note          IN nsi_history.note%TYPE)
    AS
        v_table_name VARCHAR2(50);
        v_content CLOB;
        v_max_ver NUMBER;
        v_begin_date DATE;
    BEGIN
        IF (p_end_date IS NULL) THEN
            RAISE_APPLICATION_ERROR (NSI_ERROR_CODE, 
                '[nsi_history_push] Дата окончания должна быть определена.'); 
        END IF;

        IF (Trunc(p_end_date) > Trunc(Sysdate) ) THEN
            RAISE_APPLICATION_ERROR (NSI_ERROR_CODE, 
                '[nsi_history_push] Дата окончания не должна превышать текущую дату.'); 
        END IF;
        
        SELECT begin_date INTO v_begin_date
          FROM nsi
         WHERE nsi_id = p_nsi_id
           AND nsi_type_id = p_nsi_type_id;

        IF (Trunc(p_end_date) < Trunc(v_begin_date) ) THEN
            RAISE_APPLICATION_ERROR (NSI_ERROR_CODE, 
                '[nsi_history_push] Дата окончания не должна быть меньше даты начала действия текущей версии записи.'); 
        END IF;
        
        v_table_name := get_table_name(p_nsi_type_id);
        v_content := get_json ('select * from ' || v_table_name || ' where nsi_id=' || p_nsi_id);
        
        SELECT MAX(version) INTO v_max_ver
          FROM nsi_history
         WHERE nsi_id = p_nsi_id
           AND nsi_type_id = p_nsi_type_id;
          
        IF (v_max_ver IS NULL) THEN
            v_max_ver := 0;
        END IF;

        v_max_ver := v_max_ver   1;
        
        UPDATE nsi
           SET begin_date = Trunc(p_end_date)   1
         WHERE nsi_id = p_nsi_id
           AND nsi_type_id = p_nsi_type_id;
           
        INSERT INTO nsi_history
        (nsi_history_id, nsi_id, nsi_type_id, version, content, note, begin_date, end_date)
        VALUES (get_nsi_id, p_nsi_id, p_nsi_type_id, v_max_ver, v_content, p_note, v_begin_date, Trunc(p_end_date));
        
        log_oper(p_nsi_id, p_nsi_type_id, NSI_LOG_OPERNUM_HISTORY_PUSH, v_content);
    END nsi_history_push; 

Таким образом любой справочник может воспользоваться этой функцией, чтобы увести в историю текущее состояние. Уже хорошо, хоть что-то полезное появилось от такого обобщения))) Для извлечения актуального состояния справочника добавим в пакет соответствующую pipeline-функцию. Записи справочника будут возвращаться в тип, расширенный системными полями.

    -- Запись содержит поля таблицы nsi_organization и дополнены служебными полями nsi
    TYPE nsi_organization_rec IS RECORD(
        nsi_id          nsi_organization.nsi_id%TYPE, 
        name            nsi_organization.name%TYPE,
        full_name       nsi_organization.full_name%TYPE,
        inn             nsi_organization.inn%TYPE,
        nsi_type_id     nsi.nsi_type_id%TYPE, 
        create_date     nsi.create_date%TYPE,
        modif_date      nsi.create_date%TYPE,
        version         nsi_history.version%TYPE,
        begin_date      nsi.begin_date%TYPE,
        end_date        nsi_history.end_date%TYPE
    );
    TYPE nsi_organization_list IS TABLE OF nsi_organization_rec;

    /* Возвращает список, актуальный на указанную дату.
    *  Если дата не задана, актуальной считается текущая дата.
    *  @param p_date DATE - дата, на которую необходимо получить состояние справочника
    *  @return nsi_organization_table - таблица с записями nsi_organization_rec
    */
    FUNCTION nsi_organization_table(p_date IN DATE := null) 
    RETURN nsi_organization_list PIPELINED
    AS
        v_date date;
    BEGIN
        v_date := Trunc(Sysdate);
        IF p_date IS NOT NULL THEN
            v_date := Trunc(p_date);
        END IF;

        FOR rec IN (
            SELECT 
                o.nsi_id, o.name, o.full_name, o.inn,
                n.nsi_type_id, n.create_date, n.modif_date, 
                0 AS version, n.begin_date, to_date(null) AS end_date
            FROM 
                nsi_organization o INNER JOIN nsi n
                ON (o.nsi_id = n.nsi_id)
            WHERE 
                n.begin_date <= v_date
            UNION ALL
            SELECT 
                n.nsi_id, 
                json_value(h.content, '$.NAME') AS name, 
                json_value(h.content, '$.FULL_NAME') AS full_name,
                json_value(h.content, '$.INN') AS inn, 
                n.nsi_type_id, n.create_date, n.modif_date, 
                h.version, h.begin_date, h.end_date
            FROM 
                nsi_history h INNER JOIN nsi n
                ON (h.nsi_id = n.nsi_id AND h.nsi_type_id = n.nsi_type_id)
            WHERE 
                    h.begin_date <= v_date
                AND h.end_date >= v_date
        ) LOOP
            PIPE ROW (rec);
        END LOOP;
    END nsi_organization_table;

Применим к нашей таблице nsi_organization.

select * from nsi where nsi_id=1;
---------------------------------------------------------------------------------------
"NSI_ID"	"NSI_TYPE_ID"	"DESCR"	"CREATE_DATE"	"MODIF_DATE"	"BEGIN_DATE"
1	1	"АО ""Рога и копыта"""	11.03.20	11.03.20	11.03.20
---------------------------------------------------------------------------------------

begin
-- конечно это нереальная ситуация по смене инн, но для тестового примера вполне подойдёт
    pkg_nsi.nsi_history_push(202, 1, sysdate, 'смена инн');
end;
select * from nsi_history;
---------------------------------------------------------------------------------------
"NSI_HISTORY_ID"	"NSI_ID"	"NSI_TYPE_ID"	"VERSION"	"CONTENT"	"NOTE"	"BEGIN_DATE"	"END_DATE"
205	1	1	1	"{""NSI_ID"" : ""1"", ""NAME"" : ""АО ""Рога и копыта"""", ""FULL_NAME"" : ""Акционерное общество ""Рога и копыта"""", ""INN"" : ""11223344""}"	"смена инн"	11.03.20	11.03.20
---------------------------------------------------------------------------------------

-- следует обратить внимание на дату начала
-- так как был вызов сохранения в историю, то новая версия начала быть актуальной на следующий день
select * from nsi where nsi_id=1;
---------------------------------------------------------------------------------------
"NSI_ID"	"NSI_TYPE_ID"	"DESCR"	"CREATE_DATE"	"MODIF_DATE"	"BEGIN_DATE"
1	1	"АО ""Рога и копыта"""	11.03.20	11.03.20	12.03.20
---------------------------------------------------------------------------------------

-- обновим инн и посмотрим выборку на различные даты
-- различия присутствуют в полях inn, version, begin_date, end_date
-- текущая запись в таблице имеет версию 0
update nsi_organization set inn='99887766' where nsi_id=1;

select * from table(pkg_nsi.nsi_organization_table(sysdate));
---------------------------------------------------------------------------------------
"NSI_ID"	"NAME"	"FULL_NAME"	"INN"	"NSI_TYPE_ID"	"CREATE_DATE"	"MODIF_DATE"	"VERSION"	"BEGIN_DATE"	"END_DATE"
1	"АО ""Рога и копыта"""	"Акционерное общество ""Рога и копыта"""	"11223344"	1	11.03.20	11.03.20	1	11.03.20	11.03.20
---------------------------------------------------------------------------------------

select * from table(pkg_nsi.nsi_organization_table(sysdate 1));
---------------------------------------------------------------------------------------
"NSI_ID"	"NAME"	"FULL_NAME"	"INN"	"NSI_TYPE_ID"	"CREATE_DATE"	"MODIF_DATE"	"VERSION"	"BEGIN_DATE"	"END_DATE"
1	"АО ""Рога и копыта"""	"Акционерное общество ""Рога и копыта"""	"99887766"	1	11.03.20	11.03.20	0	12.03.20	
---------------------------------------------------------------------------------------

Функция nsi_organization_table очень полезна, потому как удовлетворяет нашим требованиям и окончательно

уводит проблему номер четыре в прошлое

.

Идём дальше. Раз у нас появилось такое преимущество с введением единого подхода для работы со всеми справочниками, то воспользуемся им и для хранения дополнительной информации, которой может быть наделена любая запись из любого справочника. Такое механизм уже давно существует, называется EAV-pattern, его и реализуем.

    -- Ограничение CHECK nsi_attribute_type_ch
    NSI_ATTRIBUTE_TYPE_STRING   NUMBER := 1;
    NSI_ATTRIBUTE_TYPE_INT      NUMBER := 2;
    NSI_ATTRIBUTE_TYPE_DOUBLE   NUMBER := 3;
    NSI_ATTRIBUTE_TYPE_DATE     NUMBER := 4;

CREATE TABLE nsi_attribute_type (
    nsi_attribute_type_id   NUMBER(10) NOT NULL,
    value_type              NUMBER NOT NULL,
    descr                   VARCHAR2(100) NOT NULL,
    CONSTRAINT nsi_attribute_type_pk PRIMARY KEY (nsi_attribute_type_id),
    CONSTRAINT nsi_attribute_type_ch CHECK (value_type IN (1, 2, 3, 4)),
    CONSTRAINT nsi_attribute_type_fk FOREIGN KEY (nsi_attribute_type_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_attribute_type IS 'НСИ. Тип атрибута';
COMMENT ON COLUMN nsi_attribute_type.nsi_attribute_type_id IS 'Ключ';
COMMENT ON COLUMN nsi_attribute_type.value_type IS 'Тип значения (1 - строка, 2 - целое, 3 - дробное, 4 - дата)';
COMMENT ON COLUMN nsi_attribute_type.descr IS 'Описание';

CREATE TABLE nsi_attribute (
    nsi_attribute_id        NUMBER(10) NOT NULL,
    nsi_attribute_type_id   NUMBER(10) NOT NULL,
    nsi_id                  NUMBER(10) NOT NULL,
    nsi_type_id             NUMBER(10) NOT NULL,
    value_1                 VARCHAR2(100),
    value_2_3               NUMBER,
    value_4                 DATE,
    begin_date              DATE,
    end_date                DATE,
    CONSTRAINT nsi_attribute_pk PRIMARY KEY (nsi_attribute_id),
    CONSTRAINT nsi_attribute_type_fk FOREIGN KEY (nsi_attribute_type_id) REFERENCES nsi_attribute_type (nsi_attribute_type_id),
    CONSTRAINT nsi_attribute_nsi_fk FOREIGN KEY (nsi_id, nsi_type_id) REFERENCES nsi (nsi_id, nsi_type_id)
);

COMMENT ON TABLE nsi_attribute IS 'НСИ. Тип атрибута';
COMMENT ON COLUMN nsi_attribute.nsi_attribute_id IS 'Ключ';
COMMENT ON COLUMN nsi_attribute.nsi_attribute_type_id IS 'Тип атрибута';
COMMENT ON COLUMN nsi_attribute.nsi_id IS 'Справочник';
COMMENT ON COLUMN nsi_attribute.nsi_type_id is 'Тип справочника';
COMMENT ON COLUMN nsi_attribute.value_1 IS 'Значение типа строка';
COMMENT ON COLUMN nsi_attribute.value_2_3 IS 'Значение типа целое или дробное';
COMMENT ON COLUMN nsi_attribute.value_4 IS 'Значение типа дата';
COMMENT ON COLUMN nsi_attribute.begin_date IS 'Дата начала действия атрибута';
COMMENT ON COLUMN nsi_attribute.end_date IS 'Дата окончания действия атрибута';

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

CREATE TABLE nsi_person (
    nsi_id   NUMBER(10) NOT NULL,
    surname         VARCHAR2(30) NOT NULL,
    name            VARCHAR2(30) NOT NULL,
    patronymic      VARCHAR2(30) NOT NULL,
    birthday        DATE,
    CONSTRAINT nsi_person_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_person_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_person IS 'НСИ. Физическое лицо';
COMMENT ON COLUMN nsi_person.nsi_id IS 'Ключ';
COMMENT ON COLUMN nsi_person.surname IS 'Фамилия';
COMMENT ON COLUMN nsi_person.name IS 'Имя';
COMMENT ON COLUMN nsi_person.patronymic IS 'Отчество';
COMMENT ON COLUMN nsi_person.birthday IS 'Дата рождения';

CREATE OR REPLACE TRIGGER nsi_person_trg_insert 
BEFORE INSERT ON nsi_person FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_person');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_query := 'SELECT ''' || :NEW.surname || ''' AS surname, ''' || :NEW.name || ''' AS name, ''' || :NEW.patronymic || ''' AS patronymic, to_date(''' || :NEW.birthday || ''', ''dd.mm.yy'') AS birthday FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_person_trg_update 
BEFORE UPDATE ON nsi_person FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_person');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :NEW.surname || ''' AS surname, ''' || :NEW.name || ''' AS name, ''' || :NEW.patronymic || ''' AS patronymic, to_date(''' || :NEW.birthday || ''', ''dd.mm.yy'') AS birthday FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_person_trg_delete 
AFTER DELETE ON nsi_person FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_person');

    DELETE FROM nsi_history 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi_attribute 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.surname || ''' AS surname, ''' || :OLD.name || ''' AS name, ''' || :OLD.patronymic || ''' AS patronymic, to_date(''' || :OLD.birthday || ''', ''dd.mm.yy'') AS birthday FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;

Осталось дополнить пакет pkg_nsi обработкой этой таблицы.

-- Запись содержит поля таблицы nsi_person и дополнены служебными полями nsi
    TYPE nsi_person_rec IS RECORD(
        nsi_id          nsi_person.nsi_id%TYPE, 
        surname         nsi_person.surname%TYPE,
        name            nsi_person.name%TYPE,
        patronymic      nsi_person.patronymic%TYPE,
        birthday        nsi_person.birthday%TYPE,
        nsi_type_id     nsi.nsi_type_id%TYPE, 
        create_date     nsi.create_date%TYPE,
        modif_date      nsi.create_date%TYPE,
        version         nsi_history.version%TYPE,
        begin_date      nsi.begin_date%TYPE,
        end_date        nsi_history.end_date%TYPE
    );
    TYPE nsi_person_list IS TABLE OF nsi_person_rec;

    /* Возвращает список, актуальный на указанную дату.
    *  Если дата не задана, актуальной считается текущая дата.
    *  @param p_date DATE - дата, на которую необходимо получить состояние справочника
    *  @return nsi_person_table - таблица с записями nsi_person_rec
    */
    FUNCTION nsi_person_table(p_date IN DATE := null) 
    RETURN nsi_person_list PIPELINED
    AS
        v_date date;
    BEGIN
        v_date := Trunc(Sysdate);
        IF p_date IS NOT NULL THEN
            v_date := Trunc(p_date);
        END IF;

        FOR rec IN (
            SELECT 
                p.nsi_id, p.surname, p.name, p.patronymic, p.birthday, 
                n.nsi_type_id, n.create_date, n.modif_date, 
                0 AS version, n.begin_date, to_date(null) AS end_date
            FROM 
                nsi_person p INNER JOIN nsi n
                ON (p.nsi_id = n.nsi_id)
            WHERE 
                n.begin_date <= v_date
            UNION ALL
            SELECT 
                n.nsi_id, 
                json_value(h.content, '$.SURNAME') AS surname, 
                json_value(h.content, '$.NAME') AS name,
                json_value(h.content, '$.PATRONYMIC') AS patronymic,
                to_date(json_value(h.content, '$.BIRTHDAY')) AS birthday,
                n.nsi_type_id, n.create_date, n.modif_date, 
                h.version, h.begin_date, h.end_date
            FROM 
                nsi_history h INNER JOIN nsi n
                ON (h.nsi_id = n.nsi_id AND h.nsi_type_id = n.nsi_type_id)
            WHERE 
                    h.begin_date <= v_date
                AND h.end_date >= v_date
        ) LOOP
            PIPE ROW (rec);
        END LOOP;
    END nsi_person_table;

И добавим кого-нибудь в эту таблицу.

INSERT INTO nsi_person
(surname, name, patronymic, birthday)
VALUES ('Деревянный', 'Буратино', 'Карлович', to_date('22.12.70', 'dd.mm.yy'));

Создадим атрибуты для самого востребованного родительного падежа.

INSERT INTO nsi_attribute_type (nsi_attribute_type_id, value_type, descr) 
VALUES (1, 1, 'Фамилия в род. падеже');
INSERT INTO nsi_attribute_type (nsi_attribute_type_id, value_type, descr) 
VALUES (2, 1, 'Имя в род. падеже');
INSERT INTO nsi_attribute_type (nsi_attribute_type_id, value_type, descr) 
VALUES (3, 1, 'Отчество в род. падеже');

В пакете pkg_nsi добавим функции для работы с атрибутами справочников.

    /* Для переданного id возвращает тип значения и описание атрибута.
    *  @param p_nsi_attribute_type_id nsi_attribute_type.nsi_attribute_type_id%TYPE - Тип атрибута
    *  @param p_value_type nsi_attribute_type.value_type%TYPE - Тип знаения
    *  @param p_descr nsi_attribute_type.descr%TYPE - Описание атрибута
    */
    PROCEDURE get_attribute_type (
        p_nsi_attribute_type_id IN nsi_attribute_type.nsi_attribute_type_id%TYPE,
        p_value_type            OUT nsi_attribute_type.value_type%TYPE,
        p_descr                 OUT nsi_attribute_type.descr%TYPE)
    AS
    BEGIN
        SELECT value_type, descr
          INTO p_value_type, p_descr
          FROM nsi_attribute_type
         WHERE nsi_attribute_type_id = p_nsi_attribute_type_id;
    END;


    /* Реализует вставку записи.
    *  @param p_nsi_attribute_type_id nsi_attribute.nsi_attribute_type_id%TYPE - Тип атрибута
    *  @param p_nsi_id nsi_attribute.nsi_id%TYPE - Справочник
    *  @param p_nsi_type_id nsi_attribute.nsi_type_id%TYPE - Тип справочника
    *  @param p_value_1 nsi_attribute.value_1%TYPE - Значение строкового типа
    *  @param p_value_2_3 nsi_attribute.value_2_3%TYPE - Значение числового типа
    *  @param p_value_4 nsi_attribute.value_4%TYPE - Значение типа даты
    *  @param p_begin_date nsi_attribute.begin_date%TYPE - Дата начала действия атрибута
    *  @param p_end_date nsi_attribute.end_date%TYPE - Дата окончания действия атрибута
    */
    PROCEDURE nsi_attribute_insert (
        p_nsi_attribute_type_id IN nsi_attribute.nsi_attribute_type_id%TYPE,
        p_nsi_id                IN nsi_attribute.nsi_id%TYPE,
        p_nsi_type_id           IN nsi_attribute.nsi_type_id%TYPE,
        p_value_1               IN nsi_attribute.value_1%TYPE,
        p_value_2_3             IN nsi_attribute.value_2_3%TYPE,
        p_value_4               IN nsi_attribute.value_4%TYPE,
        p_begin_date            IN nsi_attribute.begin_date%TYPE,
        p_end_date              IN nsi_attribute.end_date%TYPE)
    AS
        v_id            NUMBER;
        v_log_descr     nsi_log.descr%TYPE;
        v_value_type    nsi_attribute_type.value_type%TYPE;
        v_descr         nsi_attribute_type.descr%TYPE;
    BEGIN
        v_id := get_nsi_id;
        get_attribute_type(p_nsi_attribute_type_id, v_value_type, v_descr);

        IF (v_value_type = NSI_ATTRIBUTE_TYPE_STRING) THEN
            INSERT INTO nsi_attribute 
                (nsi_attribute_id, nsi_attribute_type_id, nsi_id, nsi_type_id, 
                 value_1, value_2_3, value_4, begin_date, end_date)
            VALUES (v_id, p_nsi_attribute_type_id, p_nsi_id, p_nsi_type_id,
                    p_value_1, null, null, p_begin_date, p_end_date);
                    
            v_log_descr := p_value_1;
                    
        ELSIF (v_value_type IN (NSI_ATTRIBUTE_TYPE_INT, NSI_ATTRIBUTE_TYPE_DOUBLE)) THEN
            INSERT INTO nsi_attribute 
                (nsi_attribute_id, nsi_attribute_type_id, nsi_id, nsi_type_id, 
                 value_1, value_2_3, value_4, begin_date, end_date)
            VALUES (v_id, p_nsi_attribute_type_id, p_nsi_id, p_nsi_type_id,
                    null, p_value_2_3, null, p_begin_date, p_end_date);
                    
            v_log_descr := p_value_2_3;
                    
        ELSE
            INSERT INTO nsi_attribute 
                (nsi_attribute_id, nsi_attribute_type_id, nsi_id, nsi_type_id, 
                 value_1, value_2_3, value_4, begin_date, end_date)
            VALUES (v_id, p_nsi_attribute_type_id, p_nsi_id, p_nsi_type_id,
                    null, null, p_value_4, p_begin_date, p_end_date);
                    
            v_log_descr := p_value_4;
        END IF;
        
        v_log_descr := '[' || get_nsi_descr(p_nsi_id, p_nsi_type_id) || '] ' ||
                       ' Атрибут: ' || v_descr || 
                       ' Значение: ' || v_log_descr || 
                       ' Период: ' || p_begin_date || ' - ' || p_end_date;
        log_oper(p_nsi_id, p_nsi_type_id, NSI_LOG_OPERNUM_ATTR_INSERT, v_log_descr);
    END;

    /* Реализует обновление типа и значения атрибута.
    *  @param p_nsi_attribute_id nsi_attribute.nsi_attribute_id%TYPE - Ключ атрибута
    *  @param p_value_1 nsi_attribute.value_1%TYPE - Значение строкового типа
    *  @param p_value_2_3 nsi_attribute.value_2_3%TYPE - Значение числового типа
    *  @param p_value_4 nsi_attribute.value_4%TYPE - Значение типа даты
    */
    PROCEDURE nsi_attribute_value (
        p_nsi_attribute_id      IN nsi_attribute.nsi_attribute_id%TYPE,
        p_value_1               IN nsi_attribute.value_1%TYPE,
        p_value_2_3             IN nsi_attribute.value_2_3%TYPE,
        p_value_4               IN nsi_attribute.value_4%TYPE)
    AS
        v_nsi_id            nsi.nsi_id%TYPE;
        v_nsi_type_id       nsi.nsi_type_id%TYPE;
        v_log_descr         nsi_log.descr%TYPE;
        v_value_type        nsi_attribute_type.value_type%TYPE;
        v_descr             nsi_attribute_type.descr%TYPE;
        v_nsi_attribute_type_id  nsi_attribute.nsi_attribute_type_id%TYPE;
    BEGIN
        SELECT nsi_attribute_type_id, nsi_id, nsi_type_id
          INTO v_nsi_attribute_type_id, v_nsi_id, v_nsi_type_id
          FROM nsi_attribute
          WHERE nsi_attribute_id = p_nsi_attribute_id;
          
        get_attribute_type(v_nsi_attribute_type_id, v_value_type, v_descr);
        
        IF (v_value_type = NSI_ATTRIBUTE_TYPE_STRING) THEN
            UPDATE nsi_attribute
               SET value_1 = p_value_1,
                   value_2_3 = null,
                   value_4 = null
            WHERE nsi_attribute_id = p_nsi_attribute_id;

            v_log_descr := p_value_1;
                    
        ELSIF (v_value_type IN (NSI_ATTRIBUTE_TYPE_INT, NSI_ATTRIBUTE_TYPE_DOUBLE)) THEN
            UPDATE nsi_attribute
               SET value_1 = null,
                   value_2_3 = p_value_2_3,
                   value_4 = null
            WHERE nsi_attribute_id = p_nsi_attribute_id;

            v_log_descr := p_value_2_3;
                    
        ELSE
            UPDATE nsi_attribute
               SET value_1 = null,
                   value_2_3 = null,
                   value_4 = p_value_4
            WHERE nsi_attribute_id = p_nsi_attribute_id;

            v_log_descr := p_value_4;
        END IF;

         
        v_log_descr := '[' || get_nsi_descr(v_nsi_id, v_nsi_type_id) || '] ' ||
                       ' Атрибут: ' || v_descr || 
                       ' Изменение значения: ' || v_log_descr;
        log_oper(v_nsi_id, v_nsi_type_id, NSI_LOG_OPERNUM_ATTR_UPDATE, v_log_descr);
    END;

    /* Реализует обновление периода действия атрибута.
    *  @param p_nsi_attribute_id nsi_attribute.nsi_attribute_id%TYPE - Ключ атрибута
    *  @param p_begin_date nsi_attribute.begin_date%TYPE - Дата начала действия атрибута
    *  @param p_end_date nsi_attribute.end_date%TYPE - Дата окончания действия атрибута
    */
    PROCEDURE nsi_attribute_period (
        p_nsi_attribute_id  IN nsi_attribute.nsi_attribute_id%TYPE,
        p_begin_date        IN nsi_attribute.begin_date%TYPE,
        p_end_date          IN nsi_attribute.end_date%TYPE)
    AS
        v_nsi_id        nsi.nsi_id%TYPE;
        v_nsi_type_id   nsi.nsi_type_id%TYPE;
        v_log_descr     nsi_log.descr%TYPE;
        v_value_type    nsi_attribute_type.value_type%TYPE;
        v_descr         nsi_attribute_type.descr%TYPE;
        v_nsi_attribute_type_id nsi_attribute.nsi_attribute_type_id%TYPE;
    BEGIN
        SELECT nsi_id, nsi_type_id, nsi_attribute_type_id
          INTO v_nsi_id, v_nsi_type_id, v_nsi_attribute_type_id
          FROM nsi_attribute
         WHERE nsi_attribute_id = p_nsi_attribute_id;
    
        get_attribute_type(v_nsi_attribute_type_id, v_value_type, v_descr);
        
        UPDATE nsi_attribute
           SET begin_date = p_begin_date,
               end_date = p_end_date
         WHERE nsi_attribute_id = p_nsi_attribute_id;
         
        v_log_descr := '[' || get_nsi_descr(v_nsi_id, v_nsi_type_id) || '] ' ||
                       ' Атрибут: ' || v_descr || 
                       ' Изменение периода: ' || p_begin_date || ' - ' || p_end_date;
        log_oper(v_nsi_id, v_nsi_type_id, NSI_LOG_OPERNUM_ATTR_UPDATE, v_log_descr);
    END;

    /* Реализует удаление записи.
    *  @param p_nsi_attribute_id nsi_person.nsi_attribute_id%TYPE - id записи nsi_attribute
    */
    PROCEDURE nsi_attribute_delete (p_nsi_attribute_id nsi_attribute.nsi_attribute_id%TYPE)
    AS
        v_nsi_id        nsi.nsi_id%TYPE;
        v_nsi_type_id   nsi.nsi_type_id%TYPE;
        v_log_descr     nsi_log.descr%TYPE;
        v_value_type    nsi_attribute_type.value_type%TYPE;
        v_descr         nsi_attribute_type.descr%TYPE;
        v_nsi_attribute_type_id nsi_attribute.nsi_attribute_type_id%TYPE;
    BEGIN
        SELECT nsi_id, nsi_type_id, nsi_attribute_type_id
          INTO v_nsi_id, v_nsi_type_id, v_nsi_attribute_type_id
          FROM nsi_attribute
         WHERE nsi_attribute_id = p_nsi_attribute_id;
    
        get_attribute_type(v_nsi_attribute_type_id, v_value_type, v_descr);
        
        DELETE FROM nsi_attribute
        WHERE nsi_attribute_id = p_nsi_attribute_id;
         
        v_log_descr := '[' || get_nsi_descr(v_nsi_id, v_nsi_type_id) || '] ' ||
                       ' Атрибут: ' || v_descr;
        log_oper(v_nsi_id, v_nsi_type_id, NSI_LOG_OPERNUM_ATTR_DELETE, v_log_descr);
    END;

Теперь присвоим соответствующие атрибуты.

begin
    pkg_nsi.nsi_attribute_insert(1, 225, 6, 'деревянного', null, null, sysdate, null);
    pkg_nsi.nsi_attribute_insert(2, 225, 6, 'Буратино', null, null, sysdate, null);
    pkg_nsi.nsi_attribute_insert(3, 225, 6, 'Карловича', null, null, sysdate, null);
end;

-- но когда просматриваем результат видим ошибку, фамилия Буратино написана с маленькой буквы, нужно исправить
--------------------------------------------------------------------------------------------
"NSI_ATTRIBUTE_ID"	"NSI_ATTRIBUTE_TYPE_ID"	"NSI_ID"	"NSI_TYPE_ID"	"VALUE_1"	"VALUE_2_3"	"VALUE_4"	"BEGIN_DATE"	"END_DATE"
230	1	225	6	"деревянного"			11.03.20	
232	2	225	6	"Буратино"			11.03.20	
234	3	225	6	"Карловича"			11.03.20	
--------------------------------------------------------------------------------------------

begin
    pkg_nsi.nsi_attribute_value(230, 'Деревянного', null, null);
end;
--------------------------------------------------------------------------------------------
"NSI_ATTRIBUTE_ID"	"NSI_ATTRIBUTE_TYPE_ID"	"NSI_ID"	"NSI_TYPE_ID"	"VALUE_1"	"VALUE_2_3"	"VALUE_4"	"BEGIN_DATE"	"END_DATE"
230	1	225	6	"Деревянного"			11.03.20
232	2	225	6	"Буратино"			11.03.20	
234	3	225	6	"Карловича"			11.03.20	
--------------------------------------------------------------------------------------------

-- перенесём начало действия атрибута на день раньше
begin
    pkg_nsi.nsi_attribute_period(230, sysdate-1, null);
    pkg_nsi.nsi_attribute_period(232, sysdate-1, null);
    pkg_nsi.nsi_attribute_period(234, sysdate-1, null);
end;
--------------------------------------------------------------------------------------------
"NSI_ATTRIBUTE_ID"	"NSI_ATTRIBUTE_TYPE_ID"	"NSI_ID"	"NSI_TYPE_ID"	"VALUE_1"	"VALUE_2_3"	"VALUE_4"	"BEGIN_DATE"	"END_DATE"
230	1	225	6	"Деревянного"			10.03.20	
232	2	225	6	"Буратино"			10.03.20	
234	3	225	6	"Карловича"			10.03.20	
--------------------------------------------------------------------------------------------

Таким образом мы

Код ошибки:  Такая тема: OBDII | SUZUKI CLUB RUSSIA

победим третью проблему

.

Кроме таблиц справочников в системе НСИ также важны отношение между ними. Так, например крупные организации включают в себя различные подразделения, филиалы, отделы и т.п., которые можно выстроить в древовидную структуру. Для начала заведём в нашей системе ещё несколько организаций, которые будут в подчинении у уже существующей «Рога и копыта».

INSERT INTO nsi_organization (name, full_name, inn)
VALUES ('Подразделение по обслуживанию рогов', 'Подразделение по обслуживанию рогов', '1111111111');
INSERT INTO nsi_organization (name, full_name, inn)
VALUES ('Подразделение по обслуживанию копыт', 'Подразделение по обслуживанию копыт', '2222222222');
INSERT INTO nsi_organization (name, full_name, inn)
VALUES ('Отдел по изготовлению подков', 'Отдел по изготовлению подков', '3333333333');

----------------------------------------------------------------------------
281	1	Подразделение по обслуживанию рогов	13.03.20	13.03.20	13.03.20
283	1	Подразделение по обслуживанию копыт	13.03.20	13.03.20	13.03.20
285	1	Отдел по изготовлению подков	13.03.20	13.03.20	13.03.20
1	1	АО "Рога и копыта"	11.03.20	13.03.20	12.03.20
----------------------------------------------------------------------------

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

CREATE TABLE nsi_structure (
    nsi_structure_id    NUMBER(10) NOT NULL,
    nsi_parent_structure_id NUMBER(10),
    nsi_id              NUMBER(10) NOT NULL,
    nsi_type_id         NUMBER(10) NOT NULL,
    ordnum              NUMBER,
    begin_date          DATE NOT NULL,
    end_date            DATE,
    CONSTRAINT nsi_structure_pk PRIMARY KEY (nsi_structure_id),
    CONSTRAINT nsi_parent_struct_fk FOREIGN KEY (nsi_parent_structure_id) REFERENCES nsi_structure (nsi_structure_id),
    CONSTRAINT nsi_struct_nsi_fk FOREIGN KEY (nsi_id, nsi_type_id) REFERENCES nsi (nsi_id, nsi_type_id)
);

COMMENT ON TABLE nsi_structure IS 'НСИ. Таблица структуры справочников';
COMMENT ON COLUMN nsi_structure.nsi_structure_id IS 'Ключ';
COMMENT ON COLUMN nsi_structure.nsi_parent_structure_id IS 'Ключ родителя';
COMMENT ON COLUMN nsi_structure.nsi_id IS 'Справочник';
COMMENT ON COLUMN nsi_structure.nsi_type_id IS 'Тип справочника';
COMMENT ON COLUMN nsi_structure.ordnum IS 'Порядковый номер';
COMMENT ON COLUMN nsi_structure.begin_date IS 'Дата начала действия';
COMMENT ON COLUMN nsi_structure.end_date IS 'Дата окончания действия';

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

    /* Реализует вставку записи.
    *  @param p_nsi_parent_structure_id nsi_structure.nsi_parent_structure_id%TYPE - запись родителя
    *  @param p_nsi_id nsi_structure.nsi_id%TYPE - справочник
    *  @param p_nsi_type_id nsi_structure.nsi_type_id%TYPE - тип справочника
    *  @param p_ordnum nsi_structure.ordnum%TYPE - порядковый номер
    *  @param p_begin_date nsi_structure.begin_date%TYPE - дата начала действия записи
    *  @param p_end_date nsi_structure.end_date%TYPE - дата окончания действия записи
    */
    FUNCTION nsi_structure_insert (
        p_nsi_parent_structure_id   IN nsi_structure.nsi_parent_structure_id%TYPE,
        p_nsi_id                    IN nsi_structure.nsi_id%TYPE,
        p_nsi_type_id               IN nsi_structure.nsi_type_id%TYPE,
        p_ordnum                    IN nsi_structure.ordnum%TYPE,
        p_begin_date                IN nsi_structure.begin_date%TYPE, 
        p_end_date                  IN nsi_structure.end_date%TYPE)
    RETURN nsi_structure.nsi_structure_id%TYPE
    AS
        v_id        NUMBER;
        v_log_descr nsi_log.descr%TYPE;
        v_type_id 	nsi.nsi_type_id%TYPE;
    BEGIN
        v_id := get_nsi_id;
        v_type_id := get_type_id('nsi_structure');

        INSERT INTO nsi_structure (
            nsi_structure_id, nsi_parent_structure_id,
            nsi_id, nsi_type_id, ordnum, begin_date, end_date)
        VALUES (
            v_id, p_nsi_parent_structure_id, 
            p_nsi_id, p_nsi_type_id, p_ordnum, Trunc(p_begin_date), Trunc(p_end_date));
         
        v_log_descr := '[' || get_nsi_descr(p_nsi_id, p_nsi_type_id) || '] ';
        v_log_descr := v_log_descr || 'Период ' || p_begin_date || ' - ' || p_end_date;
        log_oper (v_id, v_type_id, NSI_LOG_OPERNUM_INSERT, v_log_descr);
        
        RETURN v_id;
    END nsi_structure_insert;


    /* Реализует обновление порядкового номера записи.
    *  @param p_nsi_structure_id nsi_structure.nsi_structure_id%TYPE - ключ nsi_structure
    *  @param p_ordnum nsi_structure.ordnum%TYPE - порядковый номер
    */
    PROCEDURE nsi_structure_ordnum (
        p_nsi_structure_id  IN nsi_structure.nsi_structure_id%TYPE,
        p_ordnum            IN nsi_structure.ordnum%TYPE)
    AS
        v_nsi_id 		    nsi_structure.nsi_id%TYPE;
        v_nsi_type_id 	    nsi_structure.nsi_type_id%TYPE;
        v_type_id 	        nsi.nsi_type_id%TYPE;
        v_log_descr         nsi_log.descr%TYPE;
    BEGIN
        v_type_id := get_type_id('nsi_structure');
        
        SELECT nsi_id, nsi_type_id
          INTO v_nsi_id, v_nsi_type_id
          FROM nsi_structure
         WHERE nsi_structure_id = p_nsi_structure_id;

        UPDATE nsi_structure
           SET ordnum = p_ordnum 
         WHERE nsi_structure_id = p_nsi_structure_id;
         
        v_log_descr := '[' || get_nsi_descr(v_nsi_id, v_nsi_type_id) || '] ';
        v_log_descr := v_log_descr || 'Номер ' || p_ordnum;
        log_oper (p_nsi_structure_id, v_type_id, NSI_LOG_OPERNUM_UPDATE, v_log_descr);
    END;


    /* Реализует обновление периода действия записи.
    *  @param p_nsi_structure_id nsi_structure.nsi_structure_id%TYPE - ключ nsi_structure
    *  @param p_begin_date nsi_structure.begin_date%TYPE - дата начала действия
    *  @param p_end_date nsi_structure.end_date%TYPE - дата окончания действия
    */
    PROCEDURE nsi_structure_period (
        p_nsi_structure_id  IN nsi_structure.nsi_structure_id%TYPE,
        p_begin_date        IN nsi_structure.begin_date%TYPE, 
        p_end_date          IN nsi_structure.end_date%TYPE)
    AS
        v_nsi_id 		    nsi_structure.nsi_id%TYPE;
        v_nsi_type_id 	    nsi_structure.nsi_type_id%TYPE;
        v_type_id 	        nsi.nsi_type_id%TYPE;
        v_log_descr         nsi_log.descr%TYPE;
    BEGIN
        v_type_id := get_type_id('nsi_structure');
        
        SELECT nsi_id, nsi_type_id
          INTO v_nsi_id, v_nsi_type_id
          FROM nsi_structure
         WHERE nsi_structure_id = p_nsi_structure_id;

        UPDATE nsi_structure
           SET begin_date = Trunc(p_begin_date),
               end_date = Trunc(p_end_date) 
         WHERE nsi_structure_id = p_nsi_structure_id;
         
        v_log_descr := '[' || get_nsi_descr(v_nsi_id, v_nsi_type_id) || '] ';
        v_log_descr := v_log_descr || 'Период ' || p_begin_date || ' - ' || p_end_date;
        log_oper (p_nsi_structure_id, v_type_id, NSI_LOG_OPERNUM_UPDATE, v_log_descr);
    END;


    /* Реализует удаление записи.
    *  @param p_nsi_structure_id nsi_structure.nsi_structure_id%TYPE - ключ nsi_structure
    */
    PROCEDURE nsi_structure_delete (p_nsi_structure_id IN nsi_structure.nsi_structure_id%TYPE)
    AS
        v_type_id 	nsi.nsi_type_id%TYPE;
        v_log_descr nsi_log.descr%TYPE;
    BEGIN
        v_type_id := pkg_nsi.get_type_id('nsi_structure');
        
        FOR rec IN (
            SELECT nsi_structure_id, nsi_parent_structure_id,
                    nsi_id, nsi_type_id, ordnum, begin_date, end_date
            FROM nsi_structure
            START WITH nsi_structure_id = p_nsi_structure_id
            CONNECT BY PRIOR nsi_structure_id = nsi_parent_structure_id
        )
        LOOP
            v_log_descr := '[' || pkg_nsi.get_nsi_descr(rec.nsi_id, rec.nsi_type_id) || '] ';
            v_log_descr := v_log_descr || 'Период ' || rec.begin_date || ' - ' || rec.end_date;
            pkg_nsi.log_oper (rec.nsi_structure_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
        END LOOP;
        
        DELETE FROM nsi_structure
        WHERE nsi_structure_id = p_nsi_structure_id;
    END;

После появления такого инструмента можно смело выстраивать отношения между организациями.

declare
    id number;
    root_id number;
begin
    root_id := pkg_nsi.nsi_structure_insert(null, 1, 1, null, to_date('13.02.20', 'dd.mm.yy'), null);
    id := pkg_nsi.nsi_structure_insert(root_id, 281, 1, null, to_date('13.02.20', 'dd.mm.yy'), to_date('15.02.20', 'dd.mm.yy'));
    id := pkg_nsi.nsi_structure_insert(root_id, 283, 1, null, to_date('13.02.20', 'dd.mm.yy'), null);
    id := pkg_nsi.nsi_structure_insert(id, 285, 1, null, to_date('13.02.20', 'dd.mm.yy'), null);
end;

SELECT *
FROM nsi_structure
START WITH (nsi_parent_structure_id IS NULL)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id);
-----------------------------------------------------------------------------------
316		1	1		13.02.20	
318	316	281	1		13.02.20	15.02.20
320	316	283	1		13.02.20	
322	320	285	1		13.02.20	
-----------------------------------------------------------------------------------

-- а если необходимо задать определённую сортировку
begin
    pkg_nsi.nsi_structure_ordnum(320, 1);
    pkg_nsi.nsi_structure_ordnum(318, 2);
end;

SELECT *
FROM nsi_structure
START WITH (nsi_parent_structure_id IS NULL)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id)
ORDER SIBLINGS BY ordnum;
-----------------------------------------------------------------------------------
316		1	1		13.02.20	
320	316	283	1	1	13.02.20	
322	320	285	1		13.02.20	
318	316	281	1	2	13.02.20	15.02.20
-----------------------------------------------------------------------------------

-- изменим периоды действия подразделения
begin
    pkg_nsi.nsi_structure_period(320, to_date('14.02.20', 'dd.mm.yy'), to_date('14.02.20', 'dd.mm.yy'));
end;

SELECT *
FROM nsi_structure
START WITH (nsi_parent_structure_id IS NULL)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id)
ORDER SIBLINGS BY ordnum;
-----------------------------------------------------------------------------------
316		1	1		13.02.20	
320	316	283	1	1	14.02.20	14.02.20
322	320	285	1		13.02.20	
318	316	281	1	2	13.02.20	15.02.20
-----------------------------------------------------------------------------------

Так как справочники отделены от структуры, то каждый раз обращаться к организациям с учётом их отношений становится грамозко, поэтому немного упростим себе жизнь.

CREATE OR REPLACE VIEW V_NSI_ORGANIZATION AS
SELECT 
    s.nsi_structure_id, s.nsi_parent_structure_id,
    s.ordnum, s.begin_date, s.end_date,
    s.nsi_id, s.nsi_type_id, o.name, o.full_name, o.inn
FROM nsi_structure s INNER JOIN nsi_organization o
    ON (s.nsi_id = o.nsi_id)
START WITH (nsi_parent_structure_id IS NULL)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id)
ORDER SIBLINGS BY ordnum;

SELECT * FROM v_nsi_organization;
-----------------------------------------------------------------------------------
316			13.02.20		1	1	АО "Рога и копыта"	Акционерное общество "Рога и копыта"	99887766
320	316	1	14.02.20	14.02.20	283	1	Подразделение по обслуживанию копыт	Подразделение по обслуживанию копыт	2222222222
322	320		13.02.20		285	1	Отдел по изготовлению подков	Отдел по изготовлению подков	3333333333
318	316	2	13.02.20	15.02.20	281	1	Подразделение по обслуживанию рогов	Подразделение по обслуживанию рогов	1111111111
-----------------------------------------------------------------------------------

То, что мы строим дерево это замечательно, но все узлы этого дерева относятся к одной сущности, а наша задача реализовать построение отношения между разными сущностями. Это тоже не проблема, потому как структура не завязывается на какой-то определённый справочник, а работает в целом на всей системе НСИ. Для примера построим классификатор для должностей государственной гражданской службы и классификатор для должностей муниципалитета.

CREATE TABLE nsi_classifier (
    nsi_id      NUMBER(10) NOT NULL,
    code        VARCHAR2(10),
    name        VARCHAR2(200) NOT NULL,
    CONSTRAINT nsi_classifier_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_classifier_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_classifier IS 'НСИ. Классификатор';
COMMENT ON COLUMN nsi_classifier.nsi_id IS 'Ключ';
COMMENT ON COLUMN nsi_classifier.code IS 'Код';
COMMENT ON COLUMN nsi_classifier.name IS 'Наименование';


CREATE OR REPLACE TRIGGER nsi_classifier_trg_insert 
BEFORE INSERT ON nsi_classifier FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_classifier');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name, ''' || :NEW.code || ''' AS code FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_classifier_trg_update 
BEFORE UPDATE ON nsi_classifier FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_classifier');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name, ''' || :NEW.code || ''' AS code FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_classifier_trg_delete 
AFTER DELETE ON nsi_classifier FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_classifier');

    DELETE FROM nsi_history 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi_attribute 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name, ''' || :OLD.code || ''' AS code FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;
CREATE TABLE nsi_post_group (
    nsi_id   NUMBER(10) NOT NULL,
    name     VARCHAR2(50) NOT NULL,
    CONSTRAINT nsi_post_group_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_post_group_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_post_group is 'НСИ. Группа должности';
COMMENT ON COLUMN nsi_post_group.nsi_id is 'Ключ';
COMMENT ON COLUMN nsi_post_group.name is 'Наименование';


CREATE OR REPLACE TRIGGER nsi_post_group_trg_insert 
BEFORE INSERT ON nsi_post_group FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_group');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_group_trg_update 
BEFORE UPDATE ON nsi_post_group FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_group');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_group_trg_delete 
AFTER DELETE ON nsi_post_group FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_group');

    DELETE FROM nsi_history 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi_attribute 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;
CREATE TABLE nsi_post_category (
    nsi_id   NUMBER(10) NOT NULL,
    name     VARCHAR2(50) NOT NULL,
    CONSTRAINT nsi_post_category_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_post_category_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_post_category is 'НСИ. Категория должности';
COMMENT ON COLUMN nsi_post_category.nsi_id is 'Ключ';
COMMENT ON COLUMN nsi_post_category.name is 'Наименование';


CREATE OR REPLACE TRIGGER nsi_post_category_trg_insert 
BEFORE INSERT ON nsi_post_category FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_category');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_category_trg_update 
BEFORE UPDATE ON nsi_post_category FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_category');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :NEW.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_category_trg_delete 
AFTER DELETE ON nsi_post_category FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post_category');

    DELETE FROM nsi_history 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi_attribute 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;
CREATE TABLE nsi_post (
    nsi_id          NUMBER(10) NOT NULL,
    code_OKPDTR     VARCHAR2(10),
    name            VARCHAR2(50) NOT NULL,
    CONSTRAINT nsi_post_pk PRIMARY KEY (nsi_id),
    CONSTRAINT nsi_post_nsi_fk FOREIGN KEY (nsi_id) REFERENCES nsi (nsi_id)
);

COMMENT ON TABLE nsi_post IS 'НСИ. Должность';
COMMENT ON COLUMN nsi_post.nsi_id IS 'Ключ';
COMMENT ON COLUMN nsi_post.code_OKPDTR IS 'Код ОКПДТР';
COMMENT ON COLUMN nsi_post.name IS 'Наименование';


CREATE OR REPLACE TRIGGER nsi_post_trg_insert 
BEFORE INSERT ON nsi_post FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post');
    :NEW.nsi_id := pkg_nsi.get_nsi_id();

    INSERT INTO nsi (nsi_id, nsi_type_id, descr, create_date, modif_date, begin_date)
    VALUES (:NEW.nsi_id, v_type_id, :NEW.name, Trunc(Sysdate), Trunc(Sysdate), Trunc(Sysdate));
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name, ''' || :OLD.code_OKPDTR || ''' AS code_OKPDTR FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_INSERT, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_trg_update 
BEFORE UPDATE ON nsi_post FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post');

    UPDATE nsi
       SET modif_date = Trunc(Sysdate)
     WHERE nsi_id = :NEW.nsi_id
       AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name, ''' || :OLD.code_OKPDTR || ''' AS code_OKPDTR FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:NEW.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_UPDATE, v_log_descr);
END;

CREATE OR REPLACE TRIGGER nsi_post_trg_delete 
AFTER DELETE ON nsi_post FOR EACH ROW
DECLARE
    v_type_id 	nsi.nsi_type_id%TYPE;
    v_log_descr nsi_log.descr%TYPE;
    v_log_query VARCHAR(4000);
BEGIN
    v_type_id := pkg_nsi.get_type_id('nsi_post');

    DELETE FROM nsi_history 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi_attribute 
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;

    DELETE FROM nsi
    WHERE nsi_id = :OLD.nsi_id
      AND nsi_type_id = v_type_id;
    
    v_log_query := 'SELECT ''' || :OLD.name || ''' AS name, ''' || :OLD.code_OKPDTR || ''' AS code_OKPDTR FROM DUAL';
    v_log_descr := pkg_nsi.get_json(v_log_query);
    pkg_nsi.log_oper (:OLD.nsi_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
END;

Осталось только заполнить и собрать необходимые классификаторы.

INSERT INTO nsi_classifier (name) VALUES ('Классификатор должностей ГГС');
INSERT INTO nsi_classifier (name) VALUES ('Классификатор должностей муниципалитета');

INSERT INTO nsi_post_group (name) VALUES ('Высшие');
INSERT INTO nsi_post_group (name) VALUES ('Главные');
INSERT INTO nsi_post_group (name) VALUES ('Ведущие');
INSERT INTO nsi_post_group (name) VALUES ('Старшие');
INSERT INTO nsi_post_group (name) VALUES ('Младшие');

INSERT INTO nsi_post_category (name) VALUES ('Руководители');
INSERT INTO nsi_post_category (name) VALUES ('Помощники (советники)');
INSERT INTO nsi_post_category (name) VALUES ('Специалисты');
INSERT INTO nsi_post_category (name) VALUES ('Обеспечивающие специалист');

INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('24742', 'Начальник отдела');
INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('26480', 'Советник');
INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('23509', 'Консультант');
INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('20419', 'Ведущий специалист');
INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('26541', 'Специалист');
INSERT INTO nsi_post (code_OKPDTR, name)
VALUES ('26544', 'Специалист 2 разряда');

commit;

declare
    post_id number;
    classif_id number;
    categ_id number;
    group_id number;
begin
    -- Классификатор должностей ГГС
    classif_id := pkg_nsi.nsi_structure_insert(null, 331, 5, null, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Руководители
    categ_id := pkg_nsi.nsi_structure_insert(classif_id, 347, 4, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Высшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 355, 3, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Главные
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 357, 3, 2, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Начальник отдела
    post_id := pkg_nsi.nsi_structure_insert(group_id, 335, 2, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Ведущие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 359, 3, 3, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Помощники (советники)
    categ_id := pkg_nsi.nsi_structure_insert(classif_id, 349, 4, 2, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Высшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 355, 3, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Главные
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 357, 3, 2, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Ведущие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 359, 3, 3, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Советник
    post_id := pkg_nsi.nsi_structure_insert(group_id, 337, 2, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Специалисты
    categ_id := pkg_nsi.nsi_structure_insert(classif_id, 351, 4, 3, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Высшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 355, 3, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Главные
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 357, 3, 2, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Ведущие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 359, 3, 3, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Ведущий специалист
    post_id := pkg_nsi.nsi_structure_insert(group_id, 341, 2, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Старшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 361, 3, 4, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Обеспечивающие специалист
    categ_id := pkg_nsi.nsi_structure_insert(classif_id, 353, 4, 4, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Главные
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 357, 3, 1, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Ведущие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 359, 3, 2, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Старшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 361, 3, 3, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Младшие
    group_id := pkg_nsi.nsi_structure_insert(categ_id, 363, 3, 4, to_date('13.02.20', 'dd.mm.yy'), null);
    -- Специалист 2 разряда
    post_id := pkg_nsi.nsi_structure_insert(group_id, 345, 2, 1, to_date('13.02.20', 'dd.mm.yy'), null);

commit;
end;


SELECT *
FROM nsi_structure s
START WITH (nsi_id = 331)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id)
ORDER SIBLINGS BY ordnum;
----------------------------------------------------------------------------------
"NSI_STRUCTURE_ID"	"NSI_PARENT_STRUCTURE_ID"	"NSI_ID"	"NSI_TYPE_ID"	"ORDNUM"	"BEGIN_DATE"	"END_DATE"
385		331	5		13.02.20	
387	385	347	4	1	13.02.20	
389	387	355	3	1	13.02.20	
391	387	357	3	2	13.02.20	
393	391	335	2	1	13.02.20	
395	387	359	3	3	13.02.20	
397	385	349	4	2	13.02.20	
399	397	355	3	1	13.02.20	
401	397	357	3	2	13.02.20	
403	397	359	3	3	13.02.20	
405	403	337	2	1	13.02.20	
407	385	351	4	3	13.02.20	
409	407	355	3	1	13.02.20	
411	407	357	3	2	13.02.20	
413	407	359	3	3	13.02.20	
415	413	341	2	1	13.02.20	
417	407	361	3	4	13.02.20	
419	385	353	4	4	13.02.20	
421	419	357	3	1	13.02.20	
423	419	359	3	2	13.02.20	
425	419	361	3	3	13.02.20	
427	419	363	3	4	13.02.20	
429	427	345	2	1	13.02.20	
----------------------------------------------------------------------------------

Ой, как это не читабельно!

CREATE OR REPLACE VIEW V_NSI_CLASSIFIRE_GGS AS
SELECT 
    s.nsi_structure_id, s.nsi_parent_structure_id,
    s.ordnum, s.begin_date, s.end_date,
    n.nsi_id, n.nsi_type_id, n.descr
FROM nsi_structure s INNER JOIN nsi n
    ON (s.nsi_id = n.nsi_id)
START WITH (s.nsi_id = 331)
CONNECT BY (nsi_parent_structure_id = PRIOR nsi_structure_id)
ORDER SIBLINGS BY ordnum;


SELECT * FROM V_NSI_CLASSIFIRE_GGS ;
----------------------------------------------------------------------------------
"NSI_STRUCTURE_ID"	"NSI_PARENT_STRUCTURE_ID"	"NSI_ID"	"NSI_TYPE_ID"	"ORDNUM"	"BEGIN_DATE"	"END_DATE"
385			13.02.20		331	5	Классификатор должностей ГГС
387	385	1	13.02.20		347	4	Руководители
389	387	1	13.02.20		355	3	Высшие
391	387	2	13.02.20		357	3	Главные
393	391	1	13.02.20		335	2	Начальник отдела
395	387	3	13.02.20		359	3	Ведущие
397	385	2	13.02.20		349	4	Помощники (советники)
399	397	1	13.02.20		355	3	Высшие
401	397	2	13.02.20		357	3	Главные
403	397	3	13.02.20		359	3	Ведущие
405	403	1	13.02.20		337	2	Советник
407	385	3	13.02.20		351	4	Специалисты
409	407	1	13.02.20		355	3	Высшие
411	407	2	13.02.20		357	3	Главные
413	407	3	13.02.20		359	3	Ведущие
415	413	1	13.02.20		341	2	Ведущий специалист
417	407	4	13.02.20		361	3	Старшие
419	385	4	13.02.20		353	4	Обеспечивающие специалист
421	419	1	13.02.20		357	3	Главные
423	419	2	13.02.20		359	3	Ведущие
425	419	3	13.02.20		361	3	Старшие
427	419	4	13.02.20		363	3	Младшие
429	427	1	13.02.20		345	2	Специалист 2 разряда
----------------------------------------------------------------------------------

Следует не забывать, что кроме отношения включения (в том числе и древовидного), существует отношение пересечения, то есть кросс-таблиц. Здесь добавляется дополнительное условие проверки пересечения по времени.

CREATE TABLE nsi_cross (
    nsi_cross_id        NUMBER(10) NOT NULL,
    nsi_main_id         NUMBER(10) NOT NULL,
    nsi_main_type_id    NUMBER(10) NOT NULL,
    nsi_detail_id       NUMBER(10) NOT NULL,
    nsi_detail_type_id  NUMBER(10) NOT NULL,
    begin_date          DATE NOT NULL,
    end_date            DATE,
    CONSTRAINT nsi_cross_pk PRIMARY KEY (nsi_cross_id),
    CONSTRAINT nsi_cross_main_nsi_fk FOREIGN KEY (nsi_main_type_id, nsi_main_id) REFERENCES nsi (nsi_type_id, nsi_id),
    CONSTRAINT nsi_cross_detail_nsi_fk FOREIGN KEY (nsi_detail_type_id, nsi_detail_id) REFERENCES nsi (nsi_type_id, nsi_id)
);

COMMENT ON TABLE nsi_cross IS 'НСИ. Кросс-таблица справочников';
COMMENT ON COLUMN nsi_cross.nsi_cross_id IS 'Ключ';
COMMENT ON COLUMN nsi_cross.nsi_main_id IS 'Ключ основной таблицы';
COMMENT ON COLUMN nsi_cross.nsi_main_type_id IS 'Тип справочника основной таблицы';
COMMENT ON COLUMN nsi_cross.nsi_detail_id IS 'Ключ таблици детализации';
COMMENT ON COLUMN nsi_cross.nsi_detail_type_id IS 'Тип справочника таблици детализации';
COMMENT ON COLUMN nsi_cross.begin_date IS 'Дата начала действия';
COMMENT ON COLUMN nsi_cross.end_date IS 'Дата окончания действия';

    /* Реализует проверку на пересечения периода действия записи кросс-таблицы.
    *  @param p_nsi_main_id nsi_cross.nsi_main_id%TYPE - справочник основной записи
    *  @param p_nsi_main_type_id nsi_cross.nsi_main_type_id%TYPE - тип справочника основной записи
    *  @param p_nsi_detail_id nsi_cross.nsi_detail_id%TYPE - справочник записи детализации
    *  @param p_nsi_detail_type_id nsi_cross.nsi_detail_type_id%TYPE - ттип справочника записи детализации
    *  @param p_begin_date DATE - дата начала действия записи
    *  @param p_end_date DATE - дата окончания действия записи
    */
    PROCEDURE nsi_cross_check_period (
        p_nsi_cross_id          IN nsi_cross.nsi_cross_id%TYPE,
        p_begin_date            IN nsi_cross.begin_date%TYPE, 
        p_end_date              IN nsi_cross.end_date%TYPE)
    AS
        v_cnt NUMBER;
        v_nsi_main_id           nsi_cross.nsi_main_id%TYPE;
        v_nsi_main_type_id      nsi_cross.nsi_main_type_id%TYPE;
        v_nsi_detail_id         nsi_cross.nsi_detail_id%TYPE;
        v_nsi_detail_type_id    nsi_cross.nsi_detail_type_id%TYPE;
    BEGIN
        IF (p_end_date IS NOT NULL) AND (Trunc(p_begin_date) > Trunc(p_end_date)) THEN
            RAISE_APPLICATION_ERROR (NSI_ERROR_CODE, 
                '[nsi_cross_check_period] Дата начала не может быть больше даты окончания ' || Trunc(p_begin_date) || ' - ' || Trunc(p_end_date)); 
        END IF;
        
        SELECT MIN(nsi_main_id), MIN(nsi_main_type_id),
               MIN(nsi_detail_id), MIN(nsi_detail_type_id) 
          INTO v_nsi_main_id, v_nsi_main_type_id,
               v_nsi_detail_id, v_nsi_detail_type_id 
          FROM nsi_cross
         WHERE nsi_cross_id = p_nsi_cross_id;
         
        v_cnt := 0;
        
        IF (v_nsi_main_id IS NOT NULL) THEN
        
            IF (p_end_date IS NOT NULL) THEN
                SELECT COUNT(*)
                  INTO v_cnt
                  FROM nsi_cross
                 WHERE nsi_main_id = v_nsi_main_id
                   AND nsi_main_type_id = v_nsi_main_type_id
                   AND nsi_detail_id = v_nsi_detail_id
                   AND nsi_detail_type_id = v_nsi_detail_type_id
                   AND nsi_cross_id <> p_nsi_cross_id
                   AND begin_date <= Trunc(p_end_date)
                   AND ((end_date IS NULL) OR (end_date >= Trunc(p_end_date)));
            ELSE
                SELECT COUNT(*)
                  INTO v_cnt
                  FROM nsi_cross
                 WHERE nsi_main_id = v_nsi_main_id
                   AND nsi_main_type_id = v_nsi_main_type_id
                   AND nsi_detail_id = v_nsi_detail_id
                   AND nsi_detail_type_id = v_nsi_detail_type_id
                   AND nsi_cross_id <> p_nsi_cross_id
                   AND ((
                        (end_date IS NOT NULL) AND (end_date >= Trunc(p_begin_date))
                        ) OR (end_date IS NULL)
                        );
            END IF;
        END IF;

        IF (v_cnt > 0) THEN
            RAISE_APPLICATION_ERROR (NSI_ERROR_CODE, 
                '[nsi_cross_check_period] Присутствует пересечение с периодом ' || p_begin_date || ' - ' || p_end_date);    
        END IF;
    END;


    /* Реализует вставку записи.
    *  @param p_nsi_main_id nsi_cross.nsi_main_id%TYPE - справочник основной записи
    *  @param p_nsi_main_type_id nsi_cross.nsi_main_type_id%TYPE - тип справочника основной записи
    *  @param p_nsi_detail_id nsi_cross.nsi_detail_id%TYPE - справочник записи детализации
    *  @param p_nsi_detail_type_id nsi_cross.nsi_detail_type_id%TYPE - ттип справочника записи детализации
    *  @param p_begin_date DATE - дата начала действия записи
    *  @param p_end_date DATE - дата окончания действия записи
    */
    PROCEDURE nsi_cross_insert (
        p_nsi_main_id           IN nsi_cross.nsi_main_id%TYPE,
        p_nsi_main_type_id      IN nsi_cross.nsi_main_type_id%TYPE,
        p_nsi_detail_id         IN nsi_cross.nsi_detail_id%TYPE,
        p_nsi_detail_type_id    IN nsi_cross.nsi_detail_type_id%TYPE,
        p_begin_date            IN nsi_cross.begin_date%TYPE, 
        p_end_date              IN nsi_cross.end_date%TYPE)
    AS
        v_id        NUMBER;
        v_log_descr nsi_log.descr%TYPE;
        v_type_id 	nsi.nsi_type_id%TYPE;
    BEGIN
        v_id := get_nsi_id;
        v_type_id := get_type_id('nsi_cross');

        INSERT INTO nsi_cross (
            nsi_cross_id, nsi_main_id, nsi_main_type_id,
            nsi_detail_id, nsi_detail_type_id, 
            begin_date, end_date)
        VALUES (
            v_id, p_nsi_main_id, p_nsi_main_type_id,
            p_nsi_detail_id, p_nsi_detail_type_id, 
            Trunc(p_begin_date), Trunc(p_end_date));

        nsi_cross_check_period (v_id, p_begin_date, p_end_date);

        v_log_descr := '[' || get_nsi_descr(p_nsi_main_id, p_nsi_main_type_id) || ' <=> ' || get_nsi_descr(p_nsi_detail_id, p_nsi_detail_type_id) || '] ';
        v_log_descr := v_log_descr || 'Период ' || p_begin_date || ' - ' || p_end_date;
        log_oper (v_id, v_type_id, NSI_LOG_OPERNUM_INSERT, v_log_descr);
    END nsi_cross_insert;


    /* Реализует обновление периода действия записи.
    *  @param p_nsi_cross_id nsi_cross.nsi_cross_id%TYPE - ключ nsi_cross
    *  @param p_begin_date nsi_cross.begin_date%TYPE - дата начала действия
    *  @param p_end_date nsi_cross.end_date%TYPE - дата окончания действия
    */
    PROCEDURE nsi_cross_period (
        p_nsi_cross_id  IN nsi_cross.nsi_cross_id%TYPE,
        p_begin_date    IN nsi_cross.begin_date%TYPE, 
        p_end_date      IN nsi_cross.end_date%TYPE)
    AS
        v_main_id 		    nsi_cross.nsi_main_id%TYPE;
        v_main_type_id 	    nsi_cross.nsi_main_type_id%TYPE;
        v_detail_id 		nsi_cross.nsi_detail_id%TYPE;
        v_detail_type_id 	nsi_cross.nsi_detail_type_id%TYPE;
        v_type_id 	        nsi.nsi_type_id%TYPE;
        v_log_descr         nsi_log.descr%TYPE;
    BEGIN
        v_type_id := get_type_id('nsi_cross');
        
        SELECT nsi_main_id, nsi_main_type_id,
               nsi_detail_id, nsi_detail_type_id
          INTO v_main_id, v_main_type_id,
               v_detail_id, v_detail_type_id
          FROM nsi_cross
         WHERE nsi_cross_id = p_nsi_cross_id;

        nsi_cross_check_period (p_nsi_cross_id, p_begin_date, p_end_date);

        UPDATE nsi_cross
           SET begin_date = Trunc(p_begin_date),
               end_date = Trunc(p_end_date) 
         WHERE nsi_cross_id = p_nsi_cross_id;
         
        v_log_descr := '[' || get_nsi_descr(v_main_id, v_main_type_id) || ' <=> ' || get_nsi_descr(v_detail_id, v_detail_type_id) || '] ';
        v_log_descr := v_log_descr || 'Период ' || p_begin_date || ' - ' || p_end_date;
        log_oper (p_nsi_cross_id, v_type_id, NSI_LOG_OPERNUM_UPDATE, v_log_descr);
    END;


    /* Реализует удаление записи.
    *  @param p_nsi_cross_id nsi_cross.nsi_cross_id%TYPE - ключ nsi_cross
    */
    PROCEDURE nsi_cross_delete (p_nsi_cross_id IN nsi_cross.nsi_cross_id%TYPE)
    AS
        v_type_id 	nsi.nsi_type_id%TYPE;
        v_log_descr nsi_log.descr%TYPE;
    BEGIN
        v_type_id := pkg_nsi.get_type_id('nsi_cross');
        
        FOR rec IN (
            SELECT nsi_cross_id, nsi_main_id, nsi_main_type_id,
                    nsi_detail_id, nsi_detail_type_id,
                    begin_date, end_date
            FROM nsi_cross
            WHERE nsi_cross_id = p_nsi_cross_id
        )
        LOOP
            v_log_descr := '[' || pkg_nsi.get_nsi_descr(rec.nsi_main_id, rec.nsi_main_type_id) || ' <=> ' || pkg_nsi.get_nsi_descr(rec.nsi_detail_id, rec.nsi_detail_type_id) || '] ';
            v_log_descr := v_log_descr || 'Период ' || rec.begin_date || ' - ' || rec.end_date;
            pkg_nsi.log_oper (rec.nsi_cross_id, v_type_id, pkg_nsi.NSI_LOG_OPERNUM_DELETE, v_log_descr);
        END LOOP;
        
        DELETE FROM nsi_cross
        WHERE nsi_cross_id = p_nsi_cross_id;
    END;

Всё, теперь мы с уверенностью можем сказать, что

закрыли первую проблему

.

Конечно можно много чего пытаться прикрутить к этой системе, но я думаю, что поставленную задачу в начале статьи я выполнила, а остальное уже можно рассмотреть в процессе дискуссии.

Материал подготавливался на версии Oracle 18c, хотя нативное поддержание формата json уже присутствует в версии 12. Здесь ссылка с архивом скриптов.

Нси в организациях и фирмах

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

Код ошибки:  Ошибки на приборной панели Шкода Октавия А7: виды, значение, коды, сброс и назначение EPC –

Существует несколько основных причин, по которым руководители крупных компаний стараются пользоваться системами нормативно-справочной информации в своих организациях:

Поскольку Росатом объединяет множество предприятий и организаций, создание общеотраслевых справочников является необходимым условием для централизации и обеспечения прозрачности закупочной деятельности и отношений с поставщиками, а также для организации совместной работы ИТ-систем предприятий отрасли.

Именно поэтому проект по созданию единой отраслевой системы нормативно-справочной информации (ЕОС НСИ) был включен в «Программу трансформации финансово-экономического блока и информационных технологий» Госкорпорации. Система ЕОС НСИ охватит организации блоков «инжиниринг и строительство атомных станций», «эксплуатация атомных станций», «жизненный цикл ядерного топлива».

К настоящему моменту завершен пилотный проект по созданию ЕОС НСИ. В его рамках создан ряд справочников: «Контрагенты» (дебиторы/кредиторы, юридические лица, резиденты/нерезиденты), «Материально-технические ресурсы» (МТР), «Элементы промышленных объектов», «Единый план счетов», набор общероссийских справочников и классификаторов.

Наиболее востребованными стали справочники «Контрагенты» (в настоящий момент содержит около 70 тыс. записей), «МТР» (около 150 тыс. записей) и «Единый план счетов». Уже в ходе пилотного проекта к ЕОС НСИ по справочнику «Контрагенты» были подключены 215 предприятий, по справочнику «МТР» – 35 предприятий. Всего в системе работает более 4 тыс. пользователей, их доступ обеспечен с помощью портального сервиса.

Сейчас ведутся работы по тиражированию системы. Ожидается, что к 2021 году общее число пользователей ЕОС НСИ достигнет порядка 10 тыс. человек. Таким образом, данный проект в области организации нормативно-справочной информации на платформе SAP станет одним из самых масштабных в мире и крупнейшим в Европе.

Результаты проекта и возможности ЕОС НСИ будут использованы в целом ряде других ИТ-проектов Госкорпорации «Росатом». Среди них – создание единой отраслевой системы закупок, единой отраслевой системы интеграции корпоративных приложений, единой отраслевой системы документооборота, системы управления имущественными активами, внедрение системы единого расчетного центра и др.

«Централизация процессов ведения нормативно-справочной информации и использование соответствующей информационной системы, во-первых, повысит качество и достоверность информации, предоставляемой ИТ-системами. Во-вторых, позволит снизить затраты и временя для формирования консолидированной отчетности.

В-третьих, минимизирует риски из-за неполноты или некорректности данных для платежей. Также это позволит оптимизировать и обеспечить прозрачность процессов закупок и работы с поставщиками, сократить время планирования закупок и снабжения МТР, оптимизировать процесс ведения НСИ за счет организации единой среды управления», – отметил руководитель направления по программе НСИ ЗАО «Гринатом» Кирилл Суковых
.

1. Историческое наследие

«Историческое наследие автоматизации в крупных компаниях и холдингах в подавляющем большинстве случаев плачевно: отдельные системы и «системки» работают на разных программных платформах и используют разные локальные справочники, никак не связанные между собой, что препятствует информационному обмену и консолидации данных.

Многие специалисты склонны в этой ситуации употреблять такие метафоры, как «лоскутная автоматизация» и «информационный зоопарк». Ключевым решением проблемы является создание Единой системы ведения нормативно-справочной информации, стандартизирующей и унифицирующей все информационные потоки внутри компании».

Эксперты НЦИТ «ИНТЕРТЕХ» по результатам анализа информационных систем, используемых в крупных компаниях и государственных структурах, пришли к следующим выводам:

  • большинство используемых прикладных систем построены на разных программно-аппаратных платформах;
  • прикладные системы не интегрированы между собой, в них используются нестандартизованные и отличающиеся по структуре и составу справочники;
  • отсутствует централизованная система поддержки доступа пользователей к нормативно-справочной информации;
  • в существующих справочниках недостаточно полно описываются объекты учета, не унифицированы их наименования, не стандартизована система кодирования;
  • при структуризации больших информационных массивов не используются классификаторы, облегчающие поиск требуемой информации.

2. Существующие проблемы

Выделим некоторые основные проблемы ведения НСИ, значительно увеличивающие материальные и трудовые затраты многих компаний и государственных структур на выполнение важных бизнес-процессов:

  • консолидации заявок для централизованных закупок и составление сводных заявок;
  • формирования и исполнения бюджета в части материально-технического обеспечения;
  • размещения и контроля исполнения заказов, контроля складских остатков;
  • учета и контроля движения материальных потоков по всей логистической цепочке;
  • формирования и оперативного предоставления статистической и аналитической информации, необходимой для принятия эффективных управленческих решений.

3. Решения

В качестве решения указанных проблем ИНТЕРТЕХ предлагает создание Единой системы ведения НСИ, увязывающей в общекорпоративное информационное пространство всю нормативно-справочную информацию подразделений, дочерних предприятий и партнеров компании.

Для реализации этого решения необходимо:

Разработать и принять стандарты и регламенты ведения НСИ:

  • Стандарт Компании «Состав и структура Единой системы ведения НСИ, систем классификации и кодирования».
  • Регламент использования подразделениями и дочерними предприятиями Единой системы ведения НСИ, систем классификации и кодирования.
  • Регламент ведения и сопровождения Единой системы ведения НСИ, систем классификации и кодирования.
  • Регламент обеспечения доступа пользователей компании к ресурсам Единой системы ведения НСИ и их технической поддержки.

Использовать методику онтологической классификации и кодирования, разработанную специалистами ИНТЕРТЕХ.

Методика позволяет стандартизировать действия специалистов-экспертов при осуществлении ими операций по классификации и кодированию групп (классов) объектов учета, определению свойств (признаков) классов и их значений, построению навигационных иерархий.

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

Внедрить автоматизированную систему, обеспечивающую:

  • поддержку принятой технологии классификации и кодирования информации;
  • доступ пользователей к ресурсам Единой системы ведения и управления НСИ – прямой, через web-интерфейс или через существующие прикладные системы;
  • работу служб сопровождения Единой системы ведения и управления НСИ, систем классификации и кодирования в соответствии с разработанным регламентом.

4. Этапы работ

Ниже приведены основные этапы работ по созданию Единой системы ведения и управления НСИ.

5. Суть подхода

Предлагаемый подход в своей основе опирается на принципы эволюционности, адаптивности, преемственности, стандартизации и унификации, учета человеческого фактора.

Эволюционность
развития системы предполагает пошаговый переход к современным принципам ведения и сопровождения корпоративной НСИ. Общая схема такого подхода выглядит следующим образом: старое -> старое новое -> новое, когда на промежуточных этапах допускается параллельное существование старой и новой систем.

Адаптивность
системы к специфике и ландшафтам существующих прикладных систем (включая системы ERP-класса), к используемым различным системам классификации и кодирования, предполагает способность системы интегрироваться с внешними системами.

Преемственность
позволяет сохранить все лучшее и ценное, что наработано годами и десятилетиями. Это касается использования потенциала специалистов НСИ, не нарушения функционирования действующих прикладных систем, возможностей миграции и преобразования накопленных информационных массивов.

Стандартизация и унификация
регламентов и методики использования и сопровождения корпоративной НСИ, систем классификации и кодирования, что позволяет обеспечивать постоянную актуальность и доступность НСИ в масштабах всей компании.

Учет человеческого фактора
подразумевает возможность работы в системе различных категорий пользователей, с разными навыками и «степенью продвинутости» в области информационных технологий, эргономичность дизайна и «дружественность» системных интерфейсов.

6. Программное обеспечение

Ontologiс 4.6 широко используется многими крупнейшими российскими компаниями в качестве платформы для MDM-решений. На данной платформе разработаны и внедрены системы управления НСИ (MDM) в таких компаниях, как ТНК-BP, Татнефть, СИБУР, ИНТЕГРА, Норникель, Трансмашхолдинг, Транснефть, ГОЗНАК, Полюс-Золото, НОВАТЭК и др.

С учетом опыта таких внедрений, компания «ИНТЕРТЕХ» поставляет готовое типовое решение для системы управления НСИ
.

Приказ фнс россии от 20.10.2020 n ед-7-19/765@
“об утверждении порядка ведения ведомственного классификатора документов, используемых налоговыми органами при реализации своих полномочий”

МИНИСТЕРСТВО ФИНАНСОВ РОССИЙСКОЙ ФЕДЕРАЦИИ

ФЕДЕРАЛЬНАЯ НАЛОГОВАЯ СЛУЖБА

ПРИКАЗ

от 20 октября 2020 г. N ЕД-7-19/765@

ОБ УТВЕРЖДЕНИИ ПОРЯДКА

ВЕДЕНИЯ ВЕДОМСТВЕННОГО КЛАССИФИКАТОРА ДОКУМЕНТОВ,

ИСПОЛЬЗУЕМЫХ НАЛОГОВЫМИ ОРГАНАМИ ПРИ РЕАЛИЗАЦИИ

СВОИХ ПОЛНОМОЧИЙ

В соответствии с пунктом 4 статьи 31 Налогового кодекса Российской Федерации (Собрание законодательства Российской Федерации, 1998, N 31, ст. 3824; 2021, N 27, ст. 4177) приказываю:

1. Утвердить порядок ведения ведомственного классификатора документов, используемых налоговыми органами при реализации своих полномочий (далее – Классификатор КНД), согласно приложению N 1 к настоящему приказу.

2. Структурным подразделениям центрального аппарата ФНС России:

2.1. При разработке и применении форм, используемых налоговыми органами при реализации своих полномочий, а также использования сведений, содержащихся в Классификаторе КНД, руководствоваться настоящим приказом.

2.2. В срок до 15.11.2020 обеспечить актуализацию информации в Классификаторе КНД.

3. Управлению интерактивных сервисов (Е.В. Гладышев) обеспечить:

3.1. Методологическое сопровождение соблюдения порядка ведения Классификатора КНД.

3.2. Дополнение информацией о Классификаторе КНД Перечня классификаторов (справочников), используемых в автоматизируемых информационных системах ФНС России, утвержденного приказом ФНС России от 26.08.2021 N ММВ-7-6/433@ “Об утверждении перечня классификаторов (справочников), используемых в автоматизированных информационных системах ФНС России”, согласно приложению N 2 к настоящему приказу.

3.3. Размещение информации о Классификаторе КНД в Перечне классификаторов (справочников), используемых в автоматизируемых информационных системах ФНС России, размещенном на Интранет-портале ФНС России.

3.4. Совместно с Управлением информационных технологий (В.П. Кулешов) организацию автоматизации формирования и ведения Классификатора КНД в установленном порядке.

4. Межрегиональной инспекции ФНС России по централизованной обработке данных N 2 (Б.Б. Толоко) обеспечить ведение Классификатора КНД.

5. Признать утратившим силу приказ ФНС России от 22.03.2021 N ММВ-7-17/235@ “Об утверждении Стандарта состава, структуры, порядка формирования и ведения ведомственного классификатора налоговых документов” с 15.01.2021.

6. Контроль за исполнением настоящего приказа возложить на заместителя руководителя Федеральной налоговой службы, координирующего вопросы организации разработки и внедрения системы стандартов деятельности и менеджмента качества ФНС России.

Руководитель

Федеральной налоговой службы

Д.В.ЕГОРОВ

Приложение N 1

Утвержден

приказом ФНС России

от “__” ______ 2020 г. N ___

ПОРЯДОК

ВЕДЕНИЯ ВЕДОМСТВЕННОГО КЛАССИФИКАТОРА

ДОКУМЕНТОВ, ИСПОЛЬЗУЕМЫХ НАЛОГОВЫМИ ОРГАНАМИ

ПРИ РЕАЛИЗАЦИИ СВОИХ ПОЛНОМОЧИЙ

I. Основные положения

1. Перечень терминов, сокращений и определений.

Для целей настоящего Порядка используются следующие термины, сокращения, обозначения:

Термин, сокращение, обозначение

Определение

ЕРВД

Прикладная подсистема “Единая регистрация входящих документов” АИС “Налог-3”

Категория хранения

Правило для определения порядка расчета срока архивного хранения документов: от даты смерти ФЛ или иной порядок

Классификатор КНД

Ведомственный классификатор документов, используемых налоговыми органами при реализации своих полномочий

Комментарий по сроку хранения

Примечание по сроку хранения из Перечня, которое комментирует и уточняет срок хранения документов

Код КНД

Код Формы документа присваиваемый в Классификаторе КНД

Код ОКУД

Код Формы документа присваиваемый в ОКУД

Методолог формы

Структурное подразделение центрального аппарата ФНС России в чью компетенцию входит методологическое и организационное обеспечение Формы документа

ОКУД

Общероссийский классификатор управленческой документации

Пакет изменений

Откорректированные (измененные) записи таблицы Классификатора КНД, объединенные в одну группу

Перечень

Перечень документов, образующихся в деятельности Федеральной налоговой службы и ее территориальных органов, и подведомственных организаций, с указанием сроков хранения, утвержденный приказом ФНС России от 15.02.2021 N ММВ-7-10/88@ (с изменениями и дополнениями)

Порядок

Порядок формирования и ведения Классификатора КНД

СЦВ НСИ

Прикладная подсистема централизованного ведения нормативно-справочной информации” АИС “Налог-3”

СМЭВ

Система межведомственного электронного взаимодействия

СУТ

Система управления требованиями

СП ЦА ФНС России, ответственные за методологию документооборота

Административно-контрольное управление, Управление электронного документооборота, Управление интерактивных сервисов, Управление информационных технологий

Форма документа

Формы документов, формы нормативно-справочной информации, форматы, не имеющие визуализированной формы, в том числе запросы, ответы и информация, отправляемые или поступающие через СМЭВ, разрабатываемые ФНС России или сторонним органом/организацией и используемые налоговыми органами при реализации своих полномочий

Формы нормативно-справочной информации

Классификаторы, справочники, словари, кодификаторы, нормативы, идентификаторы, используемые налоговыми органами при реализации своих полномочий

Эксперт

Межрегиональная инспекция ФНС России по централизованной обработке данных N 2, ответственная за ведение Классификатора КНД

2. Цель создания Ведомственного классификатора документов, используемых налоговыми органами при реализации своих полномочий.

Классификатор КНД является составной частью системы классификации и кодирования технико-экономической информации, форм документов, форм нормативно-справочной информации, форматов, не имеющих визуализированной формы документов, запросов, ответов и информации, отправляемых или поступающих через СМЭВ, используемых налоговыми органами при реализации своих полномочий.

3. Классификатор КНД разработан для решения следующих задач:

– обеспечения учета и систематизации Форм документов на основе их регистрации в Классификаторе КНД;

– обеспечения учета и систематизации способов представления и направления Форм документов за счет их указания в Классификаторе КНД;

– контроля за составом Форм документов, в том числе для целей обеспечения реализации требуемой технологии их приема, обработки, отправки;

– планирования перевода Форм документов в машиноориентированный вид и обеспечения контроля за таким переводом;

– сохранения сведений о Формах документов, утративших силу, но по которым, в течение определенного законодательством периода времени, должны отчитываться налогоплательщики;

– обеспечения автоматизации процедур по отправке (рассылке) Форм документов;

– обеспечения автоматизации процедур по выделению Форм документов к уничтожению;

– обеспечения корректного определения структурного подразделения центрального аппарата ФНС России, ответственного за методологическое сопровождение Форм документов.

II. Структура Классификатора КНД

4. Структура Классификатора КНД представляет собой таблицу, состоящую из столбцов и строк, представленную в приложении N 1 к Порядку.

5. Описание реквизитов Классификатора КНД представлено в таблицах N 1, N 2, N 3, N 4, N 5, N 6, N 7, N 8, приведенных ниже.

Таблица N 1. Описание основных реквизитов

Классификатора КНД

“Отменен” – соответствует дате вступления в силу нормативного правового акта или организационно-распорядительного документа ФНС России, которым утверждена новая Форма документа (либо Форма документа не применяется в силу изменений в действующем законодательстве), или, при необходимости использования Формы документа стороннего органа/организации – соответствует дате вступления в силу организационно-распорядительного документа стороннего органа/организации, утвердившего новую Форму документа, или принятия решения Методологом формы об отсутствии необходимости использования Формы документа стороннего органа/организации.

N/п

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

STATUS

9

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Статус документа

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“Проект” – на стадии разработки Формы документа до момента ее утверждения нормативным правовым актом или организационно-распорядительным документом ФНС России или, при необходимости использования Формы документа стороннего органа/организации – организационно-распорядительным документом стороннего органа/организации;

“Утвержден” – в случае утверждения Формы документа нормативным правовым актом или организационно-распорядительным документом ФНС России или, при необходимости использования Формы документа стороннего органа/организации – организационно-распорядительным документом стороннего органа/организации с отложенным сроком вступления в силу;

“Действует” – устанавливается на время действия Формы документа и соответствует дате вступления в силу нормативного правового акта или организационно-распорядительного документа ФНС России до его отмены или, при необходимости использования Формы документа стороннего органа/организации – с даты вступления в силу организационно-распорядительного документа стороннего органа/организации до принятия решения Методологом формы об отсутствии необходимости использования Формы документа стороннего органа/организации или его отмены;

2

KOD

7

Текстовое значение

Первые 4 знака выбираются Методологом формы из вспомогательного справочника со встроенным поисковиком (Таблица N 9), оставшиеся 3 знака присваиваются автоматически в СЦВ НСИ.

Код ОКУД выбирается из справочника OKUD

Код КНД или код ОКУД

СЦВ НСИ

Код Формы документа:

КНД состоит из семи цифровых десятичных знаков, принимающих вид ККППРРР, где:

КК – класс документов (признак, отражающий принадлежность к налоговым документам);

ПП – подкласс документов (признак, отражающий общность содержания подмножества налоговых документов и направленность их использования) в соответствии с приложением N 2 к Порядку;

РРР – регистрационный номер документа внутри подкласса.

3

NAIM

1000

Текстовое значение

Вводится вручную Методологом формы

Наименование Формы документа

Нормативная документация, являющаяся основанием разработки/использования формы

Наименование формы

4

PMO

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак машиноориентированности Формы документа

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“М” (машиноориентированная) для Форм документов, предназначенных для машинного ввода информации, или “Н” (немашиноориентированная)

5

PRNF

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак наличия формата

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” (формат отсутствует) или “1” (формат присутствует)

6

VER

2

Текстовое значение

Проставляется Методологом формы вручную

Версия

СЦВ НСИ

Применяется порядковая нумерация, где “01” – это исходная версия формы, а “02”, “03”, “04” и т.д. – каждая последующая версия формы.

7

TIP

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Тип

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“1” (первичный учетный документ, применяемый в целях бюджетного учета доходов) или “0” (документ, не являющийся первичным учетным документом, применяемым в целях бюджетного учета доходов)

8

KODSRHR

5

Вспомогательный справочник

(таблица N 2)

Выбирается Методологом формы из вспомогательного справочника

Код срока хранения

Нормативная документация, являющаяся основанием разработки/использования формы

Формат показателя “Срока хранения” представляет собой строку из 4 или 5 символов: “XX00” или “XXAAA”,

где “XX” – количество лет архивного хранения,

“00” – указывается по умолчанию,

“AAA” – буквенное обозначение.

9

STPER

7

Вспомогательный справочник

(таблица N 10)

Выбирается Методологом формы с помощью встроенного поисковика из вспомогательного справочника

Статья по Перечню

Перечень документов, образующихся в деятельности Федеральной налоговой службы России и ее территориальных органов и подведомственных организаций, с указанием сроков хранения, утвержденный приказом ФНС России от 15.02.2021 N ММВ-7-10/88@ (с изменениями и дополнениями)

Номер Статьи по Перечню

10

KODKOMSR

3

Вспомогательный справочник

(таблица N 3)

Выбирается Методологом формы с помощью встроенного поисковика из вспомогательного справочника

Код комментария

Нормативная документация, являющаяся основанием разработки/использования формы

Код Комментария по сроку хранения

11

KODKATSR

3

Вспомогательный справочник

(таблица N 4)

Выбирается Методологом формы из вспомогательного справочника

Код категории хранения

Нормативная документация, являющаяся основанием разработки/использования формы

Код категории хранения

12

PRTP

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак использования в технологических процессах

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” – отсутствует технологический процесс или “1” – технологический процесс присутствует, при этом осуществляется автоматический переход в отдельную таблицу для привязки КНД к технологическим процессам (таблица N 5) из справочника технологических процессов ФНС России (СТПФНС)

13

PRPO

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак получателя/отправителя

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значение:

“0” (не налогоплательщик) или “1” (налогоплательщик)

14

PRSPNP

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак способа направления/представления

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” – документ не направляется/не представляется, или “1” – документ представляется, или “2” документ направляется, или “3” – возможно, как направление, так и представление документа, при этом при выборе значения “1”, или “2”, или “3” осуществляется автоматический переход в отдельную таблицу (таблица N 6) для привязки КНД к способам направления/представления из вспомогательного справочника (таблица N 7). При этом при выборе “1” или “2” предоставляется возможность выбора и способов “3”. При выборе “3” предоставляются только способы “3”.

15

NOMPRNAP

3

Вспомогательный справочник (таблица N 8)

Выбирается из вспомогательного справочника Методологом формы

Номер правила направления

Нормативная документация, являющаяся основанием разработки/использования формы

Доступен к заполнению только при значении “2” или “3” в реквизите “Признак способа направления/представления”.

Для Форм со статусом “Проект” из вспомогательного справочника устанавливается номер “999” – “Требуется установление правила” до внесения изменений во вспомогательный справочник (таблица N 8), в соответствии с установленным исполнителем по государственному контракту в СУТ номером правила.

16

PRPODP

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак подписи

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” (подпись отсутствует) или “1” (подпись присутствует)

17

PRSN

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Совместное отправление

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” (не направляется совместно) или “1” (направляется совместно)

18

KATEG

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Категория почтового отправления

Нормативная документация, являющаяся основанием разработки/использования формы

Доступен к заполнению только в случае выбора кодов способов отправления/направления “На бумажном носителе (по почте)” или “Массовая печать и рассылка (по почте)”

Принимает значения:

“1” (простое), или “2” (заказное), или “3” (заказное с уведомлением)

19

KODSP

2

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника структурных подразделений ЦА ФНС России

Код СП ЦА ФНС России

Нормативная документация, являющаяся основанием разработки/использования формы

Код структурного подразделения центрального аппарата ФНС России

20

NAIMSP

100

Вспомогательный справочник

Заполняется автоматически в СЦВ НСИ при выборе кода СП ЦА ФНС России

Наименование СП ЦА ФНС России

СЦВ НСИ

Наименование структурного подразделения центрального аппарата ФНС России

21

KODKSV

2

Числовое значение

Заполняется Методологом формы вручную

Код контрольных сроков ввода

Нормативная документация, являющаяся основанием разработки/использования формы

Сроки ввода документов в АИС “Налог-3”, измеряемое в количестве рабочих дней, в соответствии с нормативной правовой или организационно-распорядительной документацией разработки/использования формы, в формате ДД

22

PROF

3

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак обработки формы документа

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” – в случае обработки документа налоговым органом или “1” – в случае обработки документа ФКУ “Налог-Сервис” ФНС России и его филиалах.

23

PRERVD

1

Вспомогательный справочник

Выбирается Методологом формы из вспомогательного справочника

Признак ЕРВД (единая регистрация входящих документов)

Нормативная документация, являющаяся основанием разработки/использования формы

Принимает значения:

“0” (не регистрируется в ЕРВД) или “1” (регистрируется в ЕРВД)

24

OSN

1000

Текстовое значение

Вносится Методологом формы вручную

Основание

Нормативная документация, являющаяся основанием разработки/использования формы

Реквизиты нормативного правового или организационно-распорядительного документа и наименование (для статуса проект – наименование проекта организационно-распорядительного документа). В случае раздельного утверждения формы и формата также указываются реквизиты нормативного правового или организационно-распорядительного документа, утвердившего формат и наименование

25

DATAN

10

формат даты

Вносится Методологом формы вручную

(автоматически проставляется текущая дата начала действия записи, равная дате ввода, возможная для редактирования)

Начало действия записи

Нормативная документация, являющаяся основанием разработки/использования формы

Дата начала действия записи

26

DATAK

10

формат даты

При внесении новой записи автоматически принимает значения в формате даты 01.01.3000

При внесении изменений автоматически устанавливается дата на один день раньше, чем дата начала действия для новой записи, проставляется автоматически

Окончание действия записи

СЦВ НСИ

Дата окончания действия записи

Таблица N 2 Описание дополнительных реквизитов Классификатора КНД, формирующих перечень сроков хранения (KNDSRHR).

NN п.п.

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

OPIS

100

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Описание срока хранения

Нормативная документация, регламентирующая хранение документации

Описание срока хранения

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSRHR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

2

KODSRHR

5

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Код срока хранения

Нормативная документация, регламентирующая хранение документации

Код срока хранения

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSRHR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Таблица N 3 Описание дополнительных реквизитов Классификатора КНД, формирующих перечень комментариев по срокам хранения (KNDKOMSR)

NN п.п.

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

KODKOMSR

3

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Код комментария

СЦВ НСИ

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDKOMSR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

2

OPIS

1000

Текстовое значение.

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Комментарий по сроку хранения

Нормативная документация, регламентирующая хранение документации

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDKOMSR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Таблица N 4 Описание дополнительных реквизитов Классификатора КНД, формирующих перечень категорий хранения (KNDKATSR)

NN п.п.

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

KODKATSR

3

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Категория хранения

Нормативная документация, регламентирующая хранение документации

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDKATSR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

2

OPIS

1000

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Описание категории хранения

Нормативная документация, регламентирующая хранение документации

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDKATSR в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Таблица N 5 Описание дополнительных реквизитов Классификатора КНД, формирующих связь КНД с Технологическими процессами (KNDTP)

Таблица N 6 Описание дополнительных реквизитов Классификатора КНД, формирующих связь КНД и способов направления/представления (KNDSPNAP)

Таблица N 7 Описание дополнительных реквизитов Классификатора КНД, формирующих способы направления/представления (KNDSP)

NN п.п.

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

KODSP

5

Текстовое значение

Вносится вручную СП ЦА ФНС России, ответственным за методологию документооборота

Код способа направления/представления

Нормативная документация, регламентирующая способы направления/представления документов

Код способа направления/представления

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSP в СЦВ НСИ, направленным СП ЦА ФНС России, ответственным за методологию документооборота

2

NAIM

250

Текстовое значение

Вносится вручную СП ЦА ФНС России, ответственным за методологию документооборота

Наименование способа направления/представления

Нормативная документация, регламентирующая способы направления/представления документов

Наименование способа направления/представления

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSP в СЦВ НСИ, направленным СП ЦА ФНС России, ответственным за методологию документооборота

3

PR

1

Текстовое значение

Вносится вручную СП ЦА ФНС России, ответственным за методологию документооборота

Признак способа представления/направления

Нормативная документация, регламентирующая способы направления/представления документов

Признак способа представления/направления

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSP в СЦВ НСИ, направленным СП ЦА ФНС России, ответственным за методологию документооборота и принимает значение:

1 (представление);

2 (направление);

3 (возможно как направление, так и представление)

Таблица N 8 Описание дополнительных реквизитов Классификатора КНД, формирующих правила направления (KNDPRNAP)

Таблица N 9 Описание дополнительных реквизитов Классификатора КНД, формирующих подклассы форм документов (KNDPODKL)

Таблица N 10 Описание дополнительных реквизитов Классификатора КНД, формирующих Перечень статей (KNDSTPER)

NN п.п.

Код реквизита

Длина

Тип поля

Алгоритм заполнения реквизита

Наименование реквизита

Источник данных для заполнения реквизита

Описание/примечание

1

STPER

7

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Статья по перечню

Перечень документов, образующихся в деятельности Федеральной налоговой службы России и ее территориальных органов и подведомственных организаций, с указанием сроков хранения, утвержденный приказом ФНС России от 15.02.2021 N ММВ-7-10/88@ (с изменениями и дополнениями)

Статья по перечню

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSTPER в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

2

NAIM

1000

Текстовое значение

Вносится вручную СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

Наименование статьи

Перечень документов, образующихся в деятельности Федеральной налоговой службы России и ее территориальных органов и подведомственных организаций, с указанием сроков хранения, утвержденный приказом ФНС России от 15.02.2021 N ММВ-7-10/88@ (с изменениями и дополнениями)

Наименование статьи

Акцептируется Экспертом в соответствии с пакетом изменения в справочник KNDSTPER в СЦВ НСИ, направленным СП ЦА ФНС России, в функции которого входит организация работы по комплектованию, хранению, учету и использованию архивных документов, образовавшихся в деятельности ФНС России

III. Порядок ведения Классификатора КНД

6. Классификатор КНД ведется на федеральном уровне Экспертом и Методологом формы.

Код ошибки:  obd2 диагностики ккл на АлиЭкспресс — купить онлайн по выгодной цене

7. Классификатор КНД ведется в СЦВ НСИ.

8. В целях работы с Классификатором КНД в шаблонах доступа предусмотрены и должны быть назначены пользователям Классификатора КНД функциональные роли в соответствии с описанием в приложении N 3 к Порядку.

9. При разработке/изменении Форм документов Методолог форм должен руководствоваться стандартами, утвержденными приказом ФНС России от 06.07.2021 N ММВ-7-17/535@.

За своевременность и достоверность сведений, вносимых в Классификатор КНД в СЦВ НСИ, несет ответственность Методолог форм.

За своевременность и достоверность сведений, вносимых во вспомогательные справочники Классификатора КНД в СЦВ НСИ, несут ответственность структурные подразделения ЦА ФНС России и Эксперт, на которых настоящим Порядком возложены соответствующие обязанности.

9.1. В Классификатор КНД в СЦВ НСИ Методологом форм вносятся сведения, указанные в п. 10 Порядка, в случае разработки/изменении Форм документов и при необходимости использования Форм документов стороннего органа/организации. Для этого осуществляют следующие процедуры:

9.2. В СЦВ НСИ формируется пакет изменений, в котором указывается основание внесения изменений в Классификатор КНД. Пакет изменений может содержать одну или несколько записей о Формах документов.

9.3. Далее в зависимости от желаемого результата выбираются:

– кнопка “Ввести”, которая применяется при вводе записей о новых Формах документов и присвоении им кода, начальной версии и заполнении всех реквизитов, а также при изменении Форм документов для указания их последующих версий и заполнении всех реквизитов;

– кнопка “Изменить”, которая применяется при изменении иных реквизитов, применимых к Формам документов в Классификаторе КНД, при сохранении их кода и версии;

– кнопка “Аннулировать”, которая применяется при отказе от реализации Форм документов, внесенных в Классификатор КНД со статусом “проект”.

9.4. После заполнения всех необходимых реквизитов и сохранения нажимается кнопка “Отправить”.

9.5. Отправленные Методологом форм пакеты изменений проверяются Экспертом на корректность заполнения реквизитов Классификатора КНД в СЦВ НСИ и либо акцептуются, либо направляются Методологу с сообщением о необходимости корректировки пакетов изменений.

9.6. При получении сообщения о необходимости корректировки пакетов изменений Методолог форм вносит соответствующие изменения, сохраняет и повторно направляет, нажав кнопку “Отправить”.

10. Порядок заполнения реквизитов Классификатора КНД:

10.1. Реквизит “Статус документа” выбирается Методологом формы из вспомогательного справочника и принимает значения:

“Проект” – на стадии разработки Формы документа до момента ее утверждения нормативным правовым актом или организационно-распорядительным документом ФНС России или, при необходимости использования Форм документов стороннего органа/организации, организационно-распорядительным документом стороннего органа/организации;

“Утвержден” – в случае утверждения Формы документа нормативным правовым актом или организационно-распорядительным документом ФНС России или, при необходимости использования Форм документов стороннего органа/организации, организационно-распорядительным документом стороннего органа/организации с отложенным сроком вступления в силу;

“Действует” – устанавливается на время действия Формы документа и соответствует дате вступления в силу нормативного правового акта или организационно-распорядительного документа ФНС России до его отмены или, при необходимости использования Форм документов стороннего органа/организации, с даты вступления в силу организационно-распорядительного документа стороннего органа/организации до принятия решения Методологом формы об отсутствии необходимости использования Формы документа стороннего органа/организации или его отмены;

“Отменен” – соответствует дате вступления в силу нормативного правового акта или организационно-распорядительного документа ФНС России, которым утверждена новая Форма документа (либо Форма документа не применяется в силу изменений в действующем законодательстве), или, при необходимости использования Форм документов стороннего органа/организации, соответствует дате вступления в силу организационно-распорядительного документа стороннего органа/организации, утвердившего новую Форму документа, или принятия решения Методологом формы об отсутствии необходимости использования Формы документа стороннего органа/организации.

10.2. Реквизит “Код КНД или код ОКУД” состоит из семи цифровых десятичных знаков. Для Кода принимает вид ККППРРР, где:

КК – 11 – класс документов (признак, отражающий принадлежность к документам, используемым налоговыми органами при реализации своих полномочий);

ПП – подкласс документов (признак, отражающий общность содержания подмножества документов, используемых налоговыми органами, и направленность их использования) в соответствии с приложением N 2 к Порядку;

РРР – регистрационный номер документа внутри подкласса.

При переходе к заполнению реквизита “Код” появляется сообщение: “Выбор” и две кнопки “КНД” и “ОКУД”.

Если это Форма документа налогового органа, то выбирается кнопка КНД и осуществляется переход к вспомогательному справочнику подклассов форм документов налогового органа (таблица N 9), первые 4 знака выбираются Методологом формы из вспомогательного справочника, оставшиеся 3 знака присваиваются автоматически.

Для Форм документов сторонних органов/организаций выбирается кнопка “ОКУД” и осуществляется переход к “Общероссийскому классификатору управленческой документации” (ОКУД). Методолог формы с помощью встроенного поисковика осуществляет выбор необходимой формы документа и внесения ее кода в Классификатор КНД. В случае отсутствия Формы документа стороннего органа/организации в ОКУД код присваивается как для Форм документов налогового органа.

10.3. Реквизит “Наименование” Формы документа вводится вручную Методологом формы без лишних пробелов, точно в соответствии с наименованием в проекте или утвержденном нормативном правовом документе, или организационно-распорядительном документе ФНС России, или при необходимости использования Форм документов стороннего органа/организации в соответствии с организационно-распорядительным документом стороннего органа/организации.

10.4. Реквизит “Признак машиноориентированности” выбирается Методологом формы из вспомогательного справочника и принимает значения “М” (машиноориентированная), если это Форма документа предназначена для входящего документа и предполагает оформление специальными метками для машинного ввода информации с нее, или “Н” (немашиноориентированная).

10.5. Реквизит “Признак наличия формата” выбирается Методологом формы из вспомогательного справочника и принимает значения “0” (формат отсутствует) или “1” (формат присутствует).

10.6. Реквизит “Версия” проставляется Методологом формы вручную с учетом порядковой нумерации, где “01” – это исходная версия Формы документа, а “02”, “03”, “04” и т.д. – каждая последующая версия. При этом версия изменяется только при внесении изменения в Форму документа. При внесении изменений в организационно-распорядительный документ об утверждении Формы документа, при изменении порядка заполнения Формы документа или порядка представления/направления версия не изменяется. Для машиноориентированных Форм документов версия указана в 4 и 5 знаке штрихкода.

10.7. Реквизит “Тип” выбирается Методологом формы из вспомогательного справочника и принимает значения “1” (первичный учетный документ, применяемый в целях бюджетного учета доходов) или “0” (документ, не являющийся первичным учетным документом, применяемым в целях бюджетного учета доходов).

10.8. Реквизит “Код срока хранения” выбирается Методологом формы из вспомогательного справочника (Таблица N 2) в соответствии с Перечнем документов, образующихся в деятельности Федеральной налоговой службы, ее территориальных органов и подведомственных организаций, с указанием сроков хранения. Формат показателя “Срок хранения” представляет собой строку из 4 или 5 символов: “XX00” или “XXAAA”, где “XX” – количество лет архивного хранения, “00” – указывается по умолчанию, “AAA” – буквенное обозначение.

10.9. Реквизит “Статья по Перечню” выбирается Методологом формы с помощью встроенного поисковика из вспомогательного справочника (Таблица N 10), который сформирован из Перечня.

10.10. Реквизит “Код комментария” выбирается Методологом формы из вспомогательного справочника (Таблица N 3) с помощью встроенного поисковика, который сформирован из Перечня.

10.11. Реквизит “Код категории хранения” выбирается Методологом формы из вспомогательного справочника (Таблица N 4), который сформирован из Перечня.

10.12. Реквизит “Признак использования в технологических процессах” выбирается Методологом формы из вспомогательного справочника и принимает значение “0” – отсутствует технологический процесс или “1” – технологический процесс присутствует, при этом осуществляется автоматический переход в отдельную таблицу для привязки КНД к технологическим процессам (таблица N 5) из справочника технологических процессов ФНС России (СТПФНС).

Методолог формы с помощью встроенного поисковика выбирает код технологического процесса. После нажатия кнопки “Выбрать”, появляется сообщение: “Используется ли данная форма в других технологических процессах?”. Если Форма документа не используется, то Методолог формы выбирает кнопку “Нет” и осуществляется переход к следующему реквизиту Классификатора КНД, если Форма документа используется в других технологических процессах, то при выборе кнопки “Да” автоматически осуществляется переход на встроенный поисковик для выбора другого технологического процесса.

Если структурное подразделение ЦА ФНС России планирует использовать Форму документа, Методологом которой не является, в своем технологическом процессе, то необходимо служебной запиской проинформировать о данных намерениях Методолога формы. При получении такой служебной записки Методолог формы должен в течение рабочего дня внести соответствующие изменения в справочник КНД.

10.13. Реквизит “Признак получателя/отправителя” выбирается Методологом формы из вспомогательного справочника и принимает значение “0” (не налогоплательщик) или “1” (налогоплательщик).

10.14. Реквизит “Признак способа направления/представления” выбирается Методологом формы из вспомогательного справочника и принимает значение “0” – документ не направляется/не представляется, или “1” – документ представляется, или “2” – документ направляется, или “3” – возможно как направление, так и представление.

При выборе “1”, или “2”, или “3” осуществляется автоматический переход в отдельную таблицу (таблица N 6) для привязки КНД к способам направления/представления из вспомогательного справочника (таблица N 7). При этом при выборе “1” или “2” предоставляется возможность выбора и способов “3”, при выборе “3” предоставляются только способы “3”.

Методолог формы выбирает способ направления/представления из выпадающего списка в соответствии с выбранным признаком направления/представления. После нажатия кнопки “Выбрать” появляется сообщение “Выбрать следующий способ?”. Если способ единственный, то Методолог формы выбирает кнопку “Нет” и осуществляется переход к следующему реквизиту классификатора КНД, если Форма документа может направляться/представляться другими способами, то при выборе кнопки “Да” автоматически осуществляется переход на список для выбора следующего способа направления/представления.

10.15. Реквизит “Номер правила направления” заполняется только если выбран реквизит “Признак способа направления/представления” со значением “2” или “3”.

В случае Формы документа со статусом “Проект” Методологом формы из вспомогательного справочника устанавливается номер “999” – “Требуется установление правила” и осуществляется подача заявки в СУТ на присвоение “Номера правила направления”. Исполнитель по государственному контракту устанавливает номер правила направления и доводит данную информацию через СУТ до Методолога формы не позднее 5 рабочих дней со дня подачи заявки. После присвоения номера правила направления Методолог формы вносит изменения в СЦВ НСИ, выбирая из вспомогательного справочника (таблица N 8) необходимый номер правила. При этом, без внесения номера правила направления исключено изменение статуса “Проект”.

При необходимости изменения правила направления Формы документа Методолог формы направляет заявку в СУТ на присвоение номера нового правила направления Формы документа, и до внесения в СЦВ НСИ изменений в части реквизита “номер правила направления” действует предыдущий номер правила.

При отсутствии правила во вспомогательном справочнике (таблица N 8), Исполнитель по государственному контракту после установления правила в СУТ направляет Эксперту реквизиты для наполнения вспомогательного справочника (таблица N 8).

10.16. Реквизит “Признак подписи” выбирается Методологом формы из вспомогательного справочника и принимает значения “0” (подпись отсутствует) или “1” (подпись присутствует).

10.17. Реквизит “Совместное отправление” выбирается Методологом формы из вспомогательного справочника и принимает значения “0” (не направляется совместно) или “1” (направляется совместно).

10.18. Реквизит “Категория почтового отправления” заполняется, только если выбран код способа отправления/направления “На бумажном носителе (по почте)” или “Массовая печать и рассылка (по почте)”. Выбирается Методологом формы из вспомогательного справочника и принимает значения “1” (простое), или “2” (заказное), или 3 (заказное с уведомлением).

10.19. Реквизит “Код СП ЦА ФНС России” выбирается Методологом формы из вспомогательного справочника структурных подразделений ЦА ФНС России.

10.20. Реквизит “Наименование СП ЦА ФНС России” автоматически проставляется из вспомогательного справочника структурных подразделений ЦА ФНС России при выборе кода СП ЦА ФНС России.

10.21. Реквизит “Код контрольных сроков ввода” проставляется Методологом формы вручную. Принимает числовое значение, измеряемое в количестве рабочих дней, в формате ДД, и устанавливается Методологом формы документа в соответствии с нормативной правовой или организационно-распорядительной документацией, являющейся основанием разработки/использования Формы документа.

10.22. Реквизит “Признак обработки формы документа” выбирается Методологом формы из вспомогательного справочника и принимает значения “0” – в случае обработки документа налоговым органом или “1” – в случае обработки документа ФКУ “Налог-Сервис” ФНС России и его филиалами.

10.23. Реквизит “Признак ЕРВД” выбирается Методологом формы из вспомогательного справочника и принимает значения “0” (не регистрируется в ЕРВД) или “1” (регистрируется в ЕРВД).

10.24. Реквизит “Основание” вводится Методологом формы вручную. При этом указываются реквизиты нормативного правового или организационно-распорядительного документа и наименование (для статуса “проект” указывается только наименование). В случае раздельного утверждения Формы документа и формата также указываются реквизиты нормативного правового или организационно-распорядительного документа, утвердившего формат, и наименование.

10.25. Реквизит “Начало действия записи”: автоматически проставляется текущая дата начала действия записи, равная дате ввода, возможная для редактирования Методологом формы.

10.26. Реквизит “Окончание действия записи” при внесении новой записи автоматически принимает значение в формате даты 01.01.3000, а при внесении изменений автоматически устанавливается дата на один день раньше, чем дата начала действия для измененной записи.

Приложение N 1

к Порядку ведения ведомственного

классификатора документов,

используемых налоговыми органами

при реализации своих полномочий”,

утвержденному приказом ФНС России

от ______ N ___

ВЕДОМСТВЕННЫЙ КЛАССИФИКАТОР

ДОКУМЕНТОВ, ИСПОЛЬЗУЕМЫХ НАЛОГОВЫМИ ОРГАНАМИ

ПРИ РЕАЛИЗАЦИИ СВОИХ ПОЛНОМОЧИЙ (КНД)

статус документа

код КНД или код ОКУД

наименование

признак машиноориентированности

признак наличия формата

версия

тип

код срока хранения

статья по перечню

код комментария

код категории хранения

признак использования в технологических процессах

признак получателя/отправителя

признак способа направления/представления

номер правила направления

признак подписи

совместное отправление

Категория почтового отправления

код СП ЦА ФНС России

Наименование СП ЦА ФНС России

код контрольных сроков ввода

признак обработки формы документа

признак ЕРВД

Основание

начало действия записи

окончание действия записи

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

1 – “проект”,

2 – “утвержден”

3 – “действует”

4 – “Отменен”,

0000000

текст

принимает значения: “М” (машиноориентированная) или “Н” (немашиноориентированная

0 – формат отсутствует,

1 – формат присутствует

00

0 – документ не является первичным учетным документом,

1 – первичный учетный документ

текст из вспомогательного справочника

текст из вспомогательного справочника

текст из вспомогательного справочника

текст из вспомогательного справочника

0 – отсутствует технологический процесс,

1 – технологический процесс присутствует

0 (не налогоплательщик),

1 (налогоплательщик)

“0” – документ не направляется/не представляется

“1” – документ представляется

“2” – документ направляется,

“3” – возможно, как направление, так и представление документа

текст из вспомогательного справочника

“0” (подпись отсутствует)

“1” (подпись присутствует)

“0” (не направляется совместно)

“1” (направляется совместно)

“1” (простое),

“2” (заказное),

“2” (заказное с уведомлением)

текст из вспомогательного справочника

текст из вспомогательного справочника

числовое значение, измеряемое в количестве рабочих дней, в формате ДД

“0” – в случае обработки документа налоговым органом)

“1” (в случае обработки документа ФКУ “Налог-Сервис” ФНС России и его филиалах

“0” (не регистрируется в ЕРВД)),

“1” (регистрируется в ЕРВД)

текст

ДД.ММ.ГГГГ

ДД.ММ.ГГГГ

Перечень КНД в привязке к технологическим процессам

Перечень КНД в привязке к способам направления/представления

Приложение N 2

к Порядку ведения ведомственного

классификатора документов,

используемых налоговыми органами

при реализации своих полномочий”,

утвержденному приказом ФНС России

от ______ N ___

ПОДКЛАССЫ ФОРМ ДОКУМЕНТОВ

Подкласс

Наименование подкласса

Документы, необходимые при осуществлении процедур учета налогоплательщиков и контрольно-кассовой техники, лицензирования и учета деятельности юридических и физических лиц, а также для установления обязанности уплаты налогов и сборов:

10

документы, представляемые в налоговые органы налогоплательщиками всех категорий

11

документы, представляемые в налоговые органы российскими организациями

12

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

13

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

14

документы, представляемые в налоговые органы внешними организациями и частными нотариусами в порядке выполнения требований статей 85 и 86 Налогового кодекса Российской Федерации

15

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

Документы, выдаваемые (высылаемые) налоговыми органами при осуществлении процедур учета налогоплательщиков и контрольно-кассовой техники, лицензирования и учета деятельности юридических и физических лиц:

20

документы, выдаваемые (высылаемые) налогоплательщикам всех категорий

21

документы, выдаваемые (высылаемые) налогоплательщикам – юридическим лицам

22

документы, выдаваемые (высылаемые) налогоплательщикам – физическим лицам

23

документы, выдаваемые (высылаемые) внешним организациям

24

документы, выдаваемые (высылаемые) налогоплательщикам акцизов

25

иные документы, выдаваемые (высылаемые) налогоплательщикам

Документы, которыми обмениваются налоговые органы:

31

при осуществлении процедур учета налогоплательщиков – юридических лиц

32

при осуществлении процедур учета налогоплательщиков – физических лиц

33

при осуществлении процедур учета контрольно-кассовой техники

34

при осуществлении процедур учета поступающих платежей

Документы, ведущиеся в налоговых органах (журналы, реестры, листы учета и т.п.):

40

при осуществлении процедур лицензирования и учета деятельности юридических и физических лиц

41

при осуществлении процедур учета налогоплательщиков – юридических лиц

42

при осуществлении процедур учета налогоплательщиков – физических лиц

43

при осуществлении процедур учета контрольно-кассовой техники

44

по учету контрольно-проверочной работы

45

по учету налогов и сборов

46

по бухгалтерскому учету

47

по учету сообщений и бланков сообщений о счетах налогоплательщиков

48

Прочая документация, ведущаяся в налоговых органах

Документы, поступающие в налоговые органы от налогоплательщиков, связанные с уплатой налогов, в т.ч. по налоговой отчетности (налоговые декларации, расчеты, справки, уведомления и т.д.):

50

заявления, уведомления, сообщения, реестры счетов-фактур и т.д., представляемые налогоплательщиками в налоговые органы

51

декларации, расчеты, справки, представляемые в налоговые органы в связи с уплатой федеральных налогов

52

декларации, расчеты, справки, представляемые в налоговые органы в связи с уплатой региональных налогов

53

декларации, расчеты, справки, представляемые в налоговые органы в связи с уплатой местных налогов

54

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

55

документы, предусмотренные статьей 165 главы 21 Налогового кодекса РФ (часть вторая), подтверждающие применение налоговой ставки 0 процентов по налогу на добавленную стоимость

60

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

70

Платежные документы

75

Прочие первичные учетные документы

Прочие документы, обеспечивающие деятельность ФНС России:

80

Отчетные и справочные документы (о работе по учету налогоплательщиков; по поступлениям налоговых платежей, задолженностям, штрафам и пеням; по контрольно-проверочной деятельности

84

Форматы, не имеющие визуализированных форм

87

Формы общероссийских классификаторов и справочников

88

Формы ведомственных классификаторов и справочников ФНС России

89

Формы отраслевых классификаторов и справочников министерств и ведомств России

90 – 99

Документы субъектов Российской Федерации

Приложение N 3

к Порядку ведения ведомственного

классификатора документов,

используемых налоговыми органами

при реализации своих полномочий”,

утвержденному приказом ФНС России

от ______ N ___

ПЕРЕЧЕНЬ

ШАБЛОНОВ ДОСТУПА И РОЛЕЙ В НИХ ДЛЯ ФОРМИРОВАНИЯ И ВЕДЕНИЯ

ВЕДОМСТВЕННОГО КЛАССИФИКАТОРА ДОКУМЕНТОВ, ИСПОЛЬЗУЕМЫХ

НАЛОГОВЫМИ ОРГАНАМИ ПРИ РЕАЛИЗАЦИИ СВОИХ ПОЛНОМОЧИЙ

Шаблон

Описание шаблона

Категория пользователей шаблона

Роль

Описание роли

ФЦОД.

Методологи СП ЦА ФНС

Подготовка заявок для обеспечения внесения изменений в справочники федерального уровня

Специалисты СП ЦА ФНС России, ответственные за внесение изменений в справочники федерального уровня

ФЦОД.

Методолог КНД

Роль Методологов форм, ответственных за подготовку пакетов изменений в Справочнике КНД и направления их на акцептование

ФЦОД.

Эксперты СП ЦА ФНС

Акцептование (публикация в эталонные справочники СЦВ НСИ) изменений, внесенных в справочники федерального уровня

Специалисты СП ЦА ФНС России, ответственные за акцептование (публикацию в эталонные справочники СЦВ НСИ) изменений, внесенных в справочники федерального уровня

Специалисты Межрегиональной инспекция ФНС России по централизованной обработке данных N 2

ФЦОД.

Эксперт КНД

Роль Эксперта, ответственного за акцептование (публикацию) изменений в справочнике КНД

НСИ.

Пользователь

Просмотр справочников

Сотрудники центрального аппарата ФНС России,

Сотрудники управлений ФНС России по субъектам Российской Федерации,

Сотрудники ИФНС России,

Сотрудники ФКУ “Налог-Сервис” ФНС России,

Сотрудники ФКУ “Налог-Сервис” по ЦОД, Сотрудники МИ ФНС России по ЦОД, МИ ФНС России по ценам,

Сотрудники межрегиональных инспекций по крупнейшим налогоплательщикам,

Сотрудники межрегиональных инспекций по федеральным округам, МИ ФНС России по камеральному контролю

ФЦОД.

Пользователь НСИ

Просмотр КНД

Приложение N 2

к приказу ФНС России

от “__” ______ 2020 г. N ___

ПЕРЕЧЕНЬ

КЛАССИФИКАТОРОВ (СПРАВОЧНИКОВ), ИСПОЛЬЗУЕМЫХ

В АВТОМАТИЗИРОВАННЫХ ИНФОРМАЦИОННЫХ СИСТЕМАХ ФНС РОССИИ

Оцените статью
OBD
Добавить комментарий

Adblock
detector