{------------------------------------------------------------------------------}
var
  { exchange #3081
    файл: settings\TypeKBK.set
    используется для определения типа кбк.}
  v3081_TypeKBK_Set_File: TStringList;
{------------------------------------------------------------------------------}
procedure InitializationSPD;
begin

    try
      // загружаем файл
      if (v3081_TypeKBK_Set_File = NIL)
        then v3081_TypeKBK_Set_File:= LoadSettings(
                                              DirIni + 'Settings\TypeKBK.set');
      except
        ExceptionProc( 'InitializationSPD');
    end;

end;
{------------------------------------------------------------------------------}
procedure FinalizationSPD;
begin

    try
      if (v3081_TypeKBK_Set_File <> NIL) then begin
        v3081_TypeKBK_Set_File.Free;
        v3081_TypeKBK_Set_File := NIL;
      end;
      except
        ExceptionProc( 'FinalizationSPD');
    end;

end;
{------------------------------------------------------------------------------}
procedure Exch2436_Builder199Info_By_SP( aNode: Variant;
                                          var aDocInfo: string);
begin

    try
      // формируем новый ЭД
      aDocInfo := FORMAT( '"Справка по операциям БУ/АУ" № %s Дата: %s',
                          [ aNode.GetAttribute('NUM_DOC'),
                            aNode.GetAttribute('DATE_SP')]);
      except
        ExceptionLog( 'Сбой Exch2436_Builder199Info_By_SP');
    end;

end;
{------------------------------------------------------------------------------}
{~Exch2436_Parse_SPD
  exchange #2436
  первичная проверка файла (aXML).
  возвращает:
  exchange #2523 - изменен результат на:
    =1 - если есть хотя бы один ЭД, который можно создать по файлу.
          в результате файл перенести в архив.
    =0 - нет ни одного ЭД который можно создать из файла.
          файл должен остаться как есть.
    =2 - найдены ЭД для загрузки, но в конце должен остаться как есть.
    =3 - нет ни одного ЭД который можно создать из файла.
          это вариант, когда все эд определены как повторно загруженные.
          файл переносится в архив.

    по #2523 это даст вариант обработки файла:
1) все ЭД могут быть загружены (считая повторно загружаемые) - перенос в архив
2) есть эд, которые могут быть загружены, но есть и те, которые не загружаемые - остается как есть
3) ни один эд не загружается (+могут быть повторно загружаемые) - остается как есть
4) ни один эд не загружается - только как повторно загруженные - перенос в архив

    формирует массив маркеров aDocArray для каждого раздела XML. число
  элементов в массиве больше или равно числу разделов в aXML.
  при первом проходе (в этой подпрограмме) анализируются разделы SPD и SPRR.
  если ЭД в SPD можно создать, то в массиве, соответствующий аздел SPD и
  строки SPRR маркируются.
    Второй проход - создание ЭД по разделам уже не анализирует XML, а формирует
  ЭД по разделам XML. чтобы повторно не анализировать SPD и строки SPRR
  как раз и нужен массив маркеров. т.е. если раздел XML маркируется
  пригодным для формирования ЭД, этот раздел используется для формирования XML
  уже без проверки. все необходимые данные должны быть подготовлены в первом
  проходе.
    такая схема дает возможность проанализировать весь входной файл на предмет
  какие ЭД можно формировать и предложить пользователю: продолжить или нет,
  еще до создания хоть какого либо документа, в отличие от вариантов, когда
  на ходу создаются XML документов, и при этом выполняется их анализ и создание.
  в этом случае часть ЭД может быть документов может быть создана, а часть
  проигнорирована, а результат анализа будет известен в конце такого алгоритма.
  значения элементов массива:
    =0 - раздел не анализируется при формировании ЭД;
    =1 - ЭД может быть создан по SPD/SPRR;
    =-1 - для раздела SPD/SPRR ЭД не должен создаваться. при этом нужно
          проигнорировать последующие разделы SPRR с маркерами -2 и 2.
    =2 - строка SPRR должна включаться в ЭД;
    =-2 -строка SPRR не должна включаться в ЭД.

   Количество всех ЭД в файле - xDocCountAll
   Количество загружаемых ЭД - xDocCount
   Количество повторно найденных ЭД - xDocCountExists

   эти счетчики нужны чтобы в конце определить, что делать с файлом: перенести
   в архив или оставить.

    exchange #2600
   добавлены дополнительные поля
   добавлен параметр aTO_BudgetLevel - значение TO.BudgetLevel.}
function Exch2436_Parse_SPD( var aNode: Variant;
                             aBudgetID: string;
                             aLS, aLS_ID: string;
                             var aDocInfo: string;
                             var aDocCountExists: integer;
                             var aSPD_NameDoc: string): boolean;
var
  xSPD_NameDoc: string;
  xGUID_FK: string;
begin

    try
      // пока считаем что в ЭД нет ни одной строки
      Result    := FALSE;
      // проверяем новый ЭД
      Exch2436_Builder199Info_By_SP( aNode, aDocInfo);
      {
      aDocInfo := FORMAT( '"Справка по операциям БУ/АУ" № %s Дата: %s',
                          [ aNode.GetAttribute('NUM_DOC'),
                            aNode.GetAttribute('DATE_SP')]);
                            }

      { Реализовать создание «Справок по операциям БУ/АУ» только
        по блокам SPD, в которых NAME_DOC =
        «Объявление на взнос наличными»,
        «Расшифровка неиспользованных средств по банковским картам»
        или «Платежное поручение» }
      xSPD_NameDoc := GetNodeAttributeEx( aNode, 'NAME_DOC');
      // exchange #2600
      // чтобы упростить дальнейший анализ параметров при создании
      // ЭД 199го класса, поскольку тут будет проверяться значение
      // поля NAME_DOC, тут создадим идентификацию этих значений
      // более коротким значением в новом поле.
      case LOWERCASE( xSPD_NameDoc) of
        'объявление на взнос наличными',
        'платежное поручение':
             aNode.SetAttribute('NAME_DOC__', '1');

        // exchange #2848 - добавлено новое значение
        'расшифровка сумм неиспользованных (внесенных через банкомат'
       +' или пункт выдачи наличных денежных средств) средств',
        'расшифровка неиспользованных средств по банковским картам':
             aNode.SetAttribute('NAME_DOC__', '3');

        // exchange #2600
        'справка ф. 0504833',
        'справка ф.0504833',
        'справка ф. 0504833 по внебанковским операциям',
        'справка ф.0504833 по внебанковским операциям':
             aNode.SetAttribute('NAME_DOC__', '2');

        else begin
                WriteInfo( FORMAT( 'По документу с названием "%s" не будет создан ЭД %s.',
                                    [ xSPD_NameDoc,
                                      aDocInfo]));
                // игнорируем блок SPD и его SPRR
                EXIT;
              end;
      end;//case//

      // exchange #2484
      // проверяем ЭД на повторную загрузку: если в системе уже
      // есть 199 класс со значением поля Foreign_Key, равным
      // значению поля SPD.GUID_FK, не создавать по данному блоку
      // SPD 199 класс, записывать в лог сообщение о том,
      // что документ не создан по причине непрохождения проверки
      // на повторную загрузку.
      // причем если поле SPD.GUID_FK не заполнено ЭД тоже не
      // должен создаваться. этого нет в задании но согласовано с АО.
      // при этом учитывать, что для удаленных ЭД гуид не проверять
      xGUID_FK := GetNodeAttributeEx( aNode, 'GUID_FK');

      if (LENGTH( xGUID_FK) <= 0) then begin
        WriteInfo( 'АЦК: ' + aDocInfo);
        WriteInfo( 'Не заполнено обязательное служебное поле SPD.GUID_FK.');
        EXIT;
      end;
      // exchange #2617
      // здесь необходимо отключать кэш.
      // иначе, если загружаются несколько файлов но с одними
      // и теми же данными, то с кэшировании запрос берется из кеша
      // и на повторных данных срабатывает ложно, поэтому при
      // поиске дублей ЭД кэш необходимо отключать.
      // однако это будет больше нагружать сервер.
      if (QueryField( ' select count( * ) N from moneytransferorder m '
                     +' where m.foreign_key=? and m.dispstatus_id>-1',
                      [ xGUID_FK],
                      'N',
                      FALSE) <> '0') then begin
        WriteInfo( 'АЦК: ' + aDocInfo);
        WriteInfo( 'Повторная загрузка документа - пропущен.');
        // exchange #2523
        // при повторной загрузке ЭД считаем что ЭД загружен из файла.
        // это даст то, что если часть ЭД загружена, а часть ЭД нет
        // по причине повторной загрузки, то файл будет перенесен
        // в архив.
        INC( aDocCountExists);

        EXIT;
      end;

      // сохраняем промежуточное определение идентификатора
      // названия документа
      aSPD_NameDoc := GetNodeAttributeEx( aNode, 'NAME_DOC__');

      // будем формировать ЭД
      Result := TRUE;

      except
        ExceptionLog( 'Сбой Exch2436_Parse_SPD');
    end;

end;
{------------------------------------------------------------------------------}
{~DoCheck2600_ParamsDetail
  выполняет проверку КОСГУ, КВФО, а так же определяет отраслевой код и
  код субсидии с учетом проверенных КОСГУ и КВФО.
  Результат:
    =true - все успешно проверено.
    =false - ошибка при проверке. сообщение с ошибкой отображается
              в этой подпрограмме.
  Параметры:
     aLS_ID - ид.счета
     aDocInfo - строка описания ЭД;
     aKES - КОСГУ: вх - проверяемый код/вых - проверенный код
     aKIF - КВФО: вх - проверяемый код/вых - проверенный код
     aINDUSTRYCODE_ID - вых - найденный отраслевой код
     aGRANTINVESTMENT_ID - вых - найденный код субсидии.

  exchange #3081
    добавлен код КВР.
    выбор загрузки косгу/квр определяется по типу строки.
    тип строки определяется по файлу typekbk.set.

    Если строка ЭД формируется на основании поля «DEBET»:
       тип классификации:
          «Расходы» , направление операции «выплаты»;
          «Доходы», направление операции «возврат поступлений»;
          «Источники», направление операции «не указано»;
    Если строка ЭД формируется на основании поля «KREDIT»
        тип классификации:
        exchange #3126
          «Расходы», направление операции «восстановление выплат»;
          «Доходы», направление операции «поступление»;
          «Источники», направление операции «не указано»; }
function DoCheck2600_ParamsDetail( aBudgetID: string;
                                   aCode_Value: string;
                                   aLS, aLS_ID, aOrgID: string;
                                   aDocInfo: string;
                                    aXmlLine: Variant;
                                    aPrefix: string;
                                    aIsKredit: boolean): boolean;
var
  xFillKES: boolean;
  xINDUSTRYCODE_ID: string;
  xGRANTINVESTMENT_ID: string;
  xKBK_Type: string;
  xKES: string;
  xKVR: string;
  xKIF: string;
  xCode: string;
begin

    try
      Result := FALSE;
      {---------------------------------------------------------}
      // тип классификации определять в настроечном файле TypeKBK.set
      // по значениям с 19 по 26 знак анализируемых полей DEBET или KREDIT
      // (алгоритм тот же, что и для формирования справок для казенных
      // учреждений).
      xKBK_Type := FindSettingsType2( COPY( aCode_Value, 19, 8),
                                      v3081_TypeKBK_Set_File);
      case xKBK_Type of
        // доходы
        '20': aXmlLine.SetAttribute( aPrefix + 'CR_ANAL_KIND', '1');
        // расходы
        '10': aXmlLine.SetAttribute( aPrefix + 'CR_ANAL_KIND', '2');
        // источники
        '31',
        '32': aXmlLine.SetAttribute( aPrefix + 'CR_ANAL_KIND', '3');
        else begin
            // если =Нет - не создаем строку в таком ЭД
            // exchange #3126
            // формируется доходная строка если тип кбк не определяется
            // по set файлу.
            //EXIT;
            // exchange #3129
            // 1.Если строка ЭД формируется на основании поля «DEBET»
            // Если тип классификации не удалось определить,
            // по-умолчанию принимаем "расходы" - "выплаты".
            // 2.Если строка ЭД формируется на основании поля «KREDIT»
            // Если тип классификации не удалось определить,
            // то по-умолчанию принимаем "Доходы" - "Поступления"
            if aIsKredit then begin
              xKBK_Type := '10';
              aXmlLine.SetAttribute( aPrefix + 'CR_ANAL_KIND', '1');
              WriteInfo( FORMAT( 'Не определено значение типа КБК=%s в файле TypeKbk.Set для ЭД %s. Принимается тип =доходы.',
                                 [ xKBK_Type, aDocInfo]));
            end else begin
              xKBK_Type := '20';
              aXmlLine.SetAttribute( aPrefix + 'CR_ANAL_KIND', '2');
              WriteInfo( FORMAT( 'Не определено значение типа КБК=%s в файле TypeKbk.Set для ЭД %s. Принимается тип =расходы.',
                                 [ xKBK_Type, aDocInfo]));
            end;
          end;
      end;//case//
      {---------------------------------------------------------}
      {
      // направление
      if aIsKredit then
        case xKBK_Type of
          // доходы
          '20': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '2');
          // расходы
          '10': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '3');
          // для прочих - не указано
          '31',
          '32': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '0');
        end//case
      else
        case xKBK_Type of
          // доходы
          '20': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '4');
          // расходы
          '10': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '1');
          // источники
          '31',
          '32': aXmlLine.SetAttribute( aPrefix + 'CR_DIRECTION', '0');
        end;//case
        }
      {---------------------------------------------------------}
      // определяем, что загружаем: косгу или квр
      // если расходы - определяем флаг из орг.
      xFillKES := TRUE;
      if (xKBK_Type = '10') then
        if GetAUBU_KVR_EXP_FLAG_for_OrgID( aOrgID)
          then xFillKES := FALSE;
      xKES := '';
      xKVR := '';
      {---------------------------------------------------------}
      // КОСГУ/КВР:
      // Аналитический код брать из значения с 24 по 26 знак
      // полей DEBET или KREDIT - 3 последних символа
      xCode := COPY( aCode_Value, LENGTH( aCode_Value) - 2, 3);
      // КОСГУ
      if xFillKES then begin
        if NOT KbkExists( aBudgetID, xCode, 'Kes') then begin
          // если КОСГУ не найден - проверяется параметр из конфига
          // "заменять КБК на 0".
          if (not param_changeKBK) then begin
            // если =Нет - не создаем строку в таком ЭД
            WriteInfo( FORMAT( 'Значение KОСГУ=%s для ЭД %s не найдено в справочнике '
                               +'классификаторов бюджета.',
                               [ xCode, aDocInfo]));
            EXIT;
          end;
          // если =Да - заменяем КОСГУ на 0
          WriteInfo( FORMAT( 'Значение KОСГУ=%s для ЭД %s не найдено в справочнике '
                             +'классификаторов бюджета и заменено на 0.',
                             [ xCode, aDocInfo]));
          // exchange #3062 - унификация кода
          xCode := KesCodeFormat( '0', aBudgetID);//'000';
        end;
        // сохраняем в узле значение КОСГУ
        xKES := xCode;
        aXmlLine.SetAttribute( aPrefix + 'KESR_CODE', xKES);
      end else begin
        // КВР
        if NOT KbkExists( aBudgetID, xCode, 'KVR') then begin
          // если код не найден - проверяется параметр из конфига
          // "заменять КБК на 0".
          if (not param_changeKBK) then begin
            // если =Нет - не создаем строку в таком ЭД
            WriteInfo( FORMAT( 'Значение KВР=%s для ЭД %s не найдено в справочнике '
                               +'классификаторов бюджета.',
                               [ xCode, aDocInfo]));
            EXIT;
          end;
          // если =Да - заменяем КОСГУ на 0
          WriteInfo( FORMAT( 'Значение KВР=%s для ЭД %s не найдено в справочнике '
                             +'классификаторов бюджета и заменено на 0.',
                             [ xCode, aDocInfo]));
          // exchange #3062 - унификация кода
          xCode := KvrCodeFormat( '0', aBudgetID);//'000';
        end;
        // сохраняем в узле значение КВР
        xKVR := xCode;
        aXmlLine.SetAttribute( aPrefix + 'KVR_CODE', xKVR);
      end;

      {---------------------------------------------------------}
      // КВФО - 18-й знак из поля Debet
      xKIF := COPY( aCode_Value, 18, 1);
      if (LENGTH( KifExists( xKIF, '')) <= 0) then begin
        // если не найден - проверяется параметр из конфига
        // "заменять КБК на 0".
        if (not param_changeKBK) then begin
          // если =Нет - не создаем строку в таком ЭД
          WriteInfo( FORMAT( 'Значение КВФО=%s для ЭД %s не найдено в справочнике '
                             +'классификаторов бюджета.',
                             [ xKIF, aDocInfo]));
          EXIT;
        end;
        // если =Да - заменяем КОСГУ на 0
        WriteInfo( FORMAT( 'Значение КВФО=%s для ЭД %s не найдено в справочнике '
                           +'классификаторов бюджета и заменено на 0.',
                          [ xKIF, aDocInfo]));
        xKIF := '0';
      end;
      // сохраняем в узле значение КВФО
      aXmlLine.SetAttribute( aPrefix + 'FSR_ID', xKIF);
      {---------------------------------------------------------}

      // exchange #3081 - направление операции для KREDIT
      // этот код должен выполняться после заполнения полей косгу и типа класиф.
      // exchange #3129 - теперь еще и для DEBET
      if aIsKredit
        then UpdateLineED_AuBu_by3081_Direction( aXmlLine, 1, aPrefix)
        else UpdateLineED_AuBu_by3081_Direction( aXmlLine, 4, aPrefix);
      {---------------------------------------------------------}
      // ищем записи в аналитических строках
      // отраслевой код
      aXmlLine.SetAttribute(
                aPrefix + 'INDUSTRYCODE_ID_',
                SearchUnicalIndustryCode( aBudgetID,
                                          xKIF,
                                          xKES,
                                          aLS_ID,
                                          xKVR,
                                          xFillKES,
                                          NOT( xFillKES)));
      {---------------------------------------------------------}
      // код субсидии
      aXmlLine.SetAttribute(
                aPrefix + 'GRANTINVESTMENT_ID_',
                SearchUnicalGrantinvestmentCode( aBudgetID,
                                                 xKIF,
                                                 xKES,
                                                 aLS_ID,
                                                 xKVR,
                                                 xFillKES,
                                                 NOT( xFillKES)));
      {---------------------------------------------------------}
      Result := TRUE;
      except
        ExceptionLog( 'Сбой DoCheck2600_ParamsDetail');
    end;

end;
{------------------------------------------------------------------------------}
{~Exch2436_Parse_SPRR
  проверка разделов SPRR для эд ау/бу
  exchange #3081
  добавлен ид.орг плательщика}
function Exch2436_Parse_SPRR( var aNode: Variant;
                               aBudgetID: string;
                               aLS, aLS_ID: string;
                               aDocInfo: string;
                               aSPD_NameDoc__: string;
                               aOrgID: string): boolean;
var
  xSPRR_Debet: string;
  xSPRR_Kredit: string;
  xFound: boolean;
  xSublinesCount: string;

begin

    try
      // пока считаем что раздел SPRR не будет добавлен как строка к ЭД
      Result := FALSE;





      // exchange #2600
      // алгоритм описания строк разный и зависит от поля SPD.NAME_DOC.
      // выше это поле разбирали, поэтому тут проверяем уже
      // классифицированное значение из промежуточного поля
      case aSPD_NameDoc__ of
        //'объявление на взнос наличными',
        //'платежное поручение':
        //'расшифровка неиспользованных средств по банковским картам':
        '1','3': begin

              { в поле SPRR.DEBET c 19 по 23 знак включительно равны
                20313 или 20314.}
              xFound := FALSE;
              xSPRR_Debet := GetNodeAttributeEx( aNode, 'DEBET');

              if (LENGTH( xSPRR_Debet) >= 23) then
                if (COPY( xSPRR_Debet, 19, 5) in ['20313','20314'])
                  then xFound := TRUE;

              if NOT xFound then begin
                WriteInfo( FORMAT( 'Строка, в которой в поле DEBET не содержится 20313 или 20314, не будет входить в ЭД %s.',
                                    [ aDocInfo]));

                EXIT;
              end;

              // проверка КБК в строке из поля KREDIT
              // если строка короче 18-ти символов - строку не добавляем в ЭД
              xSPRR_Kredit := GetNodeAttributeEx( aNode, 'KREDIT');

              if (LENGTH( xSPRR_Kredit) < 18) then begin
                WriteInfo( FORMAT( 'Значение поля KREDIT меньше 18 символов для ЭД %s.',
                                   [ aDocInfo]));

                EXIT;
              end;

              if NOT DoCheck2600_ParamsDetail( aBudgetID,
                                               xSPRR_Kredit,
                                                aLS,
                                                aLS_ID,
                                                aOrgID,
                                                aDocInfo,
                                                aNode,
                                                'Z_',
                                                TRUE)
                then EXIT;
              // режим формирования строки
              aNode.SetAttribute( 'LINE_MODE__', '1');
            end;

        // exchange #2600
        //'справка ф. 0504833',
        //'справка ф.0504833',
        //'справка ф. 0504833 по внебанковским операциям',
        //'справка ф.0504833 по внебанковским операциям':
        '2': begin

              xSublinesCount := '';

              xSPRR_Debet := GetNodeAttributeEx( aNode, 'DEBET');

              if (LENGTH( xSPRR_Debet) >= 21) then
                if (COPY( xSPRR_Debet, 19, 3) = '307') then
                  if NOT DoCheck2600_ParamsDetail( aBudgetID,
                                               xSPRR_Debet,
                                                aLS,
                                                aLS_ID,
                                                aOrgID,
                                                aDocInfo,
                                                aNode,
                                                'D_',
                                                FALSE)
                    then EXIT
                    else xSublinesCount := xSublinesCount + 'D';

              xSPRR_Kredit := GetNodeAttributeEx( aNode, 'KREDIT');

              if (LENGTH( xSPRR_Kredit) >= 21) then
                if (COPY( xSPRR_Kredit, 19, 3) = '307') then
                  if NOT DoCheck2600_ParamsDetail( aBudgetID,
                                               xSPRR_Kredit,
                                                aLS,
                                                aLS_ID,
                                                aOrgID,
                                                aDocInfo,
                                                aNode,
                                                'K_',
                                                TRUE)
                    then EXIT
                    else xSublinesCount := xSublinesCount + 'K';

              if (xSublinesCount = '') then begin
                WriteInfo( FORMAT( 'В строке ЭД %s поле KREDIT и DEBET не содержат 307 в позиции 19...21.',
                                   [ aDocInfo]));

                EXIT;
              end;

              // промежуточный параметр описания строки ЭД
              aNode.SetAttribute( 'LINE_MODE__', xSublinesCount);
            end;
      end;//case//

      // помечаем строку, которая будет входить в ЭД
      aNode.SetAttribute( 'SPRR_PARSE__', 'OK');

      // отмечаем что строка входит в ЭД SPD
      Result := TRUE;
      except
        ExceptionLog( 'Сбой Exch2436_Parse_SPRR');
    end;

end;
{------------------------------------------------------------------------------}
{~Exch2436_Builder
  exchange #2436
  сборка ЭД по проверенным разделам XML.
  остается только сформировать ЭД и строки с ними только по успешно
  проверенным разделам. повторно разделы не проверяются.
  параметры:
    aNode - узел раздела SPD;
    aXml - список разделов;
    aBudgetID - бюджет;
    aLS - номер л/с (TO.LS);
    aLS_ID - ид.л/с в БД;
    aXmlOrg - описание организации для л/с (узел описания);
    aXmlGRBS - описание организации учредителя для л/с (узел описания);
    aDocArray - список маркеров проверенных разделов aXml.
  созданные ЭД сразу передаются в АЦК. }
procedure Exch2436_Builder199_By_SP( var aNode: Variant;
                                       aBudgetID: string;
                                       aLS, aLS_ID: string;
                                       var aXmlOrg: variant;
                                       var aXmlGRBS: variant;
                                       var aDoc199: Variant;
                                       var aDocLines: Variant;
                                       var aDocInfo: string;
                                       var aNAME_DOC__: string;
                                       var aDocDescription: string;
                                       var aFirstLine: boolean);
begin

    try
      // формируем новый ЭД
      Exch2436_Builder199Info_By_SP( aNode, aDocInfo);
      WriteLog( 'Создание ЭД ' + aDocInfo, True);

      aDoc199 := CreateOleObject('Microsoft.XmlDom');
      aDoc199 := aDoc199.appendChild( aDoc199.createElement('DOCUMENT'));
      aDoc199.setAttribute('F_BUDGET_ID', aBudgetID);
      aDoc199.setAttribute('F_ORIGINAL_TYPE', 'SP');
      aDoc199.setAttribute('action', 'insert');
      aDoc199.setAttribute('class', 199);

      // exchange #2484
      // При создании 199 класса при загрузке  файла SP реализовать
      // заполнение поля Foreign_Key в таблице MoneyTransferOrder
      // из поля SPD.GUID_FK.
      // поле необязательное, но на первом этапе проверки данных
      // незаполненное поле не создает ЭД, поэтому здесь VarToStr
      // не обязательная операция.
      aDoc199.setAttribute( 'FOREIGN_KEY', aNode.getAttribute('GUID_FK'));

      // Номер документа 	SPD.NUM_DOC
      aDoc199.setAttribute( 'DOC_NUMBER', aNode.getAttribute('NUM_DOC'));
      // Дата справки	SPD.DATE_SP
      // в документе должна быть в формате YYYY.dd.mm
      aDoc199.setAttribute(
              'DOC_DATE',
              DDdMMdYYYY_To_YYYYmMMmDD(
                            aNode.getAttribute('DATE_SP')));
      // тип операции: По-умолчанию заполняется значением, выбранным
      // для Справки по операциям БУ/АУ в справочнике «Типы операций
      // по-умолчанию», а в случае отсутствия настройки, значением
      // «Не указано»
      aDoc199.setAttribute( 'OPERTYPE_ID', OperTypeDefaultForClass( 199));
      // Заполнение блока "Учреждение"
      aDoc199.setAttribute( 'PAY_ID'      , aXmlOrg.getAttribute('ID'));
      aDoc199.setAttribute( 'PAY_TAXCODE' , aXmlOrg.getAttribute('TAXCODE'));
      aDoc199.setAttribute( 'PAY_KPP'     , aXmlOrg.getAttribute('KPP'));
      aDoc199.setAttribute( 'PAY_NAME'    , aXmlOrg.getAttribute('DESCRIPTION'));
      // счет
      aDoc199.setAttribute( 'PAY_ACC_ID'  , aLS_ID);
      aDoc199.setAttribute( 'PAY_ACCOUNT' , aLS);
      // учредитель
      aDoc199.setAttribute( 'GRBS_ID'     , aXmlGRBS.getAttribute('ID'));
      aDoc199.setAttribute( 'GRBS_NAME'   , aXmlGRBS.getAttribute('DESCRIPTION'));

      // Основание	Заполнять так:
      // Создано на основании Справки ф. 0504833 № SPD.NOM_SP
      // от SPD.DATE_SP (SPD.NAME_OPER)
      // проблема в том, что поле NAME_OPER нужно брать из первой
      // строки, а какая она первая - это сейчас неизвестно. можно
      // перебрать последующие строки здесь, но можно пойти другим
      // путем: здесь сохраним строку, в которой будет заполнена
      // дата и номер, а вместо NAME_OPER вставим "%". при формировании
      // строк, для первой строки и заполним это поле для ЭД.
      aDocDescription :=
            FORMAT( 'Создано на основании Справки ф. 0504833 № %s от %s',
                    [ VarToStr( aNode.GetAttribute( 'NOM_SP')),
                      VarToStr( aNode.GetAttribute( 'DATE_SP'))]);

      // exchange #2600
      // доработка АЦК-Ф: новое поле признак "от ФК" - значение =SP
      aDoc199.SetAttribute( 'FK_FLAG', '1');

      // exchange #2600
      // новое поле в блоке "Первичный документ" - дата
      // дата должна быть в формате YYYY.dd.mm
      aDoc199.setAttribute(
              'PAYDOC_DOC_DATE',
              DDdMMdYYYY_To_YYYYmMMmDD(
                            aNode.getAttribute('DATE_DOC')));
      // exchange #2600
      // новое поле в блоке "Первичный документ" - номер
      aDoc199.SetAttribute(
              'PAYDOC_DOC_NUMBER',
              aNode.GetAttribute( 'NUM_DOC'));
      // exchange #2600
      //  в блоке "Первичный документ" - наименование
      aDoc199.SetAttribute(
              'PAYDOC_NAME',
              aNode.GetAttribute( 'NAME_DOC'));

      // exchange #2600
      // перехватываем промежуточное значение NAME_DOC
      aNAME_DOC__ := aNode.GetAttribute('NAME_DOC__');

      // узел списка строк
      aDocLines := aDoc199.AppendChild(
                        aDoc199.ownerDocument.CreateElement( 'LINES'));

      // ожидается первая строка в ЭД
      aFirstLine := TRUE;
      except
        ExceptionLog( 'Сбой Exch2436_Builder199_By_SP');
    end;

end;
{------------------------------------------------------------------------------}
{~Exch2436_Builder199_Line_By_SP
  создание строки в эд 199м по SPRR }
procedure Exch2436_Builder199_Line_By_SP( aBudgetID: string;
                                          var aNode: Variant;
                                          var aDoc199: Variant;
                                          var aDocLines: Variant;
                                          var aDocInfo: string;
                                          aNAME_DOC__: string;
                                          aDocDescription: string;
                                          var aFirstLine: boolean);
  {---------------------------------------------------------------------------}
  {~DoFillLine_
    заполнение новой строки ЭД 199го класса.
    здесь особенность заполнения суммы: для дебета сумма отрицательная.
    если aSum_Neg=true - сумма отрицательная.}
  procedure DoFillLine_( aPrefix: string;
                         aSum_Neg: boolean);
  var
    xDocLine: variant;
  begin

      try
        // добавляем строку к ЭД
        xDocLine := aDocLines.AppendChild(
                      aDoc199.ownerDocument.CreateElement( 'LINE'));

        // описание строки
        // Сумма строки	SPRR.SUM
        // exchange #2600
        // перед значением поля суммы доолнительно указывается знак (см. пп.1.2.1)
        if aSum_Neg
          then xDocLine.SetAttribute(
                        'AMOUNT',
                        FORMAT( '%.2f',
                                [ -StrToCurrDef(
                                        GetNodeAttributeEx( aNode, 'SUM'), 0)]))
          else xDocLine.SetAttribute(
                        'AMOUNT',
                        FORMAT( '%.2f',
                                [ StrToCurrDef(
                                        GetNodeAttributeEx( aNode, 'SUM'), 0)]));


        // тип кбк
        xDocLine.SetAttribute( 'CR_ANAL_KIND',
                               GetNodeAttributeEx( aNode, aPrefix + 'CR_ANAL_KIND'));
        // направление
        xDocLine.SetAttribute( 'CR_DIRECTION',
                               GetNodeAttributeEx( aNode, aPrefix + 'CR_DIRECTION'));
        // КОСГУ
        xDocLine.SetAttribute( 'KESR_CODE',
                               GetNodeAttributeEx( aNode, aPrefix + 'KESR_CODE'));
        // КВР
        xDocLine.SetAttribute( 'KVR_CODE',
                               GetNodeAttributeEx( aNode, aPrefix + 'KVR_CODE'));
        // КВФО
        xDocLine.SetAttribute( 'FSR_ID',
                               GetNodeAttributeEx( aNode, aPrefix + 'FSR_ID'));
        // отраслевой код
        xDocLine.SetAttribute( 'INDUSTRYCODE_ID',
                               GetNodeAttributeEx( aNode, aPrefix + 'INDUSTRYCODE_ID'));
        // код субсидии
        xDocLine.SetAttribute( 'GRANTINVESTMENT_ID',
                               GetNodeAttributeEx( aNode, aPrefix + 'GRANTINVESTMENT_ID'));
        except
          ExceptionLog( 'Сбой Exch2436_Builder.DoFillLine_');
      end;

  end;
  {---------------------------------------------------------------------------}
begin

    try
      // проверяем специальный атрибут, который помечает строку SPRR,
      // которая должна будет входить в ЭД.
      // если такой атрибут отсутствует или не равен OK, такую строку
      // SPRR игнорируем.
      if (VarTostr( GetNodeAttributeEx( aNode, 'SPRR_PARSE__')) <> 'OK')
        then EXIT;

      // exchange #2600
      // по специальному промежуточному параметру
      // определяем алгоритм заполнения строки
      case aNode.GetAttribute( 'LINE_MODE__') of
        '1': DoFillLine_( 'Z_', FALSE);
        'K': DoFillLine_( 'K_', FALSE);
        'D': DoFillLine_( 'D_', TRUE);
        'DK','KD': begin
             // текущую строку заполняем для kredit
             DoFillLine_( 'K_', FALSE);
             // добавляем строку к ЭД и заполняем ее для debet
             DoFillLine_( 'D_', TRUE);
           end;
      end;//case//

      // наименование операции - поле необязательное
      {
      xDocLine.SetAttribute(
              'NOTE',
              VarToStr( aNode.GetAttribute( 'NAME_OPER')));
       }

      // в примечание ЭД описываем поле NAME_OPER из первой строки
      if aFirstLine then begin
        aFirstLine := FALSE;
        aDoc199.setAttribute(
              'DESCRIPTION',
              FORMAT( '%s (%s)',
                      [ aDocDescription,
                        GetNodeAttributeEx( aNode, 'NAME_OPER')]));
      end;
      except
        ExceptionLog( 'Сбой Exch2436_Builder199_Line_By_SP');
    end;

end;
{------------------------------------------------------------------------------}
begin
end.
