//АЦК: Уведомление об уточнении вида и принадлежности платежа
//Постановка: Exchange #1763
// #2389 - доработка получения значения ADD_KLASS по ТФФ9
uses
  'Un_Exch2719',    // exchange #2719
  'Un_Exch2344',
  'Un_Export',
  'Un_Org',
  'Un_Default',
  'QueryWork',
  'QueryKbk',
  'Un_SysParams',     // exchange #2412
  'QueryTools',
  'Un_MessageValidForm',
  'Un_VersionSupport',
  'Un_Schems',
  'Un_ToolsXml',
  'Un_Tools',
  'Un_Const',
  'Un_Progress',
  'Un_System',
  'Un_Log',
  'Un_Debug';

const
  TestFileName = 'Exp_Fk_UF_Line.Xml';
  cnCfgTemplateKBKExp = 'Правило формирования значения аналитического кода с типом классификации “Расходы”';
  cnCfgTemplateKBKInc = 'Правило формирования значения аналитического кода с типом классификации “Доходы”';
  cnCfgTemplateKBKSrc = 'Правило формирования значения аналитического кода с типом классификации “Источники”';

  
var
  // Формирование значения КОФК
  param_UFK_TOFK: String;
  paramTemplateKBKInc, paramTemplateKBKExp, paramTemplateKBKSrc: String;


// основная функция, в которую передаются данные AzkExchange
function Main(Xml: Variant): Boolean;
begin
  Result := False;
  xml := InitializeMain( xml, TestFileName);
  if VarIsNull( xml) then exit;
  try
    try
      Initialize(Xml);
      // exchange #2719
      ExportOutDirExch2719( Xml.documentElement.getAttribute('EXCH_DATE'),
                            'UF');
      //заполнение содержимого файла.
      // #2344 - выгрузка Уведомление об уточнении вида и принадлежности платежа
      // по ТФФ9 возможна в версиях 2.28.0.xxx
      // exchange #2399 переход на ТФФ 10.0 с удалением кода ТФФ8
      if NOT CompareVersionAZK_Finance(
              'Выгрузка ЭД "Уведомление об уточнении вида и принадлежности платежа" по ТФФ 9 / ТФФ 10.0',
              '2.28',
              FALSE,
              TRUE)
        then EXIT;
      if not MakeFormat_TFF9(Xml) then EXIT;
      //валидация схем.
      if param_CtlValidOn then
      begin
        WriteLog('Валидация схем...', True);
        if not ValidateFormat then
        begin
          ShellExecute('NotePad', FileValidate, False);
          WriteLog('Не пройден контроль валидности отдельными документами');
          if MessageDlg('Не пройден контроль валидности.' + cr +
            'Продолжить выгрузку?', mtConfirmation, mbYes + mbNo, 0) = mrNo then
          begin
            WriteLog('Выгрузка прервана пользователем');
            if param_StopAllUnloadDocNotValid then
              Exit
            else begin
              Result := True;
              Exit;
            end;
          end;
        end;
      end;
      try
        FileTmp := DirTmp + FileOut;
        WriteLog('Сохранение во временном каталоге: ' + FileTmp, True);
        XmlToTextFile(FileTmp);
      except
        raise('Ошибка сохранения: ' + FileTmp);
      end;
      WriteLog('Перенос документов в архив', True);
      Move_To_Arhiv(Xml);
      if Trim(DirArh) <> '' then
      begin
        WriteLog('Копирование файла в каталог архива, согласно настройке');
        CopyFile(DirTmp + FileOut, DirArh + FileOut, False);
        if not FileExists(DirArh + FileOut) then
          ShowMessage('Не удалось скопировать файл в каталог архива:' +
              DirArh + FileOut);
      end;

        // exchange #2968 - формируем конечный файл с учетом создания zip архива
        CopyExportResultFile( DirTmp + FileOut, DirOut);
    except
      WriteLog(LastException.Message);
      raise(LastException.Message);
    end;
    Result := True;
  finally
    Finalize(Xml);
    ShowJournalEnd;
  end;
end; {end Main}

{~DoFill2616_UF_OKPO_FO
  exchange #2616 - ТФФ 12
  если заполняется поле UF.NAME_UBP_FO (на форме это поле ADMIN_NAME),
  то заполнять UF.OKPO_FO из поля ОКПО карточки организации (ADMIN_ID на форме),
  наименование которой выгружается в UF.NAME_UBP_FO.

  exchange #2703
  переход на ТФФ 12.2.
  ТФФ 11 и 11.2 не используются больше, поэтому проверка ТФФ 12 исключается.}
procedure DoFill2616_UF_OKPO_FO( aDocNodeXml, aDataXml: Variant);
begin

    try
        if ( LENGTH( VarToStr( aDocNodeXml.GetAttribute('ADMIN_NAME'))) > 0) then
          if ( LENGTH( VarToStr( aDocNodeXml.GetAttribute('ADMIN_ID'))) > 0)
            then begin
              aDataXml.SetAttribute(
                          'OKPO_FO',
                          QueryField( 'select OKPO from org where id=?',
                                      [ aDocNodeXml.getAttribute('ADMIN_ID')],
                                      'OKPO'));

              end;

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

end;

{~Get_FUND_SOURCE_114
  exchange #2787
  заполнение FUND_SOURCE в разделе UF и UFPP_N для 114 класса:
    1 – если в поле КВФО первой целевой строки указано значение 1
        или 7;
    3 - если в поле КВФО первой целевой строки указано значение 4
        или 5 или 6;
    5 - если в поле КВФО первой целевой строки указано значение 3.
  дополнение ФТ-3:
    для строк ( параметр aUFPP_N=TRUE) значение 5 недопустимо.
    Если КВФО первой целевой строки  не равен  «0», то :
      1 – если в поле КВФО первой целевой строки указано значение 1 или 7;
      3 -  если в поле КВФО первой целевой строки указано значение 4 или 5 или 6;
      Если КВФО первой целевой строки   равен  «0» или любому значению
      отличному от 1, 7, 4, 5, 6, то оставлять UFPP_N.FUND_SOURCE пустым.

  АО утвердило, что КВФО=0 это тоже самое, что если в строках ЭД поле КВФО
  не заполнено.

  exchange #2827
  ошибка была в том, что сообщения для неопределенных значений КВФО в строках
  попадали в журнал критических сообщений, но они не является критическими
  сообщениями, поэтому теперь они записываются в обычный журнал.

     в ФТ-3 указано заполнение во всех строках UFPP_N.FUND_SOURCE как указано
  в первой целевой строке, однако при правильном заполнении ЭД, в каждой
  целевой строке, КВФО необходимо указывать одинаковым во всех строках,
  поэтому заполнение UFPP_N.FUND_SOURCE реализовано для каждой строки
  индивидуально.}
function Get_FUND_SOURCE_114( aKVFO: string;
                              aUFPP_N: boolean;
                              aNodeUF: Variant): string;

  procedure DoWriteDocInfo( aMsg: string);
  begin
    WriteInfo( FORMAT( 'Уведомление об уточнении вида и принадлежности платежа № %s от %s - %s',
                        [ aNodeUF.GetAttribute( 'NOM_UF'),
                          aNodeUF.GetAttribute( 'DATE_UF'),
                          aMsg]));
  end;

  procedure DoWriteDocLog( aMsg: string);
  begin
    WriteLog( FORMAT( 'Уведомление об уточнении вида и принадлежности платежа № %s от %s - %s',
                        [ aNodeUF.GetAttribute( 'NOM_UF'),
                          aNodeUF.GetAttribute( 'DATE_UF'),
                          aMsg]));
  end;

begin

    try
      Result := '';
      case aKVFO of
       ''         : if aUFPP_N
                      then DoWriteDocLog( 'невозможно определить значение поля UFPP_N.FUND_SOURCE для незаполненного значения КВФО в целевых строках')
                      else DoWriteDocInfo( 'невозможно определить значение поля UF.FUND_SOURCE');

       '1','7'    : Result := '1';
       '4','5','6': Result := '3';
       '3'        : if aUFPP_N
                      then DoWriteDocLog( 'невозможно определить значение поля UFPP_N.FUND_SOURCE для значения КВФО=3 в целевых строках')
                      else Result := '5';

       else         if aUFPP_N
                      then DoWriteDocLog( FORMAT( 'невозможно определить значение поля UFPP_N.FUND_SOURCE для значения КВФО=%s в целевых строках',
                                                   [ aKVFO]))
                      else DoWriteDocInfo( 'невозможно определить значение поля UF.FUND_SOURCE');
      end;//case//

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

end;


function MakeFormat_TFF9(Xml: Variant): Boolean;
var
  i, j, j2, line_num, k: Integer;
  found: Boolean;
  XmlQuery, Node: Variant;
  xNode: variant;
  s: string;          // exchange #2539
  xKBK: string;  // exchange #2622
  xKVFO: string;  // exchange #2622
  xNode_Data_Line: Variant;
  xNode_Data_Line2: Variant;
  xUFPP_N_LS_UBP: string;
  xFill_UF_FUND_SOURCE: boolean;
  xUF_LS_UBP: string;
  xDocument_Class: string;
  xDataXml_UF: Variant;
  xUFPP_N_LS_UBP_ACCOUNT: string;
  SrcLinesList: TList;
  SrcLine, SrcLineRes, VarList: Variant;
  amt : Currency;
  
  function isLinesEqual(Xml1, Xml2: Variant): Boolean;
  var
    i: Integer;
    attrName: String;
  begin
    Result := True;
    for i := 0 to Xml1.attributes.length - 1 do
    begin
      attrName := Xml1.attributes[i].nodeName;
      if (not (attrName in ['KESR_CODE', 'KDE_KODE', 'KDF_CODE', 'KDR_CODE', 'AMOUNT', 'LINE_NUM', 'POS',
      'KDD_CODE', 'KESD_CODE', 'KESI_CODE', 'KDI_CODE']))
        and (Xml1.getAttribute(attrName) <> Xml2.getAttribute(attrName)) then
      begin
        Result := False;
        break;
      end;
    end
  end;
  
  function getEqualLineFromArray(list: Variant; line:Variant; size: Integer): Variant;
  var
    i: Integer;
    curLine: Variant;
  begin
    Result := nil;
    found := False;
    if size = 0 then
      exit;
    for i:= 0 to size - 1 do
    begin
      CurLine := list[i];
      if isLinesEqual(curLine, line) then
      begin
        Result := list[i];
        Found := True;
      end;
    end;
  end;

  procedure setLineNum(Xml: Variant; oldLineNum, newLineNum: Integer);
  var
    i : Integer;
  begin
    for i := 0 to Xml.childNodes.Length - 1 do
    begin
      //строки - источники
      if (Xml.childNodes.Item[i].getAttribute('IS_SOURCE_LINE') = 0)
        and (Xml.childNodes.Item[i].getAttribute('LINE_NUM') = oldLineNum) then
        Xml.childNodes.Item[i].setAttribute('NEW_LINE_NUM',newLineNum);
    end;
  end;
  
begin

    try
      Result := False;
      Xml := Xml.documentElement;

      // #2344: за основу берется первый вложенный документ (согласовано с АО)
      xNode := Xml.childNodes.Item[0];

      { exchange #2539
        При формировании файла UF для выгрузки в ФК Код организации в наименование
        файла должен браться из поля From.Kod_ubp формируемого файла,
        а не жестко всегда из карточки Финансового органа бюджета.}
    
      // теперь по новому алгоритму #2539
      if (Xml.childNodes.Item[0].getAttribute('ORG_ACCOUNT') <> '')
        then s := Xml.childNodes.Item[0].getAttribute('ORG_CODE')
        else s := Xml.childNodes.Item[0].getAttribute('ADMIN_CODE');
        
      if Length(s) = 8 then
        s := Copy(s, 4, 5)
      else if Length(s) <> 5 then
      begin
        WriteInfo('Код организации-клиента (KOD_UBP) имеет длину, отличную ' +
              'от допустимой (5 либо 8 символов). Значение будет очищено');
        s := '';
      end;
        
      FileOut := GetFileName( s,
                              'UF',
                              XmlToDateTime(Xml.getAttribute('EXCH_DATE')),
                              Xml.getAttribute('EXCH_PACKET'),
                              FileOutIsLocalNet,
                              FileOutOrgCodeIsFk);
    

      WriteLog('Наименование формируемого файла: ' + FileOut, True);
      Data := Data.documentElement;
      WriteLog('Заполнение данных файла: ' + FileOut, True);
      Data := Data.appendChild(FillElementBySchema(Xml, 'FK'));
      Data.setAttribute('FORM_VER', AppVersion);
      Data := Data.parentNode;
      Data := Data.appendChild(FillElementBySchema(Xml.childNodes.Item[0], 'FROM'));
      Data.setAttribute('BUDG_LEVEL',
        GetBudgLevel(Xml.childNodes.Item[0].getAttribute('BUDGET_ID')));

      { #2344: если Организация в блоке "ПБС/АДБ/АИФДБ"  имеет роль Бюджетное
        или Автономное учреждение и Счет в блоке имеет признак "Переданные
        полномочия ПБС", выгружать в поле значение "6" }
      if Exch2344_ExistsRolesAndCredentials( xNode, 'ORG_ID', 'ORG_ACC_ID')
        then Data.setAttribute('BUDG_LEVEL', 6);

      if Xml.childNodes.Item[0].getAttribute('ORG_ACCOUNT') <> '' then
      begin
        Data.setAttribute('KOD_UBP', Xml.childNodes.Item[0].getAttribute('ORG_CODE'));
        Data.setAttribute('NAME_UBP', Xml.childNodes.Item[0].getAttribute('ORG_DESCRIPTION'));
      end;

      Data := Data.parentNode;
      Data := Data.appendChild(FillElementBySchema(Xml.childNodes.Item[0], 'TO'));
      if Xml.childNodes.Item[0].getAttribute('ORG_ACC_ID') <> '' then
      begin
        Data.setAttribute('KOD_TOFK', QueryField( sqlTofkAcc, [Xml.childNodes.Item[0].getAttribute('ORG_ACC_ID')], 'NAME'));
        Data.setAttribute('NAME_TOFK', QueryField( sqlTofkAcc, [Xml.childNodes.Item[0].getAttribute('ORG_ACC_ID')], 'DESCRIPTION'));
      end;
      Data := Data.parentNode;
      ProgressBar.Max := Xml.childNodes.length;
      //цикл по документам
      for i := 0 to Xml.childNodes.Length - 1 do
      begin
        ProgressBar.Position := i;
        Xml := Xml.childNodes.Item[i];

        Data := Data.appendChild(FillElementBySchema(Xml, 'UF'));

        // exchange #2787
        // сохраняем ссылку на раздел UF
        xDataXml_UF := Data;

        Data.setAttribute('NOM_UF', Trim(Xml.getAttribute('DOC_NUMBER')));
        Data.setAttribute('DATE_UF', FormatDateTime('dd.mm.yyyy',
          XmlToDateTime(Xml.getAttribute('DOC_DATE'))));
        if IsBudgetLevel(Xml.getAttribute('BUDGET_ID'), '1') then
          Data.setAttribute('KOD_UBP', Xml.getAttribute('ORG_CODE'));

        // exchange #2344 - задание на доработку
        // exchange #2451 - правка ошибки
        Exch2344_SetAttr_NAME_UBP_PAY_Ex( Data, Xml, 'NAME_UBP');

        // exchange #2616 - заполнение поля UF.OKPO_FO по ТФФ12
        DoFill2616_UF_OKPO_FO( Xml, Data);

        if Xml.getAttribute('MAIN_KADM') <> '' then
          Data.setAttribute('GLAVA_GRS',
            StringReplace(Format('%3s', [Xml.getAttribute('MAIN_KADM')]),' ', '0'));
        Data.setAttribute('NAME_BUD', QueryField(sqlBudgId,
          [Xml.getAttribute('BUDGET_ID')], 'CAPTION'));

        // Заполним KOF_TOFK, NAME_TOFK
        if Xml.getAttribute('ADMIN_ACC_ID') <> '' then
         setTOFKProps(param_UFK_TOFK, Data, Xml.getAttribute('ADMIN_ACC_ID'), 'KOD_TOFK', 'NAME_TOFK')
        else if Xml.getAttribute('ORG_ACC_ID') <> '' then
         setTOFKProps(param_UFK_TOFK, Data, Xml.getAttribute('ORG_ACC_ID'), 'KOD_TOFK', 'NAME_TOFK');

        if not (Copy(Data.getAttribute('LS_UBP'), 0, 2) in ['04', '08']) then
          case Xml.selectNodes('./ROW[@IS_SOURCE_LINE=1]').item[0].getAttribute('ANAL_KIND') of
            '0': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=1]').item[0].getAttribute('FSR_ID'));
            '1': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=1]').item[0].getAttribute('FSD_ID'));
            '2': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=1]').item[0].getAttribute('FSI_ID'));
          end;
        //Exchange#2063
        if ((Copy(Data.getAttribute('LS_UBP'), 0, 2) in ['04', '08']) and
          (Copy(Xml.selectNodes('./ROW[@IS_SOURCE_LINE=0]').item[0].getAttribute('REC_ACCOUNT'), 0, 2) in ['02', '03'])) then
          case Xml.selectNodes('./ROW[@IS_SOURCE_LINE=0]').item[0].getAttribute('ANAL_KIND') of
            '0': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=0]').item[0].getAttribute('FSR_ID'));
            '1': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=0]').item[0].getAttribute('FSD_ID'));
            '2': Data.setAttribute('FUND_SOURCE', Xml.selectNodes('./ROW[@IS_SOURCE_LINE=0]').item[0].getAttribute('FSI_ID'));
          end;
        if Xml.getAttribute('REQUEST_DATE') <> '' then
          Data.setAttribute('DATE_ZF', FormatDateTime('dd.mm.yyyy',
            XmlToDateTime(Xml.getAttribute('REQUEST_DATE'))));
        if Xml.getAttribute('SIGN_DATE') <> '' then
          Data.setAttribute('DATE_POD', FormatDateTime('dd.mm.yyyy',
            XmlToDateTime(Xml.getAttribute('SIGN_DATE'))));

        // exchange #2787
        // только для 114го класса и только после полного формирования
        // раздела UF
        xDocument_Class := VarToStr( Xml.getAttribute('DOCUMENTCLASS_ID'));
        if (xDocument_Class = '114') then begin

          { анализируем первую строку раздела UFPP_N.
            если нет ни одной строки, поле UP.FUND_SOURCE оставлять пустым.
            первоначально очищаем поле UP.FUND_SOURCE.}
          Data.setAttribute( 'FUND_SOURCE', '');
          // ищем первую целевую строку
          for j := 0 to Xml.childNodes.Length - 1 do begin
            xNode_Data_Line := Xml.childNodes.Item[j];
            if (xNode_Data_Line.getAttribute('IS_SOURCE_LINE') = 0) then begin

              { ФТ1: Поле UF.FUND_SOURCE ЭД класса 114 требуется заполнять в
                    следующих случаях:
                1. Если в поле UFPP_N.LS_UBP указано значение счета
                  отличного от типа «Лицевой счет по доходам в ФК» (8).
                2. Если в поле UFPP_N.LS_UBP значение счета не указано
                  и в поле UF.LS_FO указано.
                3. Если в поле UFPP_N.LS_UBP значение счета не указано
                  и в поле UF.LS_UBP указано значение счета отличного
                  от типа «Лицевой счет по доходам в ФК» (8).
                В случаях, неудовлетворяющих вышеуказанным требованиям,
                  поле FUND_SOURCE не заполнять. }
              xFill_UF_FUND_SOURCE := FALSE;
              // 1) получаем значение UFPP_N.LS_UBP
              // причем, проверяем не просто наличие счета, а указание ид.счета.
              // согласовано с АО - счет должен быть указан всегда!
              // тип счета проверяется по карточке счета, а не по первым
              // цифрам счета, посколкьу АО утвердило, что такой способ
              // неоднозначен.
              xUFPP_N_LS_UBP :=
                 TRIM( VarToStr( xNode_Data_Line.getAttribute( 'REC_ACC_ID')));
              // exchange #2840
              // если в первой целевой строке счет указан,
              // а ид.счета нет - тогда прерываем выгрузку.
              // такой ЭД считается сбойным
              xUFPP_N_LS_UBP_ACCOUNT :=
                 TRIM( VarToStr( xNode_Data_Line.getAttribute( 'REC_ACCOUNT')));

              if (( LENGTH( xUFPP_N_LS_UBP) <= 0)
                  AND ( LENGTH( xUFPP_N_LS_UBP_ACCOUNT) > 0)) then begin
                WriteInfo(
                    FORMAT( 'ЭД "%s" № %s от %s на сумму %s - в первой целевой строке не указан ID счета получателя.',
                            [ 'Уведомление об уточнении вида и принадлежности платежа',
                              Trim(Xml.getAttribute('DOC_NUMBER')),
                              Xml.getAttribute('DOC_DATE'),
                              Xml.getAttribute('AMOUNT')]));
                // дальнейшая проверка и подстановка КВФО не актуальна
                BREAK;
              end;
              if (LENGTH( xUFPP_N_LS_UBP) > 0) then begin
                if (QueryField(  ' Select ORGACCTYPE_ID ATYPE from ORGACCOUNT'
                                +' where id=?',
                                 [ xUFPP_N_LS_UBP],
                                 'ATYPE') <> '8')
                  then xFill_UF_FUND_SOURCE := TRUE;
              end else
                // 2) если UFPP_N.LS_UBP не указан, проверяем заполнение
                // UF.LS_FO (ADMIN_ACCOUNT). причем, если счет указан, его
                // тип не проверяем
                if (LENGTH( TRIM( VarToStr( Xml.getAttribute( 'ADMIN_ACCOUNT')))) > 0)
                  then xFill_UF_FUND_SOURCE := TRUE
                  else begin
                    // 3) если UF.LS_FO не заполнено, проверяем UF.LS_UBP
                    // (ORG_ACCOUNT). вместо счета проверяем ид.счета: ORG_ACC_ID
                    xUF_LS_UBP :=
                              TRIM( VarToStr( Xml.getAttribute( 'ORG_ACC_ID')));
                    if (LENGTH( xUF_LS_UBP) > 0) then
                      if (QueryField(  ' Select ORGACCTYPE_ID ATYPE from ORGACCOUNT'
                                      +' where id=?',
                                       [ xUF_LS_UBP],
                                       'ATYPE') <> '8')
                        then xFill_UF_FUND_SOURCE := TRUE;
                  end;


              // если дается добро на заполнение UF.FUND_SOURCE
              if xFill_UF_FUND_SOURCE then begin
                // определяем КВФО из целевой строки
                case xNode_Data_Line.getAttribute('ANAL_KIND') of
                  '0': xKVFO := xNode_Data_Line.getAttribute('FSR_ID');
                  '1': xKVFO := xNode_Data_Line.getAttribute('FSD_ID');
                  '2': xKVFO := xNode_Data_Line.getAttribute('FSI_ID');
                  else xKVFO := '';
                end;//case//
                { изменение ФТ2 АО:
                  ФТ2: Выгружать в поле UF.FUND_SOURCE ЭД класса 114
                  следующее значение:
Если КВФО первой целевой строки  не равен  «0», то :
1 – если в поле КВФО первой целевой строки указано значение 1 или 7;
3 -  если в поле КВФО первой целевой строки указано значение 4 или 5 или 6;
5 -  если в поле КВФО первой целевой строки указано значение 3.
Если КВФО первой целевой строки  равен  «0», то
1 – если в поле КВФО первой строки-источника указано значение 1 или 7;
3 -  если в поле КВФО первой строки-источника  указано значение 4 или 5 или 6;
5 -  если в поле КВФО первой строки-источника  указано значение 3.}
                if ( xKVFO in ['','0']) then begin
                  // предположительно ничем не заполняем, если такой строки
                  // не найдем, то будем сообщать об этом в журнале и прерывать
                  // выгрузку.
                  xKVFO := '';
                  // ищем первую строку источника

                  for j2 := 0 to Xml.childNodes.Length - 1 do begin
                    xNode_Data_Line2 := Xml.childNodes.Item[j2];
                    if (xNode_Data_Line2.GetAttribute('IS_SOURCE_LINE') = 1)
                      then begin

                        // определяем КВФО по первой строке источнику
                        case xNode_Data_Line2.getAttribute('ANAL_KIND') of
                          '0': xKVFO := xNode_Data_Line2.getAttribute('FSR_ID');
                          '1': xKVFO := xNode_Data_Line2.getAttribute('FSD_ID');
                          '2': xKVFO := xNode_Data_Line2.getAttribute('FSI_ID');
                          else xKVFO := '';
                        end;//case//
                        BREAK;
                      end;
                  end;//for//

                end;

                Data.setAttribute( 'FUND_SOURCE',
                                   Get_FUND_SOURCE_114( xKVFO, FALSE, xDataXml_UF));

              end;
              { берем только первую строку. другие строки нас не интерисуют.
                первая строка берется потому, что для нескольких строк,
                счет будет один, но кбк разное, поэтому проверять можно
                счет по первой строке.}
              BREAK;
            end;
          end;//for//

        end;


        VarList := VarArrayCreate([0, Xml.childNodes.Length - 1], varVariant);
        k := 0;
        //сольем строки - источники
        for j := 0 to Xml.childNodes.Length - 1 do
        begin
          SrcLine := Xml.childNodes.Item[j];
          if SrcLine.getAttribute('IS_SOURCE_LINE') = 1 then
          begin
            SrcLineRes := getEqualLineFromArray(VarList, SrcLine, k);
            if(found) then
            begin
              amt := StrToCurr(SrcLine.getAttribute('AMOUNT'));
              amt := amt + StrToCurr(SrcLineRes.getAttribute('AMOUNT'));
              SrcLineRes.setAttribute('AMOUNT', CurrToStr(amt));
              setLineNum(Xml, SrcLine.getAttribute('LINE_NUM'), SrcLineRes.getAttribute('LINE_NUM'));
              SrcLine.setAttribute('MARK_TO_DELETE', '1');
            end
            else
            begin
              setLineNum(Xml, SrcLine.getAttribute('LINE_NUM'), k + 1);
              SrcLine.setAttribute('LINE_NUM', IntToStr(k + 1));
              VarList[k] := SrcLine;
              Inc(k);
            end;
          end;
        end;

        VarList := VarArrayCreate([0, Xml.childNodes.Length - 1], varVariant);
        k := 0;
        //сольем целевые строки
        for j := 0 to Xml.childNodes.Length - 1 do
        begin
          SrcLine := Xml.childNodes.Item[j];
          if SrcLine.getAttribute('IS_SOURCE_LINE') = 0 then
          begin
            SrcLineRes := getEqualLineFromArray(VarList, SrcLine, k);
            if(found) then
            begin
              amt := StrToCurr(SrcLine.getAttribute('AMOUNT'));
              amt := amt + StrToCurr(SrcLineRes.getAttribute('AMOUNT'));
              SrcLineRes.setAttribute('AMOUNT', CurrToStr(amt));
              SrcLine.setAttribute('MARK_TO_DELETE', '1');
            end
            else
            begin
              VarList[k] := SrcLine;
              Inc(k);
            end;
          end;
        end;

        //теперь надо удалить лишние строки
        for j := Xml.childNodes.Length - 1 downto 0 do
        begin
          SrcLine := Xml.childNodes.Item[j];
          if SrcLine.getAttribute('MARK_TO_DELETE') = 1 then
            Xml.removeChild(SrcLine)
          else if (SrcLine.getAttribute('NEW_LINE_NUM') > 0) then
          begin
            SrcLine.setAttribute('LINE_NUM', SrcLine.getAttribute('NEW_LINE_NUM'));
          end;
        end;

        for j := 0 to Xml.childNodes.Length - 1 do
          //строки - источники
          if Xml.childNodes.Item[j].getAttribute('IS_SOURCE_LINE') = 1 then
          begin
            // строка - источник
            Xml := Xml.childNodes.Item[j];
            //сохраняем номер строки для поиска в последующем целевых строк по номеру
            Data := Data.appendChild(FillElementBySchema(Xml, 'UFPP'));

            if Xml.parentNode.getAttribute('ACT_FLAG') = '1' then
            begin
              Data.setAttribute('KOD_DOC', 'AT');
              Data.setAttribute('NOM_PP', Xml.parentNode.getAttribute('ACT_NUMBER'));
              Data.setAttribute('DATE_PP', FormatDateTime('dd.mm.yyyy',
                XmlToDateTime(Xml.parentNode.getAttribute('ACT_DATE'))));
              Data.setAttribute('NAME_PP', 'Акт приемки-передачи');
            end
            else begin
              //to_do убрать все это после полного перехода на ТФФ 80
              //to_do после перехода всех на 2.21, записать в схему данное присвоение
              //---
              Data.setAttribute('NAME_PP', GetName_PP(Xml.getAttribute('PAYDOC_CODE')));
              if VarToStr(Xml.getAttribute('PAYDOC_NAME')) <> '' then
                Data.setAttribute('NAME_PP', Xml.getAttribute('PAYDOC_NAME'));
              //---
              Data.setAttribute('NOM_PP', Xml.getAttribute('PAYDOC_DOC_NUMBER'));
              if Xml.getAttribute('PAYDOC_DOC_DATE') <> '' then
                Data.setAttribute('DATE_PP', FormatDateTime('dd.mm.yyyy',
                  XmlToDateTime(Xml.getAttribute('PAYDOC_DOC_DATE'))));
            end;
            //---
            // exchange #3062 - убран косгу из кбк
            Data.setAttribute( 'KBK',
                               GetRuleKBKLine( Xml,
                                               Xml.getAttribute('BUDGET_ID'),
                                               '',
                                               FALSE));
            Data.setAttribute('TYPE_KBK', GetTypeKBK(Xml, Xml.getAttribute('BUDGET_ID')));
            // exchange #2389 (для ТФФ9)
            // exchange #2412 - код цели
            Data.setAttribute( 'ADD_KLASS', GetPurposeFulgrantCodeExAnalKind( Xml));
            Data.setAttribute('SUM_PP',
              Format('%0.2f', [StrToCurrDef(Xml.getAttribute('AMOUNT'), 0)]));
            //---
            if Xml.getAttribute('REQUEST_DATE') <> '' then
              Data.setAttribute('DATE_ZR', FormatDateTime('dd.mm.yyyy',
                XmlToDateTime(Xml.getAttribute('REQUEST_DATE'))));

            Xml := Xml.parentNode;
            Data := Data.parentNode;
          end;
        for j := 0 to Xml.childNodes.Length - 1 do
        begin
          //целевые строки
          if Xml.childNodes.Item[j].getAttribute('IS_SOURCE_LINE') = 0  then
          begin
            Xml := Xml.childNodes.Item[j];
            Data := Data.appendChild(FillElementBySchema(Xml, 'UFPP_N'));

            // exchange #2622
            // определяем КВФО - делаем это один раз, чтобы потом не повторять
            // это несколько раз
            case Xml.getAttribute('ANAL_KIND') of
              '0': xKVFO := Xml.getAttribute('FSR_ID');
              '1': xKVFO := Xml.getAttribute('FSD_ID');
              '2': xKVFO := Xml.getAttribute('FSI_ID');
              else xKVFO := '';
            end;

            //Exchange#2196 - некрасиво, но иначе не получается отловить
            // пару моментов с пустотой
            // exchange #2622
            // если КБК=все_нули, тогда независимо от КВФО, КБК и тип КБК
            // не выгружается
            // exchange #3062 - убран косгу из кбк
            xKBK := GetRuleKBKLine( Xml, Xml.getAttribute('BUDGET_ID'), '', FALSE);
            if (xKBK <> '00000000000000000000') then begin
              Data.setAttribute( 'KBK', xKBK);
              Data.setAttribute( 'TYPE_KBK', GetTypeKBK(Xml, Xml.getAttribute('BUDGET_ID')));
            end;

            // exchange #2389 (для ТФФ9)
            // exchange #2412 - код цели
            Data.setAttribute( 'ADD_KLASS', GetPurposeFulgrantCodeExAnalKind( Xml));
            Data.setAttribute('SUM', Format('%0.2f',
              [StrToCurrDef(Xml.getAttribute('AMOUNT'), 0)]));
            //Exchange #1971
            if Data.getAttribute('SUM') = 0 then
              Data.setAttribute('SUM', '');
            //---
            Data.setAttribute('PURPOSE', Xml.getAttribute('DESCRIPTION'));

            // exchange #2622
            // если КВФО =0 он не выгружается, не зависимо от типа счета
            // exchange #2787
            // выгружать в строках FUND_SOURCE по КВФО, согласно ТФФ.
            // но только для выгрузки 114 класса.
            // по умолчанию, при автозаполнении, поле FUND_SOURCE заполняется
            // пустым значением.
            // exchange #2833
            // по записи exchange #2622 нужно было проверять счет LS_UBP
            // в шапке ЭД с проверкой на начало счета <>04 и 08.
            // это было связано со специфическими выгрузками.
            // теперь же нужно проверять REC_ACCOUNT в целевой строке.
            // проверяется что счет должен начинаться не на 04.
            // условие не на 08 убрано.

            // КВФО=0 не выгружается ни для каких классов, т.е. в этом случае,
            // поле UFPP_N.FUND_SOURCE выгружается пустой строкой.
            if (xKVFO <> '0') then
              // если выгружается не 114й класс, поле UFPP_N.FUND_SOURCE
              // заполняется как указано в КВФО строки.
              if (xDocument_Class <> '114')
                then Data.setAttribute( 'FUND_SOURCE', xKVFO)
                else
                  // если счет в строке не начинается на 04, то заполняем
                  // UFPP_N.FUND_SOURCE из КВФО по ФТ3.
                  // причем, выгрузка выполняется по каждой строке
                  // индивидуально, а не как заполнено в первой целевой строке.
                  if not ( Copy( VarToStr( Xml.getAttribute( 'REC_ACCOUNT')), 0, 2)
                           in ['04'])
                    then Data.SetAttribute(
                                'FUND_SOURCE',
                                Get_FUND_SOURCE_114( xKVFO, TRUE, xDataXml_UF));

            Xml := Xml.parentNode;
            Data := Data.parentNode;
          end;
        end;
        Data := Data.parentNode;
        Xml := Xml.parentNode;
      end;
      Data := Data.ownerDocument;
      Xml := Xml.ownerDocument;
      if FileExists(FileInfo) then Exit;
      Result := True;
      except
        ExceptionLog( 'Сбой MakeFormat_TFF9');
    end;

end;

procedure Initialize(Xml: Variant);
var
  SL: TStringList;
begin
  SL := TStringList.Create;
  with SL do
  try
    CommaText := InitializeDefault(Xml, ChangeFileExt(TestFileName, ''));
    // exchange #2968
    InitializeExportCfgZip( SL);
    param_UFK_TOFK := Values['Формирование значения КОФК'];
    paramTemplateKBKInc := SL.Values[cnCfgTemplateKbkInc];
    paramTemplateKBKExp := SL.Values[cnCfgTemplateKbkExp];
    paramTemplateKBKSrc := SL.Values[cnCfgTemplateKbkSrc];
  finally
    Free;
  end;
  // инициализируем модуль сообщений
  InitializeMessageValid( 'Exp_Fk_UF_LINE', DirIni);
  // Exchange 2336 загружаем схему в зависимости от версии
  // exchange #2542 - переход на тфф11 + переработка модуля проверки версий схем
  LoadSchema( GetFileNameSchemaTFF( 'uf_txuf*'));
end; {End Initialize}

procedure Finalize(Xml: Variant);
begin
  
  FinalizeDefault(Xml);
  FinalizeMessageValid;
  FinalizeMain;
end; {End Finalize}

begin
  Main(NULL);
end.
