uses
  'Un_Exch2769',    // exchange #2769
  'Un_Exch2583',    // exchange #2583
  // exchange #2547
  // скрипт Un_Exch2547_PayKind соответствует скрипту Un_Exch2547 для всех задач,
  // не касающихся УФЭБС загр/выгр вида платежа.
  // отладка скрипта Un_Exch2547 выполняется в каталоге:
  // "d:\work\AzkScript.Test\Вид платежа - экспорт - импорт"
  // поскольку для УФЭБС по последним требованиям тоже нужно внести изменение
  // при загрузке/выгрузке вида платежа, то скрипт переименован в другое имя,
  // чтобы не затереть скрипт Un_Exch2547 для УФЭБС - выгрузка ED244.
  'Un_Exch2547_PayKind',
  'Un_Exch2547',    // exchange #2547
  'Un_Exch2409',    // exchange #2409
  'UfebsLoadUtils',
  'UfebsTools',

  'UfebsUtils',    // exchange #3080
  'UfebsLog',
  'Un_Log',
  'UfebsMakeFileName',
  'UfebsConst',
  'Un_Version',     // добавлено exchange #2403
  'Un_Progress',
  'Un_Debug',
  'WorkUfebsVersion.inc',
  'WorkAppVersion.inc',
  'UfebsVersionInc.inc';

var
  // exchange #3068
  vCfg_CreateDocExLoadED211: boolean;
  // exchange #3080
  vCfg_LoadED206_3080: boolean;



// Главная функций вызоваемая из AzkExchange.exe при выгрузке
procedure Main(Xml: Variant);
var
  Sr: TFileSearch;
begin
  InitializeDebug;

  // Проверка соответствия текущей версии AzkExchange с версией разработки
  if CompareVersionEx(AppVersion, WorkAppVersion) < 0 then
    raise('Скрипты работают с AzkEchange.Exe начиная с версии: ' + WorkAppVersion +
      ''#13#10'Текущая версия AzkEchange.Exe: ' + AppVersion);

  // Для тестирования создаётся при удержании Shift в момент выгрузке
  FileTest := 'C:\Temp\UfebsLoad.Xml';
  with Xml.documentElement do
  if getAttribute('TESTED') = 'True' then begin
    setAttribute('TESTED', 'False');
    Xml.save(FileTest);
    ShowMessage('Тестовый пример приготовлен: ' + FileTest);
    Exit;
  end;

  Sr := TFileSearch.Create;
  try
    try

      // Инициализация параметров загрузки
      Initialize(Xml);



      // Ищем файлы по маске из настроек в конфигурации
      if Sr.FindFirst(DirIn, faAnyFile) = 0 then
      begin

        // exchange #2759
        // проверяем, все ли бюджеты разрешены для пользователя
        vAllBudgetForUser := (QueryField(
                                  ' select count( * ) N from USERROLES A '
                                 +' join USERROLE B on B.ID = A.USERROLE_ID '
                                 +' join roleright rr on rr.userrole_id=b.id '
                                 +' where A.SYSUSER_ID = ? and '
                                 +' rr.sysright_name='#39'Budgets.All'#39,
                                  UserID,
                                  'N') <> '0');

        repeat
          if (Sr.Name <> '.') and (Sr.Name <> '..') and (Sr.Attr <> faDirectory) then
          begin
            // Устанавливаем признак нового файла загрузки
            // используется в WriteInfo для вывода имени загружаемого файла
            FirstInfo := True;
            FileIn := ExtractFilePath(DirIn) + Sr.Name;
            LoadUfebs;
          end;
        until Sr.FindNext <> 0;
        Sr.FindClose;
      end;
    except
      // Для всех исключений - пишем в лог ошибку и возбуждаем исключение снова
      WriteLog(LastException.Message);
      raise(LastException.Message);
    end;
  finally
    Sr.Free;
    Finalize;

    ShowProgress(0);
    StatusBarSimpleText('');
    // В случае наличия информационного лога, выводим в NotePad (для операциониста)
    if FileExists(FileInfo) then
      ShellExecute('NotePad', FileInfo, False);
  end;
end; {End Main}

// Перенос в архив по завершению, из (FileIn)
procedure MoveToArh;
begin
  // exchange #2409
  // если при обработке запроса ED243 возникнут ошибки, то файл запроса
  // будет скопирован в каталог ошибок. так сделано чтобы не менять что либо в коде.
  // если входного файла уже не будет, архивирование выполнять не нужно.
  if NOT FileExists( FileIn) then EXIT;

  FileArh := DirArh + FormatDateTime('yyyy-mm-dd', FEDDate) + '\In\' +
    ExtractFileName(FileIn);
  ForceDirectories(ExtractFilePath(FileArh));
  if DirectoryExists(ExtractFilePath(FileArh)) then
  begin
    WriteLog('Перенос в архивный каталог: ' + FileArh, True);
    CopyFile(FileIn, FileArh, False);


    DeleteFile(FileIn);
  end
  else
    WriteInfo('Ошибка создания архивного каталога: ' + ExtractFilePath(FileArh))
end; {End MoveToArh}

procedure MoveToError(Msg: String);
begin
  if FEDDate <> 0 then
    FileErr := DirErr + FormatDateTime('yyyy-mm-dd', FEDDate) +
      '\' + ExtractFilename(FileIn)
  else
  begin
    FileErr := DirErr + FormatDateTime('yyyy-mm-dd', Date) +
      '\' + ExtractFilename(FileIn);
    WriteInfo('Ошибка произошла до определения даты ЭД' +
      ', каталог ошибок за текущую системную дату');
  end;
  ForceDirectories(ExtractFilePath(FileErr));
  if not DirectoryExists(ExtractFilePath(FileErr)) then
    raise('Ошибка при определении каталога ошибок: ' + ExtractFilePath(FileErr));
  WriteInfo(Msg);
  WriteInfo('Перенос в каталог ошибок: ' + FileErr);
  CopyFile(FileIn, FileErr);



  DeleteFile(FileIn);
end; {End MoveToError}

// Главная процедура загрузки УФЭБС, в теории :) можно надеятся что их подсунули
procedure LoadUfebs;
var
  i: Integer;
begin
  WriteLog('Обработка файла: ' + FileIn, True);
  with CreateOleObject('Microsoft.XmlDom') do
    if not load(FileIn) then
    begin
      MoveToError('Ошибка XML парсера' + #13#10 +
        'Причина: ' + parseError.reason + #13#10 + 'XML: ' + parseError.srcText);
      Exit;
    end;
  try
    Ufebs := Ufebs.LoadFromFile(FileIn);
  except
    if not Ufebs.ValidateFile(FileIn) then
    with Ufebs.ValidateError do
    begin
      MoveToError('Ошибка валидации XML' + #13#10 +
        'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
      Exit;
    end;
    with TStringList.Create do
    try
      LoadFromFile(FileIn);
      MoveToError('Файл: ' + FileIn + #13#10 + LastException.Message +
        ''#13#10'Проверьте конфигурацию загрузки' +
        ''#13#10'Текущие установки параметров:' +
        ''#13#10' - <Обрабатывать служебный конверт> = ' + BooleanToStr(FEnvelope) +
        ''#13#10' - <Распаковывать Object> = ' + BooleanToStr(Ufebs.EnvelopeCompessed) +
        ''#13#10' - <Расшифровывать Object> = ' + BooleanToStr(Ufebs.EnvelopeCrypted) +
        ''#13#10' - <Обрабатывать конверт ЭЦП(КА)> = ' + BooleanToStr(FSigEnvelope) +
        ''#13#10'Начало содержимого: ' + Copy(Text, 1, 500));
      Exit;
    finally
      Free;
    end;
  end;
  if (Ufebs.EDType = edtEnvelope) and not FEnvelope then
    raise('В конфигурации загрузки параметр:' +
      ''#13#10'<Обрабатывать служебный конверт> = Нет' +
      ''#13#10'На входе именно <Служебный конверт>');
  if (Ufebs.EDType = edtSigEnvelope) and not FSigEnvelope then
    raise('В конфигурации загрузки параметр:' +
      ''#13#10'<Обрабатывать конверт ЭЦП(КА)> = Нет' +
      ''#13#10'На входе именно <Конверт ЭЦП(КА)>');
  case Ufebs.EDType of
    edtEnvelope: WriteLog('На входе <Служебный конверт>', True);
    edtSigEnvelope: WriteLog('На входе <Конверт ЭЦП(КА)>', True);
    edtPacketEPD, edtED101: WriteLog('На входе <ЭД/Пакет ЭД>', True);
    edtPacketESID, edtED201, edtED206, edtED222:
      WriteLog('На входе ЭСИД <ЭД/Пакет ЭД>', True);

    // exchange #2696
    edtPacketEID: WriteLog('На входе <Пакет информационных ЭС>', TRUE);
  end;
  if Ufebs.EDType = edtEnvelope then
  begin
    FEDDate := Ufebs.MessageInfo.CreateTime;
    WriteLog('<Служебный конверт> - обработка', True);
    WriteLog('<Служебный конверт> - контроль валидности', True);
    if not Ufebs.Validate then
      with Ufebs.ValidateError do
      begin
        MoveToError('<Cлужебный конверт> - не прошёл контроль валидности' + #13#10 +
          'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
        Exit;
      end;
    if Ufebs.AcknowledgementInfo.AcknowledgementType <> '' then
    begin
      Msg := 'Квитанция транспортной подсистемы: ';
      case Ufebs.AcknowledgementInfo.AcknowledgementType of
        1: Msg := Msg + '1 - Отправка';
        2: Msg := Msg + '2 - Поступление в платёжную сеть УБР';
        3: Msg := Msg + '3 - Прочтение приложением-получателем';
      end;
      if Ufebs.AcknowledgementInfo.ResultCode <> '0000' then
      begin
        Msg := Msg + ' (Код ошибки - ' + Ufebs.AcknowledgementInfo.ResultCode + ') ' +
          'Текст ошибки: ' + Ufebs.AcknowledgementInfo.ResultText;
        WriteInfo(Msg);
      end
      else
        WriteLog(Msg, True);
      MoveToArh;
      Exit;
    end;
    WriteLog('<Служебный конверт> - выделение <Конверт ЭЦП(КА)>', True);
    Ufebs := Ufebs.SigEnvelope;
  end;
  if Ufebs.EDType = edtSigEnvelope then
  begin
    FSavePacketEPD := True;
    FEDDate := Ufebs.EDObject.EDDate;
    WriteLog('<Конверт ЭЦП(КА)> - обработка', True);
    WriteLog('<Конверт ЭЦП(КА)> - контроль валидности', True);
    if not Ufebs.Validate then
      with Ufebs.ValidateError do
      begin
        MoveToError('<Конверт ЭЦП(КА)> - не прошёл контроль валидности' + #13#10 +
          'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
        Exit;
      end;
    if FVerifySigEnvelope then
    begin
      WriteLog('<Конверт ЭЦП(КА)> - контроль ЭЦП(КА)', True);
      if not Ufebs.Verify then
      begin
        MoveToError('<Конверт ЭЦП(КА)> - не прошёл контроль ЭЦП(КА)');
        Exit;
      end;
    end;
    WriteLog('<Конверт ЭЦП(КА)> - выделение <ЭД/Пакет ЭД>', True);
    Ufebs := Ufebs.EDObject;
  end;
  if Ufebs.EDType in [ 1 .. 26, 54 .. 59, 64, 70, 72,
                        edtED108,
                        edtED111,
                        // exchange #2598
                        edtED107,
                        edtED275,
                        edtED276,
                        // exchange #2696
                        edtPacketEID,
                        // exchange #2646
                        edtED245] then
  begin
    WriteLog('<ЭД/Пакет ЭД> - обработка', True);

    // exchange #2403 - удален ED110 начиная с пакета 2.5.7
    if ((Ufebs.EDType = edtED110)
       AND (Version_CompareEx( '2.5.6', Ufebs.FormatVer) < 0)) then begin
      MoveToError('<ЭД/Пакет ЭД> ED110 - не обрабатывается, начиная с версии 2.5.7.');
      Exit;
    end;

    FEDDate := Ufebs.EDDate;
    if Ufebs.EDType in [edtPacketEPD, edtPacketESID, edtPacketEID] then
      SetProgressBarMax(Ufebs.Count);
    WriteLog('<ЭД/Пакет ЭД> - контроль валидности', True);
    if not Ufebs.Validate then
    begin
      if Ufebs.EDType in [edtPacketEPD, edtPacketESID, edtPacketEID] then
      for i := 0 to Ufebs.Count - 1 do
      if not Ufebs.ED[i].Validate then
      begin
        with Ufebs.ValidateError do
        begin
          MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль валидности' + #13#10 +
            'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
          Exit;
        end;
        ShowProgress(i + 1);
      end;
      Ufebs.Validate;
      with Ufebs.ValidateError do
      begin
        MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль валидности' + #13#10 +
          'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
        Exit;
      end;
      ShowProgress(0);
    end;
  end;
  if Ufebs.SignType <> stNone then
  if Ufebs.Signed then
  begin
    WriteLog('<ЭД/Пакет ЭД> - контроль ЭЦП(ЗК) на весь пакет', True);
    try
      if not Ufebs.Verify then
      begin
        MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль ЭЦП(ЗК)' + #13#10 +
          'Причина: ' + LastException.Message);
        Exit;
      end;
      except
        MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль ЭЦП(ЗК)' + #13#10 +
          'Причина: ' + LastException.Message);
        Exit;
    end;
  end
  else if (Ufebs.EDType in [edtPacketEPD, edtPacketESID, edtPacketEID])
          and Ufebs.ED[0].Signed then
  begin
    WriteLog('<ЭД/Пакет ЭД> - контроль ЭЦП(ЗК) на каждый ЭД в пакете', True);
    for i := 0 to Ufebs.Count - 1 do
    begin
      if not Ufebs.ED[i].Verify then
      try
        if not Ufebs.ED[i].Verify then
        begin
          MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль ЭЦП(ЗК)' + #13#10 +
            'Причина: ' + LastException.Message + #13#10 +
            'Документ:' + Ufebs.ED[i].XMLText);
          Exit;
        end;
        except
          MoveToError('<ЭД/Пакет ЭД> - не прошёл контроль ЭЦП(ЗК)' + #13#10 +
            'Причина: ' + LastException.Message + #13#10 +
            'Документ:' + Ufebs.ED[i].XMLText);
          Exit;
      end;
      ShowProgress(i + 1);
    end;
    ShowProgress(0);
  end
  else
    raise('В конфигурации загрузки параметр:' + ''#13#10'<Проверять ЭЦП(ЗК)> = Да' +
      ''#13#10'<ЭД/Пакет ЭД> - не подписан');
  if FSavePacketEPD then
  begin
    FileArh := DirArh + FormatDateTime('yyyy-mm-dd', FEDDate) + '\In\Xml\' +
      ExtractFileName(FileIn);
    ForceDirectories(ExtractFilePath(FileArh));
    if DirectoryExists(ExtractFilePath(FileArh)) then
    begin
      Ufebs.FormatXML;
      Ufebs.SaveToFile(FileArh + '.xml');
      WriteLog('Файл ЭД/Пакет ЭД сохранён: ' + FileArh + '.xml');
    end;
  end;
  case Ufebs.EDType of
    edtPacketEPD:
      begin
        WriteLog(edtName[Ufebs.EDType] + Format(' № %d', [Ufebs.EDNo]) +
        ' Дата: ' + FormatDateTime('dd.mm.yyyy', Ufebs.EDDate) +
        ' Количество: ' + Format('%d', [Ufebs.EDQuantity]) +
        ' Сумма: ' + Format('%.2f', [Ufebs.Sum]), True);
        for i := 0 to Ufebs.Count - 1 do
        begin
          SetProgressBarMax(Ufebs.Count);
          case Ufebs.ED[i].EDType of
            edtED101,
            edtED102,
            edtED103,
            edtED104,
            edtED105,
            edtED110: LoadED101_102_103_104_105_110_222(Ufebs.ED[i]);
            edtED108: LoadED108Main(Ufebs.ED[i]);   // exchange #2583
            else WriteInfo(edtName[Ufebs.ED[i].EDType] + ' - пока не обрабатываются.');
          end;
          ShowProgress(i + 1);
        end;
      end;
    edtPacketESID:
      begin
        WriteLog(edtName[Ufebs.EDType] + ' - Обработка', True);
        for i := 0 to Ufebs.Count - 1 do
        begin
          SetProgressBarMax(Ufebs.Count);
          case Ufebs.ED[i].EDType of
            edtED201,
            edtED206: LoadED201_206(Ufebs.ED[i]);
            edtED205: LoadED205(Ufebs.ED[i]);
            edtED207: LoadED207(Ufebs.ED[i]);
            edtED211: LoadED211(Ufebs.ED[i]);
            edtED215: LoadED215(Ufebs.ED[i]);
            edtED217: LoadED217(Ufebs.ED[i]);
            edtED219: LoadED219(Ufebs.ED[i]);
            edtED221: LoadED221(Ufebs.ED[i]);
            edtED222: LoadED101_102_103_104_105_110_222(Ufebs.ED[i]);
            edtED330: WriteInfo('ED330: Информация о корректировке' +
            ' временного регламента функционирования' + #10 +
            ', текст сообщения' + Ufebs.ED[i].CorrectionDescription);
            else WriteInfo(edtName[Ufebs.ED[i].EDType] + ' - пока не обрабатываются.');
          end;
          ShowProgress(i + 1);
        end;
      end;

    // exchange #2696
    edtPacketEID: begin
          WriteLog(edtName[Ufebs.EDType] + ' - Обработка', True);
          for i := 0 to Ufebs.Count - 1 do begin
            SetProgressBarMax(Ufebs.Count);
            case Ufebs.ED[i].EDType of
              edtED208: LoadED208( Ufebs.ED[i]);
              edtED243: LoadED243( Ufebs.ED[i]);
              edtED244: LoadED244( Ufebs.ED[i]);
              else      WriteInfo( edtName[Ufebs.ED[i].EDType]
                                    + ' - пока не обрабатываются.');
            end;
            ShowProgress(i + 1);
          end;
        end;

    edtED101,
    edtED102,
    edtED103,
    edtED104,
    edtED105,
    edtED110,
    edtED222: LoadED101_102_103_104_105_110_222(Ufebs);
    edtED108: LoadED108Main(Ufebs);   // exchange #2583
    edtED201, edtED206: LoadED201_206(Ufebs);
    edtED205: LoadED205(Ufebs);
    edtED207: LoadED207(Ufebs);
    edtED208: LoadED208(Ufebs); //не может быть в пакете ЭСИД, поэтому вызов только здесь
    edtED211: LoadED211(Ufebs);
    edtED215: LoadED215(Ufebs);
    edtED217: LoadED217(Ufebs);
    edtED219: LoadED219(Ufebs);
    edtED221: LoadED221(Ufebs);
    edtED243: LoadED243(Ufebs); //не может быть в пакете ЭСИД, поэтому вызов только здесь
    edtED244: LoadED244(Ufebs); //не может быть в пакете ЭСИД, поэтому вызов только здесь
    edtED330: WriteInfo('ED330: Информация о корректировке' +
      ' временного регламента функционирования' + #10 +
      ', текст сообщения' + Ufebs.CorrectionDescription);
    else WriteInfo(edtName[Ufebs.EDType] + ' - пока не обрабатываются.');
  end;
  MoveToArh;
end; {End LoadUfebs}


procedure LoadED101_102_103_104_105_110_222(ED: Variant);
var
  PersonalAcc:  String;
  XmlSpec, XmlLink, XmlOrgAcc: Variant;
  xPaytKind: string;
begin
{отладка
writelog('-----------------------------------------------------------');
writelog('Выполняется: LoadED101_102_103_104_105_110_222');
{отладка_конец}

  // Формирует стандартное сообщение о документе
  Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDDate) + ' Сумма: ' +
      Format('%.2f', [ED.Sum]);

  // exchange #2547 - доработка заполнения поля "вид платежа".
  // теперь либо берется из документа, либо то, что указано в конфиге.
  xPaytKind := ImpPayKind_2547( GetPayKindByED( ED));
  // проверяем возможные значения "вид платежа". если поле не допустимо
  // то отказываем обработку документа.
  // сделано так, поскольку требуется, чтобы вид платежа проверялся не
  // всегда во входном файле, а только тогда, когда указано брать вид платежа
  // из документа. если вид платежа берется из конфигурации, проверять то,
  // что указано в конфигурации.
  // если на данном этапе параметр "вид платежа" не указан, считается
  // что он не указан в файле или указан как "пусто" в конфигурации.
  if (xPaytKind <> '?') then
    if (LENGTH( xPaytKind) <= 0)
      then xPaytKind := GetPayKindByValue( ED.EDType, -1)
      else xPaytKind := GetPayKindByValue( ED.EDType, STRTOINT( xPaytKind));
  if (xPaytKind = '?') then begin
    WriteInfo( Msg + ' - недопустимое значение в поле "вид платежа". Документ не обрабатывается.');
    EXIT;
  end;

  ShowInfo(Msg);

  // Извещение о дебете кассовых документов - не обрабатываем
  if ED.EDType = edtED222 then
    if ED.CashDC = '2' then
    begin
      WriteLog(Msg);
      Exit;
    end;
  // Поиск счёта в справочнике АЦК
  if ED.EDType in [edtED101, edtED102, edtED103, edtED104, edtED105] then
    PersonalAcc := ED.Payee.PersonalAcc
  else if ED.EDType = edtED110 then
    PersonalAcc := ED.PayeeBrf.PersonalAcc
  else if ED.EDType = edtED222 then
    PersonalAcc := ED.CorrAcc;
  if FAccountLoginBudget then
  begin
    XmlOrgAcc := QueryXml(sqlOrgAccount + ' And B.Id = ?',
      [StrToInt(FormatDateTime('yyyy', FEDDate)), PersonalAcc, Budget_Id]);

{отладка
writelog('запрос (FAccountLoginBudget):'+sqlOrgAccount + ' And B.Id = ?');
writelog('год='+FormatDateTime('yyyy', FEDDate));
writelog('PersonalAcc='+PersonalAcc);
writelog('Budget_Id='+Budget_Id);
writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
{отладка_конец}

    if XmlOrgAcc.documentElement.childNodes.Length <> 1 then begin
      //ищем бюджет, организацию и счет по организации осущ. исполнение
      XmlOrgAcc := QueryXml(StringReplace(sqlOrgAccount, 'B.Org_Id = A.Org_Id',
        'B.Executor_id = A.Org_Id') + ' And B.Id = ?',
          [StrToInt(FormatDateTime('yyyy', FEDDate)), PersonalAcc, Budget_Id]);
{отладка
writelog('запрос (FAccountLoginBudget):'
          +StringReplace( sqlOrgAccount,
                          'B.Org_Id = A.Org_Id',
                          'B.Executor_id = A.Org_Id') + ' And B.Id = ?');
writelog('год='+FormatDateTime('yyyy', FEDDate));
writelog('PersonalAcc='+PersonalAcc);
writelog('Budget_Id='+Budget_Id);
writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
{отладка_конец}
    end;
  end else begin
    XmlOrgAcc := QueryXml(sqlOrgAccount, [StrToInt(FormatDateTime('yyyy', FEDDate)),
      PersonalAcc]);

{отладка
writelog('запрос (не FAccountLoginBudget):'
          +sqlOrgAccount);
writelog('год='+FormatDateTime('yyyy', FEDDate));
writelog('PersonalAcc='+PersonalAcc);
writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
{отладка_конец}

    //ищем бюджет, организацию и счет по организации осущ. исполнение
    if XmlOrgAcc.documentElement.childNodes.Length <> 1 then begin
      XmlOrgAcc := QueryXml(StringReplace(sqlOrgAccount, 'B.Org_Id = A.Org_Id',
        'B.Executor_id = A.Org_Id'), [StrToInt(FormatDateTime('yyyy', FEDDate)),
          PersonalAcc]);

{отладка
writelog('запрос (не FAccountLoginBudget):'
          +StringReplace( sqlOrgAccount,
                          'B.Org_Id = A.Org_Id',
                          'B.Executor_id = A.Org_Id') + ' And B.Id = ?');
writelog('год='+FormatDateTime('yyyy', FEDDate));
writelog('PersonalAcc='+PersonalAcc);
writelog('Budget_Id='+Budget_Id);
writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
{отладка_конец}
    end;
  end;

{отладка
writelog('исходный XmlOrgAcc='+XmlOrgAcc.xml);
{отладка_конец}

  XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
  
  { Exchange #2354
    При загрузке ed101, ed103, ed104, ed105, ed222
    по форматам УФЭБС в случаях, когда по существующему
    алгоритму не возможно однозначно определить бюджет загрузки дополнительно
    Проверить существование счета получателя.
      Поиск счёта в настройках счетов (Бухгалтерия - Настройка счетов -
    Счета ФО - группа полей Счета бюджета) с типом "Счет для учета операций
    БУ/АУ". Если счет в системе сущетсвует один, определить бюджет загрузки
    по его BUDGET_ID.
      Если счетов в системе найдено несколько, тогда выводить существующее
    сообщение об ошибке: "Счёт: %счет из выписки% в базе АЦК не однозначен".}
  if (XmlOrgAcc.length <> 1) then begin
    if (ED.EDType in [edtED101, edtED103, edtED104, edtED105, edtED222]) then begin
      XmlOrgAcc := QueryXml( sqlBuchFO_Account,
                            [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                              PersonalAcc]);
{отладка
writelog('запрос (ED101:sqlBuchFO_Account):' + sqlBuchFO_Account);
writelog('год='+FormatDateTime('yyyy', FEDDate));
writelog('PersonalAcc='+PersonalAcc);
writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
{отладка_конец}

      XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
    end;

    { exchange #2439
      Если счетов в системе найдено несколько, сверять значение "БИК" из ED
      со значениями "БИК" счетов найденных в справочнике системы,
      при однозначном совпадении значений "Счет" + "БИК" продолжать
      обработку документа, если по сочетанию "Счет" + "БИК" однозначно
      определить не удалось тогда выводить существующее сообщение об ошибке:
      "Счёт: %счет из выписки% в базе АЦК не однозначен".}
    if (XmlOrgAcc.length  > 1) then
      case ED.EDType of
        edtED101,edtED103,edtED104,edtED105: begin
              // для ED101,ED103,ED104,ED105 берем БИК - ED.Payee.Bank.BIC
              XmlOrgAcc := QueryXml( sqlBuchFO_Account_2439,
                                    [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                      ED.Payee.Bank.BIC,
                                      PersonalAcc]);
  {отладка
  writelog('запрос (ED101:sqlBuchFO_Account_2439):' + sqlBuchFO_Account_2439);
  writelog('год='+FormatDateTime('yyyy', FEDDate));
  writelog('ED.Payee.Bank.BIC='+ED.Payee.Bank.BIC);
  writelog('PersonalAcc='+PersonalAcc);
  writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
  {отладка_конец}

              XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
            end;

        edtED222: begin
              // для ED222 берем БИК - ED.BIC
              XmlOrgAcc := QueryXml( sqlBuchFO_Account_2439, //sqlOrgAccount222_2439,
                                    [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                      ED.BIC,
                                      PersonalAcc]);
  {отладка
  writelog('запрос (ED222:sqlOrgAccount222_2439):' + sqlOrgAccount222_2439);
  writelog('год='+FormatDateTime('yyyy', FEDDate));
  writelog('ED.BIC='+ED.BIC);
  writelog('PersonalAcc='+PersonalAcc);
  writelog('Результат:'#13#10+XmlOrgAcc.documentElement.xml);
  {отладка_конец}

              XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
            end;
      end;//case//
  end;


  if XmlOrgAcc.length  = 0 then
    raise('Файл: ' + FileIn + ''#13#10'Счёт: ' + PersonalAcc +
      ' не найден в базе АЦК' + ''#13#10'ЭД: ' + ED.XMLText);

  // если найдено несколько счетов (или ни одного) с указанным БИК,
  // то прерываем загрузку
  if (XmlOrgAcc.length > 1)
    then raise( 'Файл: ' + FileIn + ''#13#10'Счёт: ' + PersonalAcc
                + ' в базе АЦК не однозначен' + ''#13#10'ЭД: ' + ED.XMLText);

  XmlOrgAcc := XmlOrgAcc.items[0];

  // если в найденном ответе бюджет не определен для найденной организации
  // то это ошибка, иначе ЭД будет вставлен в прилогиненный бюджет.
  // однако это не верно, поэтому, если бюджет будет пустым - даем ошибку
  if (XmlOrgAcc.getAttribute('BUDGET_ID') = '')
    then raise( 'Файл: ' + FileIn + ''#13#10'Для счёта: ' + PersonalAcc
                + ' организации: ' + XmlOrgAcc.getAttribute('ORG_ID')
                + ' в базе АЦК не найден бюджет'
                + #13#10'ЭД: ' + ED.XMLText);

  // Проверяем условие фильтра по бюджету в настройках и бюджета, к которому относиться счёт
  if FiltrBudget and (XmlOrgAcc.getAttribute('BUDGET_ID') <> Budget_Id) then
    raise('В настройках установлен фильтр по бюджету' + #13+#10 +
      'Текущий бюджет: ' + Budget_Name + #13+#10 +
      'Документ принадлежит бюджету: ' + XmlOrgAcc.getAttribute('BUDGET_NAME'));
  // Проверка на повторную загрузку ЭД
  Foreign_Key := FormatDateTime('yyyymmdd', ED.EDDate) + ED.EDAuthor + IntToStr(ED.EDNo);
  Sql := 'Select P.Id From PayOrder P Where P.DocumentClass_Id = 24' +
    ' And P.Foreign_Key = ? And P.DispStatus_Id > -1';
  Xml := QueryXml(Sql, [Foreign_Key], False);
  if Xml.documentElement.childNodes.length > 0 then
  begin
    WriteInfo(Msg + ' - был ранее загружен');
    Exit;
  end;
  // Создаём Xml - задание навставку 24 класса
  Xml := CreateOleObject('Microsoft.XmlDom');
  Xml := Xml.appendChild(Xml.createElement('DOCUMENT'));
  Xml.setAttribute('action', 'insert');
  Xml.setAttribute('class', '24');
  // Дата ЭПД - дата зачисление (дата по банку в АЦК) может отличаться от даты
  // создания ПП в банке отправителе
  if ED.EDType in [edtED101, edtED102, edtED103, edtED104, edtED105, edtED110] then
    Xml.setAttribute('DOC_DATE', FormatDateTime('yyyy-mm-dd', ED.AccDoc.AccDocDate))
  else
    Xml.setAttribute('DOC_DATE', FormatDateTime('yyyy-mm-dd', ED.EDDate));
  Xml.setAttribute('CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate));
  Xml.setAttribute('AMOUNT', ED.Sum);
  Xml.setAttribute('REC_ID', XmlOrgAcc.getAttribute('ORG_ID'));
  Xml.setAttribute('REC_ACC_ID', XmlOrgAcc.getAttribute('ID'));

  // exchange #2696
  // поле 24 класса «Уникальный идентификатор начисления» закладки «ГИС ГМП»
  // для АЦК-Ф 2.33
  if ED.EDType in [edtED101, edtED103, edtED104, edtED105] then
    if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') >= 0) then
      if ( LENGTH( ED.PaymentID) > 0)
        then Xml.setAttribute('UIN', ED.PaymentID);

  // exchange #2547 - доработка заполнения поля "вид платежа".
  // теперь если берется из документа - пусто, либо то, что указано в конфиге
  Xml.setAttribute('PAYKIND', xPaytKind);

  Xml.setAttribute('FOREIGN_KEY', Foreign_Key);
  if ED.EDType in [edtED101, edtED102, edtED103, edtED104, edtED105, edtED110] then
  begin
    if (ED.EDType = edtED101) and FFillNumberEd101 then
    begin
      // exchange #3022
      // поменялся формат схем (версия схем).
      // поле AccDocNo стало 6 символов, поэтому дополняем 6ю нулями и отсекаем
      // по длине 6 символов.
      //if ( Ufebs.FormatVer = '2015.4.1') then begin
      if (Version_CompareEx( Ufebs.FormatVer, '2015.4.1') >= 0) then begin
        ED.AccDoc.AccDocNo := '000000' + ED.AccDoc.AccDocNo;
        ED.AccDoc.AccDocNo := Copy(ED.AccDoc.AccDocNo, Length(ED.AccDoc.AccDocNo) - 5, 6);
      end else begin
        ED.AccDoc.AccDocNo := '000' + ED.AccDoc.AccDocNo;
        ED.AccDoc.AccDocNo := Copy(ED.AccDoc.AccDocNo, Length(ED.AccDoc.AccDocNo) - 2, 3);
      end;
    end;
    Xml.setAttribute('DOC_NUMBER', ED.AccDoc.AccDocNo);
    if (ED.EDType <> edtED102) and (ED.Priority in [1 .. 6]) then
      Xml.setAttribute('QUEUE_KIND', ED.Priority);
    case ED.EDType of
      edtED101, edtED110: Xml.setAttribute('BANKOPER_ID', 1);
      edtED102: Xml.setAttribute('BANKOPER_ID', 8);
      edtED103: Xml.setAttribute('BANKOPER_ID', 2);
      edtED104: Xml.setAttribute('BANKOPER_ID', 6);
      edtED105: Xml.setAttribute('BANKOPER_ID', 9);
    end;
  end
  else if ED.EDType = edtED222 then
  begin
    Xml.setAttribute('DOC_NUMBER', ED.CashDocNo);
    Xml.setAttribute('BANKOPER_ID', 4);
    Xml.setAttribute('PAY_BIC', ED.BIC);
    Xml.setAttribute('PAY_ACCOUNT', ED.CashAcc);
    Xml.setAttribute('REC_BIC', ED.BIC);
    Xml.setAttribute('REC_ACCOUNT', ED.CorrAcc);
    Xml.setAttribute('REC_NAME', XmlOrgAcc.getAttribute('DESCRIPTION'));
    Xml.setAttribute('REC_KPP', XmlOrgAcc.getAttribute('KPP'));
    Xml.setAttribute('DESCRIPTION', 'Обьявление на взнос наличными' +
      ', приходного кассового ордера');
  end;
  if ED.EDType in [edtED101, edtED102, edtED103, edtED104, edtED105] then
  begin
    if ED.EDType = edtED102 then
      Xml.setAttribute('DESCRIPTION', ED.GoodsDescription)
    else
      Xml.setAttribute('DESCRIPTION', ED.Purpose);
    Xml.setAttribute('PAY_BIC', ED.Payer.Bank.BIC);
    Xml.setAttribute('PAY_CORACCOUNT', ED.Payer.Bank.CorrespAcc);
    Xml.setAttribute('PAY_ACCOUNT', ED.Payer.PersonalAcc);
    Xml.setAttribute('PAY_NAME', ED.Payer.Name);
    Xml.setAttribute('PAY_TAXCODE', ED.Payer.INN);
    Xml.setAttribute('PAY_KPP', ED.Payer.KPP);
    Xml.setAttribute('REC_BIC', ED.Payee.Bank.BIC);
    Xml.setAttribute('REC_CORACCOUNT', ED.Payee.Bank.CorrespAcc);
    Xml.setAttribute('REC_ACCOUNT', ED.Payee.PersonalAcc);
    Xml.setAttribute('REC_NAME', XmlOrgAcc.getAttribute('DESCRIPTION'));
    Xml.setAttribute('REC_TAXCODE', ED.Payee.INN);
    Xml.setAttribute('ORG_TAXCODE', ED.Payee.INN);
    Xml.setAttribute('REC_KPP', XmlOrgAcc.getAttribute('KPP'));
    Xml.setAttribute('ORG_KPP', ED.Payee.KPP);
    Xml.setAttribute('ORG_NAME', ED.Payee.Name);
    FillOrgAttribute(Xml, XmlOrgAcc.getAttribute('BUDGET_ID'));
    FillDepartmentalInfo(ED, Xml, XmlOrgAcc.getAttribute('BUDGET_ID'));
  end
  else if ED.EDType = edtED110 then
  begin
    Xml.setAttribute('DESCRIPTION', 'ЭПД сокращённого формата');
    Xml.setAttribute('PAY_BIC', ED.PayerBrf.Bank.BIC);
    Xml.setAttribute('PAY_CORACCOUNT', ED.PayerBrf.Bank.CorrespAcc);
    Xml.setAttribute('PAY_ACCOUNT', ED.PayerBrf.PersonalAcc);
    Xml.setAttribute('PAY_TAXCODE', ED.PayerBrf.INN);
    Xml.setAttribute('REC_BIC', ED.PayeeBrf.Bank.BIC);
    Xml.setAttribute('REC_CORACCOUNT', ED.PayeeBrf.Bank.CorrespAcc);
    Xml.setAttribute('REC_ACCOUNT', ED.PayeeBrf.PersonalAcc);
    Xml.setAttribute('REC_TAXCODE', ED.PayeeBrf.INN);
    Xml.setAttribute('REC_KPP', XmlOrgAcc.getAttribute('KPP'));
    Xml.setAttribute('ORG_TAXCODE', ED.PayeeBrf.INN);
    FillOrgAttribute(Xml, XmlOrgAcc.getAttribute('BUDGET_ID'));
  end;



  Xml.ownerDocument.loadXML(ExecXML(Xml.ownerDocument.xml, XmlOrgAcc.getAttribute('BUDGET_ID')));
  Xml := Xml.ownerDocument.documentElement;
  WriteLog(Msg);
  ExecProc('DOCUMENT', ['action', 'process', 'class', Xml.getAttribute('DOCUMENTCLASS_ID'),
    'ID', Xml.getAttribute('ID')], XmlOrgAcc.getAttribute('BUDGET_ID'));
  if fsScript <> Null then
  begin
    if IsDebug then
    begin
      ED.makeXML;
      ED.formatXML;
      ED.SaveToFile('C:\Temp\Ed.xml');
      Xml.ownerDocument.Save('C:\Temp\Doc.xml');
    end;
    if not IsDebug then
      fsScript.Exec('SpawnPayOrder', [ED, Xml]);
  end;
  VisualMainLoad(Xml.getAttribute('DOCUMENTCLASS_ID'), Xml.getAttribute('ID'));
  if ED.EDType = edtED222 then
    CashierLink(ED.Sum, FormatDateTime('yyyy-mm-dd', FEDDate),
      Xml.ownerDocument.documentElement, XmlOrgAcc.getAttribute('BUDGET_ID'));
  if (ED.EDType in [edtED102, edtED103]) then
    Exit;
  // todo Вынести в отдельный модуль
  // Для Сургута зачисление спецсредств
  if (ED.EDType = edtED110) or (ED.EDType = edtED222) or (ED.DepartmentalInfo.CBC = '')
    or (ED.Payee.PersonalAcc <> '40703810800003000004') then
    Exit;


  XmlSpec := CreateOleObject('Microsoft.XmlDom');
  { exchange #3061
    Значения для полей кодов классификации  с типом "Доходы" (поле 104)
    требуется вычислять из значения реквизита ed:DepartmentalInfo.CBC:
      - Администатор = значению CBC с 1 по 3 знак (начиная слева);
      - КВД - значению CBC с 4 по 20 знак (начиная слева)
      - КОСГУ - не заполнять.
    это должно работать только для бюджета с годом 2016 и выше.}
  if vBudgetYear2016andAbove then begin

    Sql := 'Select distinct P.Org_Id, P.OrgAccount_Id, L.* From Org O' +
      ' Left Join OrgRoles R On (R.Org_Id = O.Id)' +
      ' Left Join OrgAccount A On (A.Org_Id = O.Id)' +
      ' Left Join Estimate E On (E.Org_Id = O.Id)' +
      ' Left Join Permission P On (P.Org_Id = O.Id)' +
      ' Left Join PermissionLine L On (L.Permission_Id = P.Id)' +
      ' Where R.OrgRole_Id = 0 And A.Close_Date Is Null And A.Budget_Flag <> 1' +
      ' And  E.EstKind_Id = 5 And P.DispStatus_Id = 1  And A.OrgAccType_Id = 1 And O.TaxCode = ? ' +
      ' And L.Kadmd_Code = ? And L.Kd_Code = ? And P.End_Date >= ?';
    Query.AddStr(ED.Payee.INN);
    Query.AddStr(Copy(ED.DepartmentalInfo.CBC, 1, 3));
    Query.AddStr(Copy(ED.DepartmentalInfo.CBC, 4, 17));
    Query.addDate(FEDDate);
  end else begin

    // старая реализация
    Sql := 'Select distinct P.Org_Id, P.OrgAccount_Id, L.* From Org O' +
      ' Left Join OrgRoles R On (R.Org_Id = O.Id)' +
      ' Left Join OrgAccount A On (A.Org_Id = O.Id)' +
      ' Left Join Estimate E On (E.Org_Id = O.Id)' +
      ' Left Join Permission P On (P.Org_Id = O.Id)' +
      ' Left Join PermissionLine L On (L.Permission_Id = P.Id)' +
      ' Where R.OrgRole_Id = 0 And A.Close_Date Is Null And A.Budget_Flag <> 1' +
      ' And  E.EstKind_Id = 5 And P.DispStatus_Id = 1  And A.OrgAccType_Id = 1 And O.TaxCode = ? ' +
      ' And L.Kadmd_Code = ? And L.Kd_Code = ? And L.Kesd_Code = ? And P.End_Date >= ?';
    Query.AddStr(ED.Payee.INN);
    Query.AddStr(Copy(ED.DepartmentalInfo.CBC, 1, 3));
    Query.AddStr(Copy(ED.DepartmentalInfo.CBC, 4, 14));
    Query.AddStr(Copy(ED.DepartmentalInfo.CBC, 18, 3));
    Query.addDate(FEDDate);
  end;
  XmlSpec.LoadXML(Query.Run(Sql));


  if XmlSpec.documentElement.childNodes.length <> 1 then
    Exit;
  XmlSpec := XmlSpec.documentElement.childNodes.item[0];
  XmlLink := CreateOleObject('Microsoft.XmlDom');
  XmlLink.LoadXml(ExecProc('DOCUMENT', ['action', 'spawn_payincorder', 'class',
    Xml.getAttribute('DOCUMENTCLASS_ID'), 'ID', Xml.getAttribute('ID')],
    XmlOrgAcc.getAttribute('BUDGET_ID')));
  Sql := 'Select P.Id From PayIncOrder P' +
    ' Left Join Document D On (D.Id = P.Document_Id)' +
    ' Where D.Parent_Id = ? And D.DocumentClass_Id = 74 And D.DispStatus_Id <> -1';
  Query.addLong(Xml.getAttribute('DOCUMENT_ID'));
  XmlLink.LoadXML(Query.Run(Sql));
  XmlLink.LoadXML(ExecProc('DOCUMENT', ['action', 'read', 'class', 74, 'ID',
    XmlLink.documentElement.childNodes.item[0].getAttribute('ID')],
    XmlOrgAcc.getAttribute('BUDGET_ID')));
  XmlLink := XmlLink.documentElement;
  XmlLink.setAttribute('action', 'update');
  XmlLink.setAttribute('class', 74);
  XmlLink.setAttribute('DOC_DATE', XmlLink.getAttribute('CARRY_DATE'));
  XmlLink.setAttribute('ESTIMATE_ID' , XmlSpec.getAttribute('ESTIMATE_ID'));
  XmlLink.setAttribute('FSD_ID', XmlSpec.getAttribute('FSD_ID'));
  XmlLink.setAttribute('FSR_ID', XmlSpec.getAttribute('FSR_ID'));
  XmlLink.setAttribute('FUNDSOURCE_ID', XmlSpec.getAttribute('FUNDSOURCE_ID'));
  XmlLink.setAttribute('KADMD_CODE', XmlSpec.getAttribute('KADMD_CODE'));
  XmlLink.setAttribute('KADMR_CODE', XmlSpec.getAttribute('KADMR_CODE'));
  XmlLink.setAttribute('KCSR_CODE', XmlSpec.getAttribute('KCSR_CODE'));
  XmlLink.setAttribute('KD_CODE', XmlSpec.getAttribute('KD_CODE'));
  XmlLink.setAttribute('KDD_CODE', XmlSpec.getAttribute('KDD_CODE'));
  XmlLink.setAttribute('KDE_CODE', XmlSpec.getAttribute('KDE_CODE'));
  XmlLink.setAttribute('KDF_CODE', XmlSpec.getAttribute('KDF_CODE'));
  XmlLink.setAttribute('KDR_CODE', XmlSpec.getAttribute('KDR_CODE'));
  XmlLink.setAttribute('KDT_CODE', XmlSpec.getAttribute('KDT_CODE'));
  XmlLink.setAttribute('KESD_CODE', XmlSpec.getAttribute('KESD_CODE'));
  XmlLink.setAttribute('KESR_CODE', XmlSpec.getAttribute('KESR_CODE'));
  XmlLink.setAttribute('KFSR_CODE', XmlSpec.getAttribute('KFSR_CODE'));
  XmlLink.setAttribute('KVR_CODE', XmlSpec.getAttribute('KVR_CODE'));
  XmlLink.setAttribute('ORG_ID', XmlSpec.getAttribute('ORG_ID'));
  XmlLink.setAttribute('ORGACCOUNT_ID', XmlSpec.getAttribute('ORGACCOUNT_ID'));
  XmlLink.setAttribute('PAYER_ID', XmlSpec.getAttribute('PAYER_ID'));
  XmlLink.setAttribute('PERMISSIONLINE_ID', XmlSpec.getAttribute('ID'));
  XmlLink.setAttribute('RECEIVER_ID', XmlSpec.getAttribute('RECEIVER_ID'));
  XmlLink.setAttribute('RECIPIENT_ID', XmlSpec.getAttribute('RECIPIENT_ID'));
  XmlLink.setAttribute('TERRITORY_ID', XmlSpec.getAttribute('TERRITORY_ID'));
  XmlLink := XmlLink.ownerDocument;
  XmlLink.LoadXml(ExecXML(XmlLink.xml, XmlOrgAcc.getAttribute('BUDGET_ID')));
  VisualMainLoad(Xml.getAttribute('DOCUMENTCLASS_ID'), Xml.getAttribute('ID'));
end; {End LoadED101_102_103_104_105_110_222}

function CheckDocStatus(Doc: Variant): Boolean;
begin
  Result := False;
  if Doc.getAttribute('EXCH_RESTORE') <> '0' then
  begin
    WriteInfo(Msg + ' - Был востановлен из архива');
    Exit;
  end;
  if Doc.getAttribute('DOCUMENT_ID') <> '' then
  begin
    WriteInfo(Msg + ' - Уже имеет дебетовое приложение');
    Exit;
  end;
  Result := True;
end; {End CheckDocStatus}


{~LoadED108Main
  добавлена промежуточная подпрограмма, всвязи с доработкой #2769.
  в подпрограмме проверяется, если включена настройка в конфиге
  «Формировать одно Приложение к выписке кредитовое по ed108»=да,
  то вызывается новая подпрограмма загрузки ED108 по #2769,
  если значение параметра =нет - вызывается подпрограмма по #2583.}
procedure LoadED108Main(ED: Variant);
begin
  if vCfgLoadED108by2769
    then LoadED108by2769( ED)
    else LoadED108( ED);
end;

procedure LoadED201_206(ED: Variant);
  {----------------------------------------------------------------------------}
  function IsIgnoreCtrlCodeGroup_( aGroupCode: integer): boolean;
  var
    xMaxValue: integer;
    xMinValue: integer;
  begin
    { возвращает =true, если код aCtrlCode находится в пределах кодов:
      от aGroupCode00 до aGroupCode99}
    xMinValue:= (aGroupCode * 100);
    xMaxValue:= (xMinValue + 99);
    if ((ED.CtrlCode >= xMinValue) AND (ED.CtrlCode <= xMaxValue)) then begin
      WriteInfo( FORMAT( '%s № %d на %s № %d Дата %s с кодом %s - %s',
                        [ edtName[ED.EDType],
                          ED.EDNo,
                          edtName[edtED101],
                          ED.EDRefID.EDNo,
                          FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate),
                          INTTOSTR( ED.CtrlCode),
                          ED.Annotation]));
      Result := TRUE;
      EXIT;
    end;
    Result := FALSE;
  end;
  {----------------------------------------------------------------------------}
  {~DoSearchPP_
    поиск пп.
    результат:
      xml результата запроса.
    exchange #3080
      переделано по дополнительному фильтру поиска ПП.
      aMode: критерий поиска
        =0 - счет плательщика
        =1 - cчёт УФК плательщика»}
  function DoSearchPP_( aMode: integer;
                        aED206_DC_3: boolean): Variant;
  var
    xQuery: TRunQuery;
  begin

      try
        { exchange #3080
          чтобы доработать запрос с расширяемым набором параметров,
          будем использовать параметры запроса в виде массива variant.
          это дает то, что к запросу можно легко добавить дополнительные условия
          выборки ПП, чем использовать if then или case.}
        xQuery:= TRunQuery.Create;
        try
          Sql := ' Select P.Id, P.Amount, P.DocumentClass_Id,'
                +' P.DispStatus_Id, P.ExtStatus_Id,'
                +' D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore,'
                +' P.Budget_Id,  E.Exch_Number'
                +' From Exch_Document E'
                +' Left Join PayOrder P On (P.Id = E.Exch_DocumentRef'
                +'     And P.DocumentClass_Id = E.Exch_ClassRef)'
                +' Left Join Document D On (D.Parent_Id = P.Document_Id'
                +'     And D.DispStatus_Id > -1)'
          // exchange #2774
          // проблема в том, что по ED201/ED206 при таком запросе SQL, в записи эксча
          // есть ссылка на ЭД (Exch_DocumentRef), но в БД уже нет такого документа
          // по этой ссылке, поэтому возвращается пустая запись с незаполненными полями.
          // в запросе есть проблемное место:
          // нужно найти приложения дебетовые, выгруженные за указанную дату по уфэбс
          // (и номеру пакета/эд) и для них возвращается родительский документ.
          // затем в родительском документе выполняется spawn_decline (ed201)
          // или spawn_finish (ed206).
          // проблема в том, что в запросе не проверяется класс и статус
          // родительского ЭД (кроме того, что родительский ЭД не удален).
          // в результате приходится экшены обрамляить в try-except и игнорировать
          // сбой выполнения экшена.
          // помимо этого в результате запроса возвращаются пустые эд (#2774) поэтому
          // в условие where добавлена проверка: "and D.id is not null".
          // суть исправления - избавится от пустых эд в результате запроса.
          // но можно так же и проверять статус родительского эд, при этом убрать
          // перехват сбоя при выполнении экшена (можно оставить, но это уже будет
          // критический сбой).
          // exchange #2796
          // с условием and D.id is not null будет искаться только ПП для квитовки
          // у которого уже есть порожденное ЭД, а у нас нормальное несквитованное ПП
          // (без порождений). поэтому вместо D.id is not null нужно ставить
          // P.id is not null.
                +' Where E.Exch_Date = ? And Exch_Name = ?'
                +' and P.id is not null ';
          xQuery.AddDate( ED.EDRefID.EDDate);
          xQuery.AddStr( Exch_Name);

          if ED.EDRefID.EDNo > DPEDNo then begin
            Sql := Sql  + ' And E.Exch_Packet = ?';
            xQuery.AddInt( ED.EDRefID.EDNo - DPEDNo);
        //    Xml := QueryXml(Sql, [ ED.EDRefID.EDDate, Exch_Name, ED.EDRefID.EDNo - DPEDNo])
          end else begin
            Sql := Sql  + ' And E.Exch_Number = ?';
            xQuery.AddInt( ED.EDRefID.EDNo);
        //    Xml := QueryXml(Sql, [ ED.EDRefID.EDDate, Exch_Name, ED.EDRefID.EDNo]);
          end;

          // exchange #3080
          // добавляем критерий поиска для ED206.DC=3.
          if aED206_DC_3 then begin
            { по «Счёту УФК плательщика»/счет плательщика= Acc, «Сумме»= Sum,
              «БИК» блока «Получатель»= BICCorr ранее выгруженное ПП
              (на любом статусе, кроме «Удален»).}
            case aMode of
              1:    Sql := Sql +' And P.PAY_UFK_ACCOUNT = ?'
              else  Sql := Sql +' And P.PAY_ACCOUNT = ?'
            end;//case//
            xQuery.AddStr( ED.Acc);

            Sql := Sql +' and P.AMOUNT=?';
            xQuery.AddCurr( ED.Sum);

            { поскольку допускается пустая строка, в бд может быть либо null
              либо пустая строка.}
            if (LENGTH( ED.BICCorr) <= 0)
              then Sql := Sql + ' and (PAY_BIC is null or PAY_BIC=?)'
              else Sql := Sql + ' and (PAY_BIC=?)';
            xQuery.AddStr( ED.BICCorr);
          end;

          // exchange #3080 - запрос с обработкой результата
          Result := CreateOleObject( 'Microsoft.XmlDom');
          Result.LoadXml( xQuery.Run( Sql));
          finally
            xQuery.Free;
        end;
        except
          ExceptionProc( 'DoSearchPP_');
      end;

  end;
  {----------------------------------------------------------------------------}
var
  i: Integer;
  xED206_DC_3: boolean;
begin

    try
      { exchange #2547
        2.2.	Если «Признак дебета/кредита (DC)» = 2, не пытаться искать исходный
        документ в базе, писать в лог сообщение «Расчетный документ (AccDocNo)
        от (AccDocDate) пропущен. Кредитовые документы создаются на основании
        ed1**» и дальше обрабатывать файл.
        по согласованию с АО, проверяется, если ED <>1, то ЭД не ищется в БД.}
      // exchange #3080
      // загрузка ed206 по новому с версии 2016.1.1
      xED206_DC_3 := FALSE;
      if (ED.EDType = edtED206) then
        case ED.DC of
          1: begin {заглушка} end;   // загрузка всегда
          3: if vCfg_LoadED206_3080
               then xED206_DC_3 := TRUE
               else EXIT;
        else begin
              // exchange #2598
              // убрано сообщение из лога
        {      WriteInfo( FORMAT( 'Расчетный документ %s от %s пропущен. '
                                +'Кредитовые документы создаются на основании ed1**.',
                                 [ ED.AccDoc.AccDocNo,
                                   FormatDateTime('dd.mm.yyyy', ED.AccDoc.AccDocDate)]));}

               Exit;
             end;
        end;//case//

      // Формируем стандартное сообщение об ЭД
      if ED.EDRefID.EDNo > DPEDNo then
        Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
          ' на ' + edtName[edtPacketEPD] + Format(' № %d', [ED.EDRefID.EDNo]) +
          ' (' + IntToStr(ED.EDRefID.EDNo - DPEDNo) + ')'
      else
        Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
          ' на ' + edtName[edtED101] + Format(' № %d', [ED.EDRefID.EDNo]);


      ShowInfo(Msg);

    //  if (ED.EDType = edtED201) and (ED.CtrlCode <> '') and (ED.CtrlCode <> '2900') then
    //  begin
    //    WriteInfo(edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
    //      ' Ошибка принятия в ЦБ - C кодом (' + ED.CtrlCode + '), Причина отказа: ' + ED.Annotation);
    //    Exit;
    //  end;

      // Поиск ЭД в архиве выгрузок
      // exchange #2500
      // проверка - может отсутствовать дата. в этом случае проверяем, если дата
      // не указана, по умолчанию, она заполняется значением 0, но поскольку число
      // вещественное не факт, что оно =0, поэтому убирая знак, проверяем в пределах
      // единицы (это 1890 год).
      if ( ABS( ED.EDRefID.EDDate) < 1) then
      begin
        WriteInfo('Извещение о результатах контроля Номер ' + IntToStr(ED.EDNo) +
          ' от ' + FormatDateTime('dd.mm.yyyy', ED.EDDate) +
          ' пропущено, отсутствует идентификатор исходного ЭД.');
        Exit;
      end;

      { exchange #3080
        поиск перенесен в отдельную подпрограмму.
        для поиска по exchange #3080 выполняем поиск:
        в начале счет сравниваем: счет плательщика=acc, а если не нашли,
        тогда: по «Счёту УФК плательщика»= Acc.
        если по счет плательщика=acc нашли несколько, по
        «Счёту УФК плательщика»= Acc не ищем.
        добавлено сообщение в лог о доп.критериях поиска.}
      Xml := DoSearchPP_( 0, xED206_DC_3);
      if xED206_DC_3 then
        if (Xml.documentElement.ChildNodes.length = 0) then begin
          Xml := DoSearchPP_( 1, xED206_DC_3);
          Msg := Msg
                  +FORMAT(  ' (счет УФК плательщика = %s, сумма = %.2f,'
                           +' БИК = %s)',
                             [ ED.Acc,
                               ED.Sum,
                               ED.BICCorr]);
        end else begin
          Msg := Msg
                  +FORMAT(  ' (счет плательщика = %s, сумма = %.2f,'
                           +' БИК = %s)',
                             [ ED.Acc,
                               ED.Sum,
                               ED.BICCorr]);
        end;

      if Xml.documentElement.ChildNodes.length = 0 then begin
        WriteInfo(Msg + ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) +
          ' - ЭД не найден в базе');
        Exit;
      end;

      if (ED.EDType = edtED201) then begin
        if (ED.EDRefID.EDNo > DPEDNo) then begin
          Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
            ' на ' + edtName[edtPacketEPD] + Format(' № %d', [ED.EDRefID.EDNo]) +
            ' - причина: ' + ED.Annotation;
          WriteInfo(Msg);
          if MessageDlg(Msg + ''#13#10'Отказать весь пакет ?', mtConfirmation, mbYes + mbNo, 0) = mrNo then
          begin
            WriteInfo('Отмена отказа всех ЭД, входящих в пакет');
            Exit;
          end;
          WriteInfo('Отказ всех ЭД, входящих в пакет');
        end;

        if (ED.CtrlCode = '2900') then begin
          WriteLog(edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
            ' на ' + edtName[edtED101] + Format(' № %d', [ED.EDRefID.EDNo]) +
            ' Дата ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) +
            ' - C кодом (2900) - Успешное завершение первой стадии контроля');
          Exit;
        end;
      end;

      // exchange #2759
      // ФТ-1: по ED201 добавлен отказ по другим кодам ошибок:
      // 26** , 27**, 28**, 29** - так как данные коды относятся к ошибкам класса
      // «Правила логического контроля реквизитов ЭСИД» и к отказу платежных
      // документов (пакету платежных документов) отношения не имеют.
      if (ED.EDType = edtED201) then
        if IsIgnoreCtrlCodeGroup_( 29)
          then EXIT
          else
        if IsIgnoreCtrlCodeGroup_( 28)
          then EXIT
          else
        if IsIgnoreCtrlCodeGroup_( 27)
          then EXIT
          else
        if IsIgnoreCtrlCodeGroup_( 26)
          then EXIT;

    

      if ED.EDRefID.EDNo > DPEDNo then
        SetProgressBarMax(Xml.documentElement.childNodes.Length);
      for i := 0 to Xml.documentElement.childNodes.Length - 1 do
      begin
        Node := Xml.documentElement.childNodes.item[i];
        Msg := edtName[ED.EDType] + Format(' № %d',[ED.EDNo]) +
          ' на ' + edtName[edtED101] + Format(' № %s',[Node.getAttribute('EXCH_NUMBER')]) +
          ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) +
          ' Сумма: ' + Format('%.2f', [StrToCurr(Node.getAttribute('AMOUNT'))]);
        if CheckDocStatus(Node) then
        begin
          // exchange #2545 - перехват сбоя линковки ЭД
          try
            case ED.EDType of
              edtED201:
                begin
                  // exchange #2759
                  // ФТ2: При загрузке любых ЭСИД банка требуется обрабатывать
                  // (формировать) платежные документы только для бюджета логина
                  // либо доступных роли пользователя бюджетов.
                  // проверяем прилогиненный бюджет
                  if (Node.getAttribute('BUDGET_ID') <> Budget_Id) then
                    // если нет прав на все бюджеты
                    if NOT vAllBudgetForUser then
                      // проверяем доступный бюджет для пользователя.
                      // если в результате, ни текущий ни разрешенный бюджет для
                      // этого ПП не подходит - игнорируем таую запись ПП.
                      if (QueryField( ' Select count( * ) N From ('
                                     +' select distinct b.id from Budget B'
                                     +' join userbudget ub on ub.budget_id=B.ID and ub.access_mode>0'
                                     +' Where B.FinYear = ?'
                                     +' and ub.sysuser_id=?'
                                     +' and b.id in (?))',
                                      [ FormatDateTime('yyyy', ED.EDRefID.EDDate),
                                        UserID,
                                        Node.getAttribute('BUDGET_ID')],
                                      'N') = '0')
                        then CONTINUE;

                  WriteInfo(Msg + ' - Причина отказа: ' + ED.Annotation, True);
                  ExecProc('DOCUMENT', ['action', 'spawn_decline', 'class',
                    Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
                    'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                    'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                    'REMARK', ED.Annotation], Node.getAttribute('BUDGET_ID'));
                end;
              edtED206:
                begin
                  WriteLog(Msg, True);
                  ExecProc('DOCUMENT', ['action', 'spawn_finish', 'class',
                    Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
                    'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                    'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate)],
                    Node.getAttribute('BUDGET_ID'))
                end;
            end;
            except
              WriteLog( Msg + ' - ЭД не слинкован (игнорируемый сбой).'
                        + #13#10 + LastException.Message);
          end;
          VisualMainLoad(Node.getAttribute('DOCUMENTCLASS_ID'), Node.getAttribute('ID'));
          if ED.EDRefID.EDNo > DPEDNo then
            ShowProgress(i + 1);
        end;
      end;

      except
        ExceptionProc( 'LoadED201_206');
    end;

end; {End LoadED201_206}

procedure LoadED205(ED: Variant);
var
  i: Integer;
  xMsg: string;
begin

  if ED.EDRefID.EDNo > DPEDNo then
    Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
      ' на ' + edtName[edtPacketEPD] + Format(' № %d', [ED.EDRefID.EDNo]) +
      ' (' + IntToStr(ED.EDRefID.EDNo - DPEDNo) + ')'
  else
    Msg := edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
      ' на ' + edtName[edtED101] + Format(' № %d', [ED.EDRefID.EDNo]);

  StatusBarSimpleText(Msg);
  Sql := 'Select P.Id, P.Amount, P.DocumentClass_Id, P.DispStatus_Id, P.ExtStatus_Id' +
    ', D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore, P.Budget_Id' +
    ', E.Exch_Number' +
    ' From Exch_Document E' +
    ' Left Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
    ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
    ' Where E.Exch_Date = ? And E.Exch_Number = ? And Exch_Name = ?';
  if ED.EDRefID.EDNo > DPEDNo then
    Xml := QueryXml(Sql, [ED.EDRefID.EDDate, ED.EDRefID.EDNo - DPEDNo, Exch_Name])
  else
    Xml := QueryXml(Sql, [ED.EDRefID.EDDate, ED.EDRefID.EDNo, Exch_Name]);
  if Xml.documentElement.ChildNodes.length = 0 then
  begin
    WriteInfo(Msg + ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) +
      ' - ЭД не найден в базе');
    Exit;
  end;
  if ED.EDRefID.EDNo > DPEDNo then
  begin
    SetProgressBarMax(Xml.documentElement.childNodes.Length);
    Msg := edtName[ED.EDType] + ' на ' + edtName[edtPacketEPD] +
      Format(' № %d', [ED.EDRefID.EDNo]) + ' (' + IntToStr(ED.EDRefID.EDNo - DPEDNo) +
      ') - ' + sscName[StrToInt(ED.StatusStateCode)];
    if StrToInt(ED.StatusStateCode) in [20, 21] then
      Msg := Msg + ' - причина отказа: ' + ED.Annotation;
    WriteInfo(Msg);
    if StrToInt(ED.StatusStateCode) in [4, 20, 21, 31] then
    begin
      Msg := Msg +''#13#10'Отказать весь пакет ?';
      if MessageDlg(Msg, mtConfirmation, mbYes + mbNo, 0) = mrNo then
      begin
        WriteInfo('Отмена отказа всех ЭД, входящих в пакет');
        Exit;
      end;
      WriteInfo('Отказ всех ЭД, входящих в пакет');
    end;
  end;

  for i := 0 to Xml.documentElement.childNodes.Length - 1 do
  begin
    Node := Xml.documentElement.childNodes.item[i];

    // exchange #2788
    // проблема в том, что по ED205 при таком запросе, в записи эксча есть
    // ссылка на ЭД (Exch_DocumentRef), но в БД уже нет такого документа
    // по этой ссылке, поэтому возвращается пустая запись с незаполненными
    // полями. аналгичная проблема - #2774.
    // по причине, что в бд могут быть записи с пустыми данными, т.е. поля
    // суммы, id, номер класса и др. не заполнены (некорректный запрос),
    // из-за этого возникает сбой: в начале, при формировании
    // записи для лога, а если это пройдет - при выполнении экшенов.
    // поэтому здесь будем проверять содержимое необходимых полей, и если
    // хотя бы одно поле не будет заполнено, такой ЭД (и ED) пропускаем.
    // можно было решить проблему как в #2774 - добавив в запрос
    // выражение: "and D.id is not null". тем самым, если ЭД в бд не будет,
    // то и результат будет пустым.
    xMsg := '';
    if (LENGTH( TRIM( VarToStr( Node.getAttribute('AMOUNT')))) <= 0)
      then xMsg := 'суммы';
    if (LENGTH( TRIM( VarToStr( Node.getAttribute('DOCUMENTCLASS_ID')))) <= 0)
      then begin
        if (LENGTH( xMsg) > 0)
          then xMsg := xMsg + ', ';
        xMsg := xMsg + 'номера класса ЭД';
      end;
    if (LENGTH( TRIM( VarToStr( Node.getAttribute('ID')))) <= 0)
      then begin
        if (LENGTH( xMsg) > 0)
          then xMsg := xMsg + ', ';
        xMsg := xMsg + 'ид.документа';
      end;
    if (LENGTH( xMsg) > 0) then begin
      WriteInfo(
            FORMAT( '%s на %s № %s Дата: %s - ЭД не найден в БД. Обработка файла игнорируется.',
                    [ edtName[ED.EDType],
                      edtName[edtED101],
                      Node.getAttribute('EXCH_NUMBER'),
                      FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate)]));
      EXIT;
    end;

    Msg := edtName[ED.EDType] + ' на ' + edtName[edtED101] +
      Format(' № %s',[Node.getAttribute('EXCH_NUMBER')]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) +
      ' Сумма: ' + Format('%.2f', [StrToCurr(Node.getAttribute('AMOUNT'))]);
    if CheckDocStatus(Node) then
    begin
      Msg := Msg + ' - ' + sscName[StrToInt(ED.StatusStateCode)];
      if StrToInt(ED.StatusStateCode) in [20, 21] then
        Msg := Msg + ' - причина отказа: ' + ED.Annotation;
      WriteInfo(Msg);
      // exchange #2545 - перехват сбоя линковки ЭД
      try
        case StrToInt(ED.StatusStateCode) of
          0, 9:
            ExecProc('DOCUMENT', ['action', 'spawn_finish', 'class',
              Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
              'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
              'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate)],
              Node.getAttribute('BUDGET_ID'));
          4, 20, 21, 31:
            ExecProc('DOCUMENT', ['action', 'spawn_decline', 'class',
              Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
              'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
              'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
              'REMARK', sscName[StrToInt(ED.StatusStateCode)] + ' - ' + ED.Annotation],
              Node.getAttribute('BUDGET_ID'));
        end;
        except
          WriteLog( Msg + ' - ЭД не слинкован (игнорируемый сбой).'
                    + #13#10 + LastException.Message);
      end;
      if StrToInt(ED.StatusStateCode) in [0, 4, 9, 20, 21, 31] then
        VisualMainLoad(Node.getAttribute('DOCUMENTCLASS_ID'), Node.getAttribute('ID'));
      if ED.EDRefID.EDNo > DPEDNo then
        ShowProgress(i + 1);
    end;
  end;

end; {End LoadED205}

procedure LoadED207(ED: Variant);
var
  i: Integer;
  procedure LoadEDInfo(EDInfo: Variant);
  begin
    Sql := 'Select P.Id, P.Amount, P.DocumentClass_Id, P.DispStatus_Id, P.ExtStatus_Id' +
      ', D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore, P.Budget_Id' +
      ', E.Exch_Number' +
      ' From Exch_Document E' +
      ' Left Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
      ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
      ' Where E.Exch_Date = ? And E.Exch_Number = ? And Exch_Name = ?';
    Xml := QueryXml(Sql, [EDInfo.EDRefID.EDDate, EDInfo.EDRefID.EDNo, Exch_Name]);
    if Xml.documentElement.ChildNodes.length = 0 then
    begin
      WriteInfo(edtName[ED.EDType] + '-><EDInfo> на ' + edtName[edtED101] +
        Format(' № %d', [EDInfo.EDRefID.EDNo]) + ' Дата: ' + FormatDateTime('dd.mm.yyyy',
        EDInfo.EDRefID.EDDate) + ' - ЭД не найден в базе');
      Exit;
    end;
    Node := Xml.documentElement.childNodes.item[0];
    Msg := edtName[ED.EDType] + '-><EDInfo> на ' + edtName[edtED101] +
      Format(' № %s',[Node.getAttribute('EXCH_NUMBER')]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', EDInfo.EDRefID.EDDate) +
      ' Сумма: ' + Format('%.2f', [StrToCurr(Node.getAttribute('AMOUNT'))]);
    if CheckDocStatus(Node) then
    begin
      WriteInfo(Msg);
      // exchange #2545 - перехват сбоя линковки ЭД
      try
        case StrToInt(ED.StatusCode) of
          0, 9:  ExecProc('DOCUMENT', ['action', 'spawn_finish', 'class',
                Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
                'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate)],
                Node.getAttribute('BUDGET_ID'));
          4, 20:  ExecProc('DOCUMENT', ['action', 'spawn_decline', 'class',
                Node.getAttribute('DOCUMENTCLASS_ID'), 'ID', Node.getAttribute('ID'),
                'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                'REMARK', scName[StrToInt(ED.StatusCode)]], Node.getAttribute('BUDGET_ID'));
        end;
        except
          WriteLog( Msg + ' - ЭД не слинкован (игнорируемый сбой).'
                    + #13#10 + LastException.Message);
      end;
      if StrToInt(ED.StatusCode) in [0, 4, 9, 20] then
        VisualMainLoad(Node.getAttribute('DOCUMENTCLASS_ID'), Node.getAttribute('ID'));
    end;
  end; {End LoadEDInfo}
begin
  Xml := CreateOleObject('Microsoft.XmlDom');
  WriteInfo(edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
    ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDDate) +
    ' Количество: ' + Format('%d', [ED.QuantityED]) +
    ' Сумма: ' + Format('%.2f', [ED.Sum]) +
    ' - (' + scName[StrToInt(ED.StatusCode)] + ')');
  for i := 0 to ED.Count - 1 do
  begin
    LoadEDInfo(ED.EDInfo[i]);
    if ED.Count <> 1 then
    begin
      SetProgressBarMax(ED.Count);
      ShowProgress(i + 1);
    end;
  end;
end; {End LoadED207}

procedure LoadED208(ED: Variant);
begin
  WriteInfo(edtName[ED.EDType] + ' - Информация о состоянии ЭС' +
    Format(' № %d', [ED.EDNo]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDDate));
  case ED.ResultCode of
    1: Msg := '. Результат обработки - ЭД принят';
    2: Msg := '. Результат обработки - ЭД передан получателю';
    3: Msg := '. Результат обработки - ЭД не доставлен получателю, пояснение: ' +
      ED.Annotation
  else
    Msg := '';
  end;
  WriteInfo('Идентификаторы исходного ЭД: ' + Format(' № %d', [ED.EDRefID.EDNo]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDRefID.EDDate) + Msg);
end;

procedure CashierLink(Amount: Currency; Doc_Date: String; Doc: Variant; BudgetId: String);
var
  Xml: Variant;
  QueryLink: TRunQuery;
begin
  QueryLink := TRunQuery.Create;
  try
  Sql := 'Select A.Id From AssetAct A' +
    ' Where A.DocumentClass_Id = 7 And A.DispStatus_id = 1' +
    ' And A.Amount = ? And A.Carry_Date = ? And A.Budget_id = ?';
    QueryLink.AddCurr(Amount);
    QueryLink.AddDate(XmlToDateTime(Doc_Date));
    QueryLink.AddStr(BudgetId);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXml(QueryLink.Run(Sql));
  with Xml.documentElement do
  if ChildNodes.Length = 1 then
  with ChildNodes.items[0] do
  begin
    ExecProc('DOCUMENT', ['action', 'link', 'class', 7, 'ID',
      getAttribute('ID'), 'PARENT_ID', Doc.getAttribute('DOCUMENT_ID')], BudgetId);
    VisualMainLoad('24', Doc.getAttribute('ID'));
  end;
  finally
    QueryLink.Free;
  end;
end; {End CashierLink}

procedure LoadED211(ED: Variant);
var
  i: Integer;
  xBudg_ID:string;   // для Exchange #2376
  xEndTime: TDateTime;   // exchange #2696
  XmlOrgAcc: Variant;
  xXml: Variant;
  xXmlDoc: Variant;
  xFoundBudgetID: string;
  {----------------------------------------------------------------------------}
  {~DoNot_LoadTransInfo
    Формирует стандартное сообщение о документе - эд 24й не создается.
    добавлено по анализу проблемы АЦК-Ф 20608
    exchange #3051
    сообщение убрано по настоянию АО.}
  procedure DoNot_LoadTransInfo( aTransInfo: Variant; aMsg: string);
  begin

      try
      {
        WriteInfo(
            FORMAT(
               'Приходный кассовый документ № %s Дата: %s Сумма: %.2f (%s)'
              +' - не создан (значение TransKind не равно "04")',
              [ INTTOSTR( aTransInfo.EDRefID.EDNo),
                FormatDateTime('dd.mm.yyyy', aTransInfo.EDRefID.EDDate),
                aTransInfo.Sum,
                aMsg]));
                }
        except
          ExceptionProc( 'DoNot_LoadTransInfo');
      end;

  end;
  {----------------------------------------------------------------------------}
  {~DoSearchAcc_
    поиск счета вынесен отдельно.
    это сделано для #3068 чтобы не дублировать код.}
  procedure DoSearchAcc_( TransInfo: Variant);
  begin

      try
        // Поиск счёта в справочнике АЦК
        if FAccountLoginBudget then
        begin
          XmlOrgAcc := QueryXml(sqlOrgAccount + ' And B.Id = ?',
            [StrToInt(FormatDateTime('yyyy', FEDDate)), TransInfo.PayeePersonalAcc,
              Budget_Id]);
          if XmlOrgAcc.documentElement.childNodes.Length <> 1 then
          //ищем бюджет, организацию и счет по организации осущ. исполнение
          XmlOrgAcc := QueryXml(StringReplace(sqlOrgAccount, 'B.Org_Id = A.Org_Id',
            'B.Executor_id = A.Org_Id') + ' And B.Id = ?',
              [StrToInt(FormatDateTime('yyyy', FEDDate)), TransInfo.PayeePersonalAcc,
                Budget_Id]);
        end
        else begin
          XmlOrgAcc := QueryXml(sqlOrgAccount, [StrToInt(FormatDateTime('yyyy', FEDDate)),
            TransInfo.PayeePersonalAcc]);
          //ищем бюджет, организацию и счет по организации осущ. исполнение
          if XmlOrgAcc.documentElement.childNodes.Length <> 1 then
            XmlOrgAcc := QueryXml(StringReplace(sqlOrgAccount, 'B.Org_Id = A.Org_Id',
              'B.Executor_id = A.Org_Id'), [StrToInt(FormatDateTime('yyyy', FEDDate)),
                TransInfo.PayeePersonalAcc]);
        end;
        XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
        if XmlOrgAcc.length  = 0 then
          raise('Файл: ' + FileIn + ''#13#10'Счёт: ' + TransInfo.PayeePersonalAcc +
            ' не найден в базе АЦК' + ''#13#10'ЭД: ' + TransInfo.XMLText);
        if XmlOrgAcc.length  > 1 then
          raise('Файл: ' + FileIn + ''#13#10'Счёт: ' + TransInfo.PayeePersonalAcc +
            ' в базе АЦК не однозначен' + ''#13#10'ЭД: ' + TransInfo.XMLText);
        XmlOrgAcc := XmlOrgAcc.items[0];
        except
          ExceptionProc( 'DoSearchAcc_');
      end;

  end;
  {----------------------------------------------------------------------------}
  {~DoSearchAcc_2477_
    поиск счета вынесен отдельно.
    это сделано для #3068 чтобы не дублировать код.}
  procedure DoSearchAcc_2477_( TransInfo: Variant; aBudgetID: string);
  begin

      try
        // Поиск счёта в справочнике АЦК
        XmlOrgAcc := QueryXml( sqlOrgAccount + ' And B.Id = ?',
                                [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                  TransInfo.PayeePersonalAcc,
                                  aBudgetID]);

    {отладка
    writelog( '------------LoadTransInfo_2477:запрос1');
    writelog( 'ЗАПРОС='+sqlOrgAccount + ' And B.Id = ?');
    writelog( 'дата='+FormatDateTime('yyyy', FEDDate));
    writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
    writelog( 'aBudgetID='+aBudgetID);
    writelog( 'Результат='+XmlOrgAcc.xml);
    {отладка_конец}

        // если не нашли - ищем бюджет, организацию и счет по организации
        // осущ. исполнение
        if XmlOrgAcc.documentElement.childNodes.Length <> 1
          then XmlOrgAcc := QueryXml( StringReplace(
                                          sqlOrgAccount,
                                          'B.Org_Id = A.Org_Id',
                                          'B.Executor_id = A.Org_Id')
                                        + ' And B.Id = ?',
                                      [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                        TransInfo.PayeePersonalAcc,
                                        aBudgetID]);

    {отладка
    writelog( '------------LoadTransInfo_2477:запрос2');
    writelog( 'ЗАПРОС='+StringReplace( sqlOrgAccount,
                                          'B.Org_Id = A.Org_Id',
                                          'B.Executor_id = A.Org_Id')
                                        + ' And B.Id = ?');
    writelog( 'дата='+FormatDateTime('yyyy', FEDDate));
    writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
    writelog( 'aBudgetID='+aBudgetID);
    writelog( 'Результат='+XmlOrgAcc.xml);
    {отладка_конец}

        XmlOrgAcc := XmlOrgAcc.documentElement.childNodes;
        if XmlOrgAcc.length  = 0
          then raise( 'Файл: ' + FileIn + ''#13#10'Счёт: ' + TransInfo.PayeePersonalAcc
                      + ' не найден в базе АЦК' + ''#13#10'ЭД: ' + TransInfo.XMLText);
        if XmlOrgAcc.length  > 1
          then raise( 'Файл: ' + FileIn + ''#13#10'Счёт: ' + TransInfo.PayeePersonalAcc
                      + ' в базе АЦК не однозначен' + ''#13#10'ЭД: ' + TransInfo.XMLText);
        XmlOrgAcc := XmlOrgAcc.items[0];
        except
          ExceptionProc( 'DoSearchAcc_2477_');
      end;

  end;
  {----------------------------------------------------------------------------}
  procedure LoadTransInfo(TransInfo: Variant);
  var
    XmlLink: Variant;
  begin

      try
        // Формирует стандартное сообщение о документе
        Msg := edtName[ED.EDType] + ' - Приходный кассовый документ, обьявление на ' +
          'взнос наличными' + Format(' № %d', [TransInfo.EDRefID.EDNo]) +
          ' Дата: ' + FormatDateTime('dd.mm.yyyy', TransInfo.EDRefID.EDDate) +
          ' Сумма: ' + Format('%.2f', [TransInfo.Sum]);
        StatusBarSimpleText(Msg);

        // Поиск счёта в справочнике АЦК
        DoSearchAcc_( TransInfo);

    {отладка
    if FAccountLoginBudget
      then showmessage('(LoadTransInfo) FAccountLoginBudget=TRUE')
      else showmessage('(LoadTransInfo) FAccountLoginBudget=FALSE');
    {отладка_конец}

        // Проверяем условие фильтра по бюджету в настройках и бюджета, к которому относиться счёт
        if FiltrBudget and (XmlOrgAcc.getAttribute('BUDGET_ID') <> Budget_Id) then
          raise('В настройках установлен фильтр по бюджету' + #13+#10 +
            'Текущий бюджет: ' + Budget_Name + #13+#10 +
            'Документ принадлежит бюджету: ' + XmlOrgAcc.getAttribute('BUDGET_NAME'));
        // Проверка на повторную загрузку ЭД
        Foreign_Key := FormatDateTime('yyyymmdd', TransInfo.EDRefID.EDDate) +
          TransInfo.EDRefID.EDAuthor + IntToStr(TransInfo.EDRefID.EDNo);
        Sql := 'Select P.Id From PayOrder P Where P.DocumentClass_Id = 24' +
          ' And P.Foreign_Key = ? And P.DispStatus_Id > -1';
        Xml:= QueryXml(Sql, [Foreign_Key], False);
        if Xml.documentElement.childNodes.length > 0 then
        begin
          WriteInfo(Msg + ' - был ранее загружен', True);
          Exit;
        end;
        Xml := CreateOleObject('Microsoft.XmlDom');
        Xml := Xml.appendChild(Xml.createElement('DOCUMENT'));
        Xml.setAttribute('action', 'insert');
        Xml.setAttribute('class', '24');
        Xml.setAttribute('DOC_DATE', FormatDateTime('yyyy-mm-dd', ED.EDDate));
        Xml.setAttribute('CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate));
        Xml.setAttribute('AMOUNT', TransInfo.Sum);
        Xml.setAttribute('REC_ID', XmlOrgAcc.getAttribute('ORG_ID'));
        Xml.setAttribute('REC_NAME', XmlOrgAcc.getAttribute('DESCRIPTION'));
        Xml.setAttribute('REC_KPP', XmlOrgAcc.getAttribute('KPP'));
        Xml.setAttribute('REC_ACC_ID', XmlOrgAcc.getAttribute('ID'));

        // exchange #2547 - вид платежа
        // теперь если берется из документа - пусто, либо то, что указано в конфиге
        Xml.setAttribute('PAYKIND', ImpPayKind_2547);
        //Xml.setAttribute('PAYKIND', 1);

        Xml.setAttribute('DOC_NUMBER', IfThen(Trim(TransInfo.AccDocNo) = '', TransInfo.CashDocNo, TransInfo.AccDocNo));
        Xml.setAttribute('FOREIGN_KEY', Foreign_Key);
        Xml.setAttribute('BANKOPER_ID', 4);
        Xml.setAttribute('PAY_BIC', TransInfo.BICCorr);
        Xml.setAttribute('PAY_ACCOUNT', TransInfo.PayerPersonalAcc);
        Xml.setAttribute('REC_BIC', TransInfo.BICCorr);
        Xml.setAttribute('REC_ACCOUNT', TransInfo.PayeePersonalAcc);
        Xml.setAttribute('DESCRIPTION', 'Обьявление на взнос наличными' +
          ', приходный кассовый ордер');


        Xml.ownerDocument.loadXML(ExecXML(Xml.ownerDocument.xml,
          XmlOrgAcc.getAttribute('BUDGET_ID')));
        WriteLog(Msg);
        with Xml.ownerDocument.documentElement do
        begin

          ExecProc( 'DOCUMENT',
                    [ 'action', 'process',
                      'class', getAttribute('DOCUMENTCLASS_ID'),
                      'ID', getAttribute('ID')],
                    XmlOrgAcc.getAttribute('BUDGET_ID'));
          VisualMainLoad( getAttribute('DOCUMENTCLASS_ID'), getAttribute('ID'));
          // exchange #2613
          // здесь сумма указывается вещественным числом,
          // как в ED211. поэтому преобразование из строки
          // не нужно - эта функция дает сбой при разных
          // разделителях!
          //CashierLink(StrToCurr(TransInfo.Sum),
          CashierLink( TransInfo.Sum,
                       FormatDateTime('yyyy-mm-dd', FEDDate),
                       Xml.ownerDocument.documentElement,
                       XmlOrgAcc.getAttribute('BUDGET_ID'));
        end;
        if FED211OperType = '' then
          Exit;

        XmlLink := CreateOleObject('Microsoft.XmlDom');
        XmlLink.LoadXml(Xml.xml);
        XmlLink.documentElement.setAttribute('class', 7);
        XmlLink.documentElement.setAttribute('OPERTYPE_ID', FED211OperType);
        XmlLink.documentElement.setAttribute('AUTHOR_ID', 1);
        XmlLink.loadXML(ExecXML(XmlLink.xml));
        with XmlLink.documentElement do
        begin
          ExecProc('DOCUMENT', ['action', 'execute', 'class',
            getAttribute('DOCUMENTCLASS_ID'), 'ID', getAttribute('ID')],
            XmlOrgAcc.getAttribute('BUDGET_ID'));
          ExecProc('DOCUMENT', ['action', 'link', 'class',
            getAttribute('DOCUMENTCLASS_ID'), 'ID', getAttribute('ID'),
            'PARENT_ID', Xml.ownerDocument.documentElement.getAttribute('DOCUMENT_ID')],
            XmlOrgAcc.getAttribute('BUDGET_ID'));
        end;
        with Xml.ownerDocument.documentElement do
          VisualMainLoad(getAttribute('DOCUMENTCLASS_ID'), getAttribute('ID'))
        except
          ExceptionLog( 'Сбой LoadED211.LoadTransInfo');
      end;

  end;
  {----------------------------------------------------------------------------}
  // exchange #2477
  // здесь бюджет уже известен и счет определяем только для этого бюджета!
  procedure LoadTransInfo_2477( TransInfo: Variant; aBudgetID: string);
  var
    XmlLink: Variant;
  begin

      try
        // Формирует стандартное сообщение о документе
        Msg := edtName[ED.EDType] + ' - Приходный кассовый документ, обьявление на ' +
          'взнос наличными' + Format(' № %d', [TransInfo.EDRefID.EDNo]) +
          ' Дата: ' + FormatDateTime('dd.mm.yyyy', TransInfo.EDRefID.EDDate) +
          ' Сумма: ' + Format('%.2f', [TransInfo.Sum]);
        StatusBarSimpleText(Msg);

        DoSearchAcc_2477_( TransInfo, aBudgetID);

        // Проверка на повторную загрузку ЭД
        Foreign_Key := FormatDateTime( 'yyyymmdd', TransInfo.EDRefID.EDDate)
                        + TransInfo.EDRefID.EDAuthor
                        + IntToStr(TransInfo.EDRefID.EDNo);
        Sql := 'Select P.Id From PayOrder P Where P.DocumentClass_Id = 24' +
          ' And P.Foreign_Key = ? And P.DispStatus_Id > -1';
        Xml:= QueryXml(Sql, [Foreign_Key], False);
        if Xml.documentElement.childNodes.length > 0 then begin
          WriteInfo(Msg + ' - был ранее загружен', True);
          Exit;
        end;

        Xml := CreateOleObject('Microsoft.XmlDom');
        Xml := Xml.appendChild(Xml.createElement('DOCUMENT'));
        Xml.setAttribute('action', 'insert');
        Xml.setAttribute('class', '24');
        Xml.setAttribute('DOC_DATE', FormatDateTime('yyyy-mm-dd', ED.EDDate));
        Xml.setAttribute('CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate));
        Xml.setAttribute('AMOUNT', TransInfo.Sum);
        Xml.setAttribute('REC_ID', XmlOrgAcc.getAttribute('ORG_ID'));
        Xml.setAttribute('REC_NAME', XmlOrgAcc.getAttribute('DESCRIPTION'));
        Xml.setAttribute('REC_KPP', XmlOrgAcc.getAttribute('KPP'));
        Xml.setAttribute('REC_ACC_ID', XmlOrgAcc.getAttribute('ID'));

        // exchange #2547 - вид платежа
        // теперь если берется из документа - пусто, либо то, что указано в конфиге
        Xml.setAttribute('PAYKIND', ImpPayKind_2547);
        //Xml.setAttribute('PAYKIND', 1);

        Xml.setAttribute('DOC_NUMBER', IfThen(Trim(TransInfo.AccDocNo) = '', TransInfo.CashDocNo, TransInfo.AccDocNo));
        Xml.setAttribute('FOREIGN_KEY', Foreign_Key);
        Xml.setAttribute('BANKOPER_ID', 4);
        Xml.setAttribute('PAY_BIC', TransInfo.BICCorr);
        Xml.setAttribute('PAY_ACCOUNT', TransInfo.PayerPersonalAcc);
        Xml.setAttribute('REC_BIC', TransInfo.BICCorr);
        Xml.setAttribute('REC_ACCOUNT', TransInfo.PayeePersonalAcc);
        Xml.setAttribute('DESCRIPTION', 'Обьявление на взнос наличными' +
          ', приходный кассовый ордер');


        Xml.ownerDocument.loadXML( ExecXML(Xml.ownerDocument.xml,
                                   XmlOrgAcc.getAttribute('BUDGET_ID')));
        WriteLog(Msg);


        with Xml.ownerDocument.documentElement do begin
          ExecProc( 'DOCUMENT',
                    [ 'action', 'process',
                      'class', getAttribute('DOCUMENTCLASS_ID'),
                      'ID', getAttribute('ID')],
                      XmlOrgAcc.getAttribute('BUDGET_ID'));
          VisualMainLoad( getAttribute('DOCUMENTCLASS_ID'), getAttribute('ID'));
          // exchange #2613
          // здесь сумма указывается вещественным числом,
          // как в ED211. поэтому преобразование из строки
          // не нужно - эта функция дает сбой при разных
          // разделителях!
          //CashierLink(StrToCurr(TransInfo.Sum),
          CashierLink( TransInfo.Sum,
                       FormatDateTime('yyyy-mm-dd', FEDDate),
                       Xml.ownerDocument.documentElement,
                       XmlOrgAcc.getAttribute('BUDGET_ID'));
        end;
        if FED211OperType = '' then
          Exit;

        XmlLink := CreateOleObject('Microsoft.XmlDom');
        XmlLink.LoadXml(Xml.xml);
        XmlLink.documentElement.setAttribute('class', 7);
        XmlLink.documentElement.setAttribute('OPERTYPE_ID', FED211OperType);
        XmlLink.documentElement.setAttribute('AUTHOR_ID', 1);
        XmlLink.loadXML(ExecXML(XmlLink.xml));
        with XmlLink.documentElement do
        begin
          ExecProc('DOCUMENT', ['action', 'execute', 'class',
            getAttribute('DOCUMENTCLASS_ID'), 'ID', getAttribute('ID')],
            XmlOrgAcc.getAttribute('BUDGET_ID'));
          ExecProc('DOCUMENT', ['action', 'link', 'class',
            getAttribute('DOCUMENTCLASS_ID'), 'ID', getAttribute('ID'),
            'PARENT_ID', Xml.ownerDocument.documentElement.getAttribute('DOCUMENT_ID')],
            XmlOrgAcc.getAttribute('BUDGET_ID'));
        end;
        with Xml.ownerDocument.documentElement do
          VisualMainLoad(getAttribute('DOCUMENTCLASS_ID'), getAttribute('ID'))
        except
          ExceptionLog( 'Сбой LoadED211.LoadTransInfo_2477');
      end;

  end;
  {----------------------------------------------------------------------------}
  {~SubQueryExch2812
    Учесть, что если в ED211 выписки счет получателя (PayeePersonalAcc)
    имеет маску «30101» (первые пять символов значения), то в ЭД класса 13
    поле «Счет» блока Получатель может иметь пустое значение.

    функция возвращает подзапрос:
      (P.Rec_Account = ? or P.Rec_Account = '' or P.Rec_Account is null)
        если aTransInfo.PayeePersonalAcc начинается с «30101».
        в этом случае пп ищется либо с пустым, либо с указанным счетом.
        поскольку в некоторых бд пустые строки заменяются на null,
        то проверяем и такую возможность.

      P.Rec_Account = ?
        если aTransInfo.PayeePersonalAcc не начинается с «30101».
        в этом случае пп ищется только с указанным счетом.}
  function SubQueryExch2812( aTransInfo_PayeePersonalAcc: string): string;
  begin

      try
        if ( POS( '30101', aTransInfo_PayeePersonalAcc) = 1)
          then Result := '(P.Rec_Account = ? or P.Rec_Account = '#39#39' or P.Rec_Account is null)'
          else Result := 'P.Rec_Account = ?';

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

  end;
  {----------------------------------------------------------------------------}
  //ищет ранее выгруженную пп и линкует ее с (старый вариант)
  procedure LoadAnswerTransInfo(TransInfo: Variant);
  var
    RequiredDoc: Variant;
    xSqlBudgetLimit: string;
//    xXmlResult: Variant;
  begin

      try
    {отладка
    showmessage('step1');
    {отладка_конец}

        Msg := 'Неподтвержденный дебет по ED211' +
          ' Сумма: ' + Format('%.2f', [TransInfo.Sum]);
        WriteLog(Msg, True);

        // exchange #2587
        // добавлен прилогиненный бюджет, если включена соответствующая настройка
        if FAccountLoginBudget
          then xSqlBudgetLimit := ' and P.Budget_Id=? '
          else xSqlBudgetLimit := '';

        // Поиск ЭД в базе, выгруженного по формату ФК
        Sql := 'Select P.Id, P.Amount, P.DocumentClass_Id, P.DispStatus_Id, P.ExtStatus_Id' +
          ', D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore, P.Budget_Id' +
          ', E.Exch_Number, P.Doc_Number, P.Doc_Date' +
          ' From Exch_Document E' +
          ' Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
          ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
          ' Where P.DocumentClass_Id = 13 And P.Dispstatus_Id = 16 '
          // exchange #2587
         +xSqlBudgetLimit
          // Exchange #2345 параметр суммы добавлен непосредственно в строку
          // запроса вместо указания как параметра в QueryXml.
         +' And P.ExtStatus_Id = 1 And P.Amount = ' + Format('%.2f', [TransInfo.Sum])
         // exchange #2812 - поиск счета с возможным пустым значением
         +' And ' + SubQueryExch2812( TransInfo.PayeePersonalAcc) //P.Rec_Account = ? '
         +' And E.Exch_Name = ''PP'''
         // exchange #2538 - добавлен признак, что ЭД выгружен, но не восстановлен
         +' and e.exch_restore=0';

    {отладка
    if NOT vCfgPayerAccountConsider then begin
      writelog( 'sql='+sql);
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
    end else begin
      writelog( 'sql='+sql + ' And P.Pay_Account = ?');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'TransInfo.PayerPersonalAcc='+TransInfo.PayerPersonalAcc);
    end;
    {отладка_конец}

        { exchange #2538
          если параметр "Учитывать счет Плательщика" имеет значение "Да",
          то в условия поиска ПП (п.4 текущего алгоритма) необходимо добавить
          сравнение номера счета Плательщика.
          Сравнивать значение поля «Счет плательщика» (PAY_ACCOUNT) ПП (13)
          со значением поля «Счет плательшика» (PAY_ACCOUNT)  ПкВД (5)
          если параметр "Учитывать счет Плательщика" имеет значение "Нет" -
          стандартный алгоритм (поиск только по Сумме ЭПД и номеру счета Получателя).
          p.s.
          Счет плательшика берется из TransInfo.PayerPersonalAcc - Счет отправителя/
          плательщика - согласовано с АО.
        exchange #2587
         добавлен прилогиненный бюджет, если включена соответствующая настройка.}
        if FAccountLoginBudget then begin
          if NOT vCfgPayerAccountConsider
            then RequiredDoc := QueryXml( Sql,
                                          [ Budget_Id,
                                            TransInfo.PayeePersonalAcc])
            else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?',
                                          [ Budget_Id,
                                            TransInfo.PayeePersonalAcc,
                                            TransInfo.PayerPersonalAcc])
        end else begin
          if NOT vCfgPayerAccountConsider
            then RequiredDoc := QueryXml( Sql,
                                          [ TransInfo.PayeePersonalAcc])
            else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?',
                                          [ TransInfo.PayeePersonalAcc,
                                            TransInfo.PayerPersonalAcc]);
        end;
    //    RequiredDoc := QueryXml(Sql, [TransInfo.PayeePersonalAcc]);

    {отладка
    writelog( 'результат='+RequiredDoc.documentElement.xml);
    //showmessage('ok');
    //exit;
    {отладка_конец}

        if RequiredDoc.documentElement.ChildNodes.length <> 1 then begin
          { exchange #2538
            если однозначно ЭД ПП не нашли, пробуем выполнить поиск еще раз,
            но добавив фильтр: сравнивать последние три цифры номера ПП (13)
            с номером ПкВД (5), где "номером ПкВД (5)" можно брать из поля
            TransInfo: Номер расчетного документа (AccDocNo) - согласовано с АО.
            поиск выполняем только в случае, если первый запрос вернул несколько ЭД.}
          if (RequiredDoc.documentElement.ChildNodes.length > 1) then begin
            {exchange #2587
             добавлен прилогиненный бюджет, если включена соответствующая настройка.}
            if FAccountLoginBudget then begin
              if NOT vCfgPayerAccountConsider
                then RequiredDoc := QueryXml( Sql + ' and (trim(P.Doc_Number) like '#39'%'
                                                  + TransInfo.AccDocNo + #39')',
                                              [ Budget_Id,
                                                TransInfo.PayeePersonalAcc])
                else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?'
                                                  + ' and (trim(P.Doc_Number) like '#39'%'
                                                  + TransInfo.AccDocNo + #39')',
                                              [ Budget_Id,
                                                TransInfo.PayeePersonalAcc,
                                                TransInfo.PayerPersonalAcc]);
            end else begin
              if NOT vCfgPayerAccountConsider
                then RequiredDoc := QueryXml( Sql + ' and (trim(P.Doc_Number) like '#39'%'
                                                  + TransInfo.AccDocNo + #39')',
                                              [ TransInfo.PayeePersonalAcc])
                else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?'
                                                  + ' and (trim(P.Doc_Number) like '#39'%'
                                                  + TransInfo.AccDocNo + #39')',
                                              [ TransInfo.PayeePersonalAcc,
                                                TransInfo.PayerPersonalAcc]);
            end;
    {отладка
    if NOT vCfgPayerAccountConsider then begin
      writelog( 'sql='+sql + ' and (trim(P.Doc_Number) like '#39'%'
                           + TransInfo.AccDocNo + #39')');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
    end else begin
      writelog( 'sql='+sql + ' And P.Pay_Account = ?'
                           + ' and (trim(P.Doc_Number) like '#39'%'
                           + TransInfo.AccDocNo + #39')');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'TransInfo.PayerPersonalAcc='+TransInfo.PayerPersonalAcc);
    end;
    writelog( 'результат='+RequiredDoc.documentElement.xml);
    {отладка_конец}

            if RequiredDoc.documentElement.ChildNodes.length <> 1 then begin
              {exchange #2587
               добавлен прилогиненный бюджет, если включена соответствующая настройка.}
              if FAccountLoginBudget then begin
                if NOT vCfgPayerAccountConsider
                  then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                         +'суммой %s и номером ЭД, оканчивающимся на %s, не найден в базе в прилогиненном бюджете',
                                          [ TransInfo.PayeePersonalAcc,
                                            Format('%.2f', [TransInfo.Sum]),
                                            TransInfo.AccDocNo]))
                  else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                         +'суммой %s и номером ЭД, оканчивающимся на %s, не найден в базе в прилогиненном бюджете',
                                          [ TransInfo.PayeePersonalAcc,
                                            TransInfo.PayerPersonalAcc,
                                            Format('%.2f', [TransInfo.Sum]),
                                            TransInfo.AccDocNo]));
              end else begin
                if NOT vCfgPayerAccountConsider
                  then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                         +'суммой %s и номером ЭД, оканчивающимся на %s, не найден в базе',
                                          [ TransInfo.PayeePersonalAcc,
                                            Format('%.2f', [TransInfo.Sum]),
                                            TransInfo.AccDocNo]))
                  else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                         +'суммой %s и номером ЭД, оканчивающимся на %s, не найден в базе',
                                          [ TransInfo.PayeePersonalAcc,
                                            TransInfo.PayerPersonalAcc,
                                            Format('%.2f', [TransInfo.Sum]),
                                            TransInfo.AccDocNo]));
              end;
              Exit;
            end;
          end else begin
            {exchange #2587
             добавлен прилогиненный бюджет, если включена соответствующая настройка.}
            if FAccountLoginBudget then begin
              // сообщение без учета запроса номера ЭД, когда не найдено ни одного ЭД
              if NOT vCfgPayerAccountConsider
                then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                       +'и суммой %s не найден в базе в прилогиненном бюджете',
                                        [ TransInfo.PayeePersonalAcc,
                                          Format('%.2f', [TransInfo.Sum])]))
                else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                       +'и суммой %s не найден в базе в прилогиненном бюджете',
                                        [ TransInfo.PayeePersonalAcc,
                                          TransInfo.PayerPersonalAcc,
                                          Format('%.2f', [TransInfo.Sum])]));
            end else begin
              // сообщение без учета запроса номера ЭД, когда не найдено ни одного ЭД
              if NOT vCfgPayerAccountConsider
                then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                       +'и суммой %s не найден в базе',
                                        [ TransInfo.PayeePersonalAcc,
                                          Format('%.2f', [TransInfo.Sum])]))
                else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                       +'и суммой %s не найден в базе',
                                        [ TransInfo.PayeePersonalAcc,
                                          TransInfo.PayerPersonalAcc,
                                          Format('%.2f', [TransInfo.Sum])]));
            end;
            Exit;
          end;
        end;
    {

          WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s и суммой %s не найден в базе',
                              [ TransInfo.PayeePersonalAcc,
                                Format('%.2f', [TransInfo.Sum])]));
          Exit;
        end;}

        RequiredDoc := RequiredDoc.documentElement.childNodes.item[0];
        Msg := edtName[ED.EDType] + Format(' № %d',[ED.EDNo]) +
          ' на ' + edtName[edtED101] +
          Format(' № %s',[Trim(RequiredDoc.getAttribute('DOC_NUMBER'))]) +
          ' Дата: ' + FormatDateTime('dd.mm.yyyy',
          XmlToDateTime(RequiredDoc.getAttribute('DOC_DATE'))) +
          ' Сумма: ' + Format('%.2f', [StrToCurr(RequiredDoc.getAttribute('AMOUNT'))]);


    {отладка
    writelog( 'RequiredDoc:'#13#10+RequiredDoc.xml);
    {отладка_конец}

        if CheckDocStatus(RequiredDoc) then
        begin
          // exchange #2503
          // возможно сбой возникает в этом месте. поэтому обрамляем его в
          // try-except и продолжаем работу, сообщив что ЭД не слинкован.
          // можно перехватить конкретную ошибку (729), но надо ли это?
          try
    //        xXmlResult := CreateOleObject('Microsoft.XmlDom');
    //        xXmlResult.LoadXml(
              ExecProc('DOCUMENT', ['action', 'spawn_finish', 'class',
                        RequiredDoc.getAttribute('DOCUMENTCLASS_ID'), 'ID',
                        RequiredDoc.getAttribute('ID'),
                        'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
                        'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate)],
                        RequiredDoc.getAttribute('BUDGET_ID'));
    {        xXmlResult := xXmlResult.documentElement;
            if (xXmlResult.NodeName = 'ERROR') then
              if (xXmlResult.GetAttribute('code') = '729')
                then WriteLog(Msg + ' - ЭД не слинкован (729)')
                else WriteLog(Msg + ' - ЭД не слинкован (')}
            WriteLog(Msg + ' - ЭД слинкован');
            except
              WriteInfo( Msg + ' - ЭД не слинкован (игнорируемый сбой).'
                        + #13#10 + LastException.Message);
          end;
          // exchange #2503
          // при линковке сбоя не проявилось
          // перехват сбоя в этом кода
          try
            VisualMainLoad(RequiredDoc.getAttribute('DOCUMENTCLASS_ID'), RequiredDoc.getAttribute('ID'));
            except
              WriteInfo( Msg + ' - ошибка операции VisualMainLoad'
                        + #13#10 + LastException.Message);
          end;
        end;

        except
          ExceptionLog( 'Сбой LoadED211.LoadAnswerTransInfo');
      end;

  end;
  {----------------------------------------------------------------------------}
  //ищет ранее выгруженную пп и линкует ее с
  // изменения exchange #2376
  procedure LoadAnswerTransInfo_2376(TransInfo: Variant; aBudg_ID_FO: string);
  var
    RequiredDoc: Variant;
  begin

      try
        Msg := 'Неподтвержденный дебет по ED211' +
          ' Сумма: ' + Format('%.2f', [TransInfo.Sum])
          + FORMAT( ' по бюджету %s', [ aBudg_ID_FO]);
        WriteLog(Msg, True);
        // Поиск ЭД в базе, выгруженного по формату ФК
        Sql := 'Select P.Id, P.Amount, P.DocumentClass_Id, P.DispStatus_Id, P.ExtStatus_Id' +
          ', D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore, P.Budget_Id' +
          ', E.Exch_Number, P.Doc_Number, P.Doc_Date' +
          ' From Exch_Document E' +
          ' Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
          ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
          ' Where P.DocumentClass_Id = 13 And P.Dispstatus_Id = 16 ' +
          // Exchange #2345 параметр суммы добавлен непосредственно в строку
          // запроса вместо указания как параметра в QueryXml.
          '   And P.ExtStatus_Id = 1 And P.Amount = ' + Format('%.2f', [TransInfo.Sum])
         // exchange #2812 - поиск счета с возможным пустым значением
         +' And ' + SubQueryExch2812( TransInfo.PayeePersonalAcc) //P.Rec_Account = ? '
         +' And E.Exch_Name = ''PP'''
         // exchange #2376 - добавлен указанный бюджет
         +' and P.Budget_Id=? '
         // exchange #2538 - добавлен признак, что ЭД выгружен, но не восстановлен
         +' and e.exch_restore=0';
    {
        RequiredDoc := QueryXml(Sql, [TransInfo.PayeePersonalAcc, aBudg_ID_FO]);

        if RequiredDoc.documentElement.ChildNodes.length <> 1 then
        begin
          WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s и суммой %s (по бюджету %s) не найден в базе',
                              [ TransInfo.PayeePersonalAcc,
                                Format('%.2f', [TransInfo.Sum]),
                                aBudg_ID_FO]));
          Exit;
        end;
    }
    {отладка
    if NOT vCfgPayerAccountConsider then begin
      writelog( 'sql='+sql);
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'Бюджет='+aBudg_ID_FO);
    end else begin
      writelog( 'sql='+sql + ' And P.Pay_Account = ?');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'TransInfo.PayerPersonalAcc='+TransInfo.PayerPersonalAcc);
      writelog( 'Бюджет='+aBudg_ID_FO);
    end;
    {отладка_конец}


        { exchange #2538
          если параметр "Учитывать счет Плательщика" имеет значение "Да",
          то в условия поиска ПП (п.4 текущего алгоритма) необходимо добавить
          сравнение номера счета Плательщика.
          Сравнивать значение поля «Счет плательщика» (PAY_ACCOUNT) ПП (13)
          со значением поля «Счет плательшика» (PAY_ACCOUNT)  ПкВД (5)
          если параметр "Учитывать счет Плательщика" имеет значение "Нет" -
          стандартный алгоритм (поиск только по Сумме ЭПД и номеру счета Получателя).
          p.s.
          Счет плательшика берется из TransInfo.PayerPersonalAcc - Счет отправителя/
          плательщика - согласовано с АО.}
        if NOT vCfgPayerAccountConsider
          then RequiredDoc := QueryXml( Sql,
                                        [ TransInfo.PayeePersonalAcc,
                                          aBudg_ID_FO])
          else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?',
                                        [ TransInfo.PayeePersonalAcc,
                                          aBudg_ID_FO,
                                          TransInfo.PayerPersonalAcc]);

    {отладка
    writelog( 'результат='+RequiredDoc.documentElement.xml);
    //showmessage('ok');
    //exit;
    {отладка_конец}

        if RequiredDoc.documentElement.ChildNodes.length <> 1 then begin
          { exchange #2538
            если однозначно ЭД ПП не нашли, пробуем выполнить поиск еще раз,
            но добавив фильтр: сравнивать последние три цифры номера ПП (13)
            с номером ПкВД (5), где "номером ПкВД (5)" можно брать из поля
            TransInfo: Номер расчетного документа (AccDocNo) - согласовано с АО.
            поиск выполняем только в случае, если первый запрос вернул несколько ЭД.}
          if (RequiredDoc.documentElement.ChildNodes.length > 1) then begin
            if NOT vCfgPayerAccountConsider
              then RequiredDoc := QueryXml( Sql + ' and (trim(P.Doc_Number) like '#39'%'
                                                + TransInfo.AccDocNo + #39')',
                                            [ TransInfo.PayeePersonalAcc,
                                              aBudg_ID_FO])
              else RequiredDoc := QueryXml( Sql + ' And P.Pay_Account = ?'
                                                + ' and (trim(P.Doc_Number) like '#39'%'
                                                + TransInfo.AccDocNo + #39')',
                                            [ TransInfo.PayeePersonalAcc,
                                              aBudg_ID_FO,
                                              TransInfo.PayerPersonalAcc]);

    {отладка
    if NOT vCfgPayerAccountConsider then begin
      writelog( 'sql='+sql + ' and (trim(P.Doc_Number) like '#39'%'
                           + TransInfo.AccDocNo + #39')');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'Бюджет='+aBudg_ID_FO);
    end else begin
      writelog( 'sql='+sql + ' And P.Pay_Account = ?'
                           + ' and (trim(P.Doc_Number) like '#39'%'
                           + TransInfo.AccDocNo + #39')');
      writelog( 'TransInfo.PayeePersonalAcc='+TransInfo.PayeePersonalAcc);
      writelog( 'TransInfo.PayerPersonalAcc='+TransInfo.PayerPersonalAcc);
      writelog( 'Бюджет='+aBudg_ID_FO);
    end;
    writelog( 'результат='+RequiredDoc.documentElement.xml);
    {отладка_конец}

            if RequiredDoc.documentElement.ChildNodes.length <> 1 then begin
              if NOT vCfgPayerAccountConsider
                then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                       +'суммой %s и номером ЭД, оканчивающимся на %s, '
                                       +'(по бюджету %s) не найден в базе',
                                        [ TransInfo.PayeePersonalAcc,
                                          Format('%.2f', [TransInfo.Sum]),
                                          TransInfo.AccDocNo,
                                          aBudg_ID_FO]))
                else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                       +'суммой %s и номером ЭД, оканчивающимся на %s, '
                                       +'(по бюджету %s) не найден в базе',
                                        [ TransInfo.PayeePersonalAcc,
                                          TransInfo.PayerPersonalAcc,
                                          Format('%.2f', [TransInfo.Sum]),
                                          TransInfo.AccDocNo,
                                          aBudg_ID_FO]));
              EXIT;
            end;
          end else begin
            // сообщение без учета запроса номера ЭД, когда не найдено ни одного ЭД
            if NOT vCfgPayerAccountConsider
              then WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s, '
                                     +'суммой %s (по бюджету %s) не найден в базе',
                                      [ TransInfo.PayeePersonalAcc,
                                        Format('%.2f', [TransInfo.Sum]),
                                        aBudg_ID_FO]))
              else WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s (и счетом плательщика № %s), '
                                     +'суммой %s (по бюджету %s) не найден в базе',
                                      [ TransInfo.PayeePersonalAcc,
                                        TransInfo.PayerPersonalAcc,
                                        Format('%.2f', [TransInfo.Sum]),
                                        aBudg_ID_FO]));
            Exit;
          end;
    {
          WriteInfo( FORMAT( 'ЭД Платежное поручение cо счетом № %s и суммой %s (по бюджету %s) не найден в базе',
                              [ TransInfo.PayeePersonalAcc,
                                Format('%.2f', [TransInfo.Sum]),
                                aBudg_ID_FO]));
          Exit;
          }
        end;

        RequiredDoc := RequiredDoc.documentElement.childNodes.item[0];
        Msg := edtName[ED.EDType] + Format(' № %d',[ED.EDNo]) +
          ' на ' + edtName[edtED101] +
          Format(' № %s',[Trim(RequiredDoc.getAttribute('DOC_NUMBER'))]) +
          ' Дата: ' + FormatDateTime('dd.mm.yyyy',
          XmlToDateTime(RequiredDoc.getAttribute('DOC_DATE'))) +
          ' Сумма: ' + Format('%.2f', [StrToCurr(RequiredDoc.getAttribute('AMOUNT'))]);

    {отладка
    writelog( 'RequiredDoc:'#13#10+RequiredDoc.xml);
    {отладка_конец}

        if CheckDocStatus(RequiredDoc) then
        begin
          // exchange #2503
          // возможно сбой возникает в этом месте. поэтому обрамляем его в
          // try-except и продолжаем работу, сообщив что ЭД не слинкован.
          try
            ExecProc('DOCUMENT', ['action', 'spawn_finish', 'class',
              RequiredDoc.getAttribute('DOCUMENTCLASS_ID'), 'ID',
              RequiredDoc.getAttribute('ID'),
              'BANK_DATE', FormatDateTime('yyyy-mm-dd', FEDDate),
              'CARRY_DATE', FormatDateTime('yyyy-mm-dd', FEDDate)],
              RequiredDoc.getAttribute('BUDGET_ID'));
            WriteLog(Msg + ' - ЭД слинкован');
            except
              WriteInfo( Msg + ' - ЭД не слинкован (игнорируемый сбой).'
                        + #13#10 + LastException.Message);
          end;
          // exchange #2503
          // при линковке сбоя не проявилось
          // перехват сбоя в этом кода
          try
            VisualMainLoad(RequiredDoc.getAttribute('DOCUMENTCLASS_ID'), RequiredDoc.getAttribute('ID'));
            except
              WriteInfo( Msg + ' - ошибка операции VisualMainLoad'
                        + #13#10 + LastException.Message);
          end;
        end;
        except
          ExceptionLog( 'Сбой LoadED211.LoadAnswerTransInfo_2376');
      end;

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

    try
      // exchange #2696
      // получаем время из ED с учетом настройки использования UTC.
      // для схем меньше 2.6.0 параметр не проверяется и всегда берется время
      // как раньше.
      if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') < 0)
        then xEndTime := ED.EndTime
        else
      if vCfgConvertTimeToUTC
        then xEndTime := ED.EndTimeLocal
        else xEndTime := ED.EndTime;

      WriteLog(edtName[ED.EDType] + ' Дата ' + FormatDateTime('dd.mm.yyyy', ED.AbstractDate) +
        ' Время ' + FormatDateTime('hh.mm.ss', xEndTime) +
        ' Остаток: ' + Format('%.2f', [ED.Outbal]) +
        ' Дебет(Сумма: ' + Format('%.2f', [ED.DebetSum]) + ') Кредит(Сумма: ' +
        Format('%.2f', [ED.CreditSum]) + ')', True);

      // инициализация локальной переменной
      xBudg_ID := '';



      // exchange #3068
      // если требуется создавать эд при загрузке ED211, то определяем
      // бюджет как при загрузке ED211 с созданием эд 24х (по старому)
      if (FNotED222 OR FAnswerEd211 OR vCfg_CreateDocExLoadED211) then begin

        // Exchange #2376
        // проверяем бюджетов для ЭД по полю Acc по таблице Счета
        // Бюджета (Бухгалтерия/Настройка счетов/Счета ФО)
        // если найдено несколько бюджетов по счету или ни одного то сбрасываем
        // переменную xBudg_ID. если найден один бюджен - сохраняем его а этой
        // переменной.
        // Exchange #2435
        // добавлен финансовый год в запрос поиска бюджета.
        // В результате, запрос, вместо поиск бюджета, проверит наличие счета в
        // бюджете текущего фин.года.
        // Exchange #2502
        // если в настройках указано использовать прилогиненный бюджет, то задачи
        // поиска бюджета по счету (#2376, #2435, #2439) не использовать и
        // работать чисто по старому алгоритму.
        if FAccountLoginBudget
          then xBudg_ID := ''
          else begin
            if (STRTOINT( QueryField( sqlBuchFO_2376,
                                      [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                        ED.Acc],
                                      'BUDGCOUNT')) = 1)
              then xBudg_ID := QueryField( sqlBuchFO_2376_Budget,
                                          [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                            ED.Acc],
                                          'ID')
              else begin
                xBudg_ID := '';
                // exchange #2439
                // если бюджет не определен, пробуем найти повторно с учетом "Счет" + "БИК"
                // нужно перебрать все секции TransInfo и если хотя бы в одной секции
                // будт найден однозначно бюджет по "счет+бик", то берем этот бюджет
                // и обрабатываем ED211 по новому алгоритму.
                // если бюджет не будет найден - работаем по старому.
                for i := 0 to ED.Count - 1 do begin

                  if (STRTOINT( QueryField( sqlBuchFO_2439,
                                            [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                              ED.TransInfo(i).BICCorr,
                                              ED.Acc],
                                            'BUDGCOUNT')) = 1)
                    then begin
                      xBudg_ID := QueryField( sqlBuchFO_2439_Budget,
                                                [ StrToInt(FormatDateTime('yyyy', FEDDate)),
                                                  ED.TransInfo(i).BICCorr,
                                                  ED.Acc],
                                                'ID');
        {отладка
        writelog( 'Бюджет найден:итерация='+inttostr(i));
        {отладка_конец}
                      BREAK;   // дальнейший перебор не нужен
                    end;
                end;//for//
              end;

          end;
      end;

      //-----------------------------------------------------------------------
      // exchange #3068
      if (vCfg_CreateDocExLoadED211 AND (ED.AbstractKind = '0')) then begin
        // если бюджет не определен, проверяем, если используется прилогиненный
        // бюджет - берем его
        xFoundBudgetID := xBudg_ID;
        if (LENGTH( xFoundBudgetID) <= 0) then
          if FAccountLoginBudget
            then xFoundBudgetID := Budget_Id;

        if (LENGTH( xFoundBudgetID) <= 0)
          then WriteInfo( 'Бюджет не определен: «Итоговые обороты по выписке банка» не будет создан.')
          else begin
            XmlOrgAcc := QueryXml(
                           ' select a.id AID, b.org_id OID from orgaccount a'
                          +' join budget b on b.org_id=a.org_id'
                          +' where b.id=? and a.orgacctype_id=2'
                          +' and a.account_number=?',
                           [ xFoundBudgetID,
                             ED.Acc]);
            XmlOrgAcc := XmlOrgAcc.documentElement;
            if ( XmlOrgAcc.childNodes.length <= 0)
              then WriteInfo(
                      FORMAT( '«Итоговые обороты по выписке банка» не создан.'
                             +' Не найден счет %s для организации "Финансовый орган"'
                             +' в бюджете %s.',
                              [ ED.Acc,
                                xFoundBudgetID]))
              else begin
                XmlOrgAcc := XmlOrgAcc.childNodes.Items[ 0];
                // создание эд
                xXml := CreateOleObject('Microsoft.XmlDom');
                xXmlDoc := xXml.appendChild( xXml.createElement('REFERENCE'));
                xXmlDoc.setAttribute( 'ref_name', 'ACCTURNOVER');
                xXmlDoc.setAttribute( 'action', 'insert');
                xXmlDoc.setAttribute( 'BUDGET_ID', xFoundBudgetID);
                xXmlDoc.setAttribute( 'ORG_ID', XmlOrgAcc.getAttribute('OID'));
                xXmlDoc.setAttribute( 'ORG_ACC_ID', XmlOrgAcc.getAttribute('AID'));

                // дата: нужно выгрузить как гггг-мм-дд
                xXmlDoc.setAttribute( 'CARRY_DATE',
                                      DateTimeToXml( ED.AbstractDate));

                // вх.отс по выписке
                xXmlDoc.setAttribute(
                              'IN_AMOUNT',
                              FORMAT( '%.2f', [ ED.EnterBal]));

                // обороты по дебету
                xXmlDoc.setAttribute(
                              'DEBIT_AMOUNT',
                              FORMAT( '%.2f', [ ED.DebetSum]));

                // обороты по кредиту
                xXmlDoc.setAttribute(
                              'CREDIT_AMOUNT',
                              FORMAT( '%.2f', [ ED.CreditSum]));

                try
                  WriteLog(
                      FORMAT( 'Создание «Итоговые обороты по выписке банка»'
                             +' для организации %s и счета %s...',
                              [ XmlOrgAcc.getAttribute('OID'),
                                XmlOrgAcc.getAttribute('AID')]));

                  xXml.loadXml( ExecXml( xXml.xml));

                  WriteLog( 'Выполнено.');
                  except
                    WriteInfo( 'Не создан. Причина: ' + LastException.Message);
                end;
              end;
          end;
      end;

      //-----------------------------------------------------------------------
    {отладка
    if FNotED222 then writelog( 'выполняется по FNotED222');
    {отладка_конец}
      if FNotED222 then begin
        // exchange #2477
        // правка БЛ - если бюджет определили неоднозначно - работаем по старому
        // алгоритму, иначе - создаем ЭД по новому алгоритму
        if (LENGTH( xBudg_ID) <= 0) then begin
          for i := 0 to ED.Count - 1 do
            if StrToInt(ED.TransInfo(i).TransKind) = 4
              then LoadTransInfo(ED.TransInfo(i))
              else DoNot_LoadTransInfo( ED.TransInfo(i), 'Бюджет не определен');
        end else begin
          for i := 0 to ED.Count - 1 do
            if StrToInt(ED.TransInfo(i).TransKind) = 4
              then LoadTransInfo_2477(ED.TransInfo(i), xBudg_ID)
              else DoNot_LoadTransInfo( ED.TransInfo(i), 'Бюджет = ' + xBudg_ID);
        end;
      end else begin
        // добавлено по анализу проблемы АЦК-Ф 20608
        WriteInfo( 'Приходные кассовые документы не будут созданы по настройке "Отсутствует ED222"=Нет.');
      end;

      if FAnswerEd211 then begin
    {отладка
    showmessage('выполняется по FAnswerEd211');
    {отладка_конец}
        // exchange #2376 - проверяем бюджет по ED.Acc
        if (LENGTH( xBudg_ID) <= 0) then begin
          // exchange #2376^ если описано несколько (или ни одного) бюджета для
          // ЭД 211 по Acc, то работаем по старому алгоритму

    {отладка
    showmessage( format( 'xBudg_ID=пусто + NOT(FAnswerEd211). ED.Count=%d',
                    [ED.Count]));
    {отладка_конец}

          for i := 0 to ED.Count - 1 do
            if StrToInt(ED.TransInfo(i).DC) = 1
              then LoadAnswerTransInfo(ED.TransInfo(i));
        end else begin
          // exchange #2376: если описан только один бюджет для ЭД 211 по Acc,
          // то работаем с учетом этого описанного бюджета
          for i := 0 to ED.Count - 1 do
            if StrToInt(ED.TransInfo(i).DC) = 1
              then LoadAnswerTransInfo_2376(ED.TransInfo(i), xBudg_ID);
        end;
      end else begin
        // добавлено по анализу проблемы АЦК-Ф 20608
        WriteInfo( 'Приходные кассовые документы не линкуются по настройке "Ответы в ED211"=Нет.');
      end;


    {отладка
    writelog( 'выполняется отчет в Excel');
    {отладка_конец}

      FileRep := DirRep + FormatDateTime('yyyy-mm-dd', FEDDate) +
        '\' + ChangeFileExt(ExtractFileName(FFileRepED211), '') +
        FormatDateTime('_hhmmss_', xEndTime) + ED.Acc + '.xls';
      ForceDirectories(ExtractFilePath(FileRep));



      WriteLog('Формирование отчёта по шаблону: ' + ExtractFileName(FFileRepED211), True);
      try
        Excel := GetActiveOleObject('Excel.Application');
      except
        try
          Excel := CreateOleObject('Excel.Application');
        except
          LastException.Message := 'CreateOleObject(''Excel.Application'') - ' +
            LastException.Message;
          raise(LastException.Message);
        end;
      end;
      try
       try
         Excel.Application.EnableEvents := false;
         Excel.WorkBooks.Add(FFileRepED211);
         except
           raise( 'Сбой подготовки создания отчета: ' + LastException.Message);
       end;
       try
         // exchange #2496 - добавление параметра к скрипту шаблона



         Excel.Application.Run('Module.Run', ED, FileRep, vReportConvertTimeToUTC);
         except
           raise( 'Сбой создания отчета: ' + LastException.Message);
       end;
       WriteLog('Отчёт сохранён: ' + FileRep, True);
      finally
        Excel := Null;
      end;
      except
        ExceptionProc( 'LoadED211');
    end;

end; {End LoadED211}

procedure LoadED217(ED: Variant);
var i: integer;
begin
  WriteLog(edtName[ED.EDType] + ' Дата ' + FormatDateTime('dd.mm.yyyy', ED.InfoDate), True);

  // exchange #2547
  // проверяем возможные значения "вид платежа" в ED217. если поле не допустимо
  // то отказываем обработку документа.
  // в 2.5.7 поле paytkind перенесено в другой раздел, поэтому прверяем
  // его во всех этих разделах
  for i := 0 to ED.Count - 1 do
    if (GetPayKindByValue( ED.EDType, ED.CreditInfo[i].AccDocInfo.PaytKind) = '?')
      then begin
        WriteInfo( 'Недопустимое значение в поле "вид платежа". Документ не обрабатывается.');
        EXIT;
      end;

  WriteLog('Формирование отчёта по шаблону: ED217.xlt', True);
  try
    Excel := GetActiveOleObject('Excel.Application');
  except
    try
      Excel := CreateOleObject('Excel.Application');
    except
      LastException.Message := 'CreateOleObject(''Excel.Application'') - ' +
        LastException.Message;
      raise(LastException.Message);
    end;
  end;
  try
   Excel.Application.EnableEvents := false;
   Excel.WorkBooks.Add(ExtractFilePath(FileLog) + 'UfebsReports\ED217.xlt');
   Excel.Application.Run('Module.Run', ED);
  finally
    Excel := Null;
  end;
end; {End LoadED217}

procedure LoadED219(ED: Variant);
begin
  WriteLog(edtName[ED.EDType] + ' Дата ' + FormatDateTime('dd.mm.yyyy', ED.ReportDate), True);
  with TStringList.Create do
  try
    Text := ED.ReportContent;
    ForceDirectories('C:\Temp');
    WriteLog('Сохранение формы 0401301 в: C:\Temp\ED219_' + ExtractFileName(FileIn) + '.Txt', True);
    SaveToFile('C:\Temp\ED219_' + ExtractFileName(FileIn) + '.Txt');
    WriteLog('Открытие в NotePad файла: C:\Temp\ED219_' + ExtractFileName(FileIn) + '.Txt', True);
    ShellExecute('NotePad', 'C:\Temp\ED219_' + ExtractFileName(FileIn) + '.Txt', False);
  finally
    Free;
  end;
end; {End LoadED219}


{~LoadED221
  exchange #2696
  в логах и отчетах необходимо отображать время в UTC в зависимости от
  настройки в конфиге.
  в схемах 2.6.0 время указывается в UTC }
procedure LoadED221(ED: Variant);
var
  i: integer;
  xEndTime: TDateTime;
begin
  // exchange #2696
  // получаем время из ED с учетом настройки использования UTC.
  // для схем меньше 2.6.0 параметр не проверяется и всегда берется время
  // как раньше.
  if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') < 0)
    then xEndTime := ED.EndTime
    else
  if vCfgConvertTimeToUTC
    then xEndTime := ED.EndTimeLocal
    else xEndTime := ED.EndTime;

  WriteLog(edtName[ED.EDType] + ' Дата ' + FormatDateTime('dd.mm.yyyy', ED.AbstractDate) +
    ' Время ' + FormatDateTime('hh.mm.ss', xEndTime) +
    ' Остаток: ' + Format('%.2f', [ED.Outbal]) +
    ' Дебет(Количество: ' + Format('%d', [ED.DebetQuantity]) +
    ' Сумма: ' + Format('%.2f', [ED.DebetSum]) + ') Кредит(Количество: ' +
    Format('%d', [ED.CreditQuantity]) + ' Сумма: ' + Format('%.2f', [ED.CreditSum]) + ')', True);

  // exchange #2598
  // по ED107 отчет не формируется (согласовано с АО), поскольку он сильно
  // отличается от ED105. при этом проверяем, если в пакете ED221 есть хотя бы
  // один вложенный ED107, то отчет в xml не формируем.
  For i := 0 To ED.Count - 1 do
    if (ED.EDCopy(i).ED.EDType = edtED107) then begin
      WriteInfo( 'Отчет не формируется, если ED221 содержит хотя бы один вложенный ED107.');
      EXIT;
    end;

  FileRep := DirRep + FormatDateTime('yyyy-mm-dd', FEDDate) + '\ED221' +
    FormatDateTime('_hhmmss_', xEndTime) + ED.Acc + '.xls';
  ForceDirectories(ExtractFilePath(FileRep));

  WriteLog('Формирование отчёта по шаблону: ED221.xlt', True);
  
  try
    Excel := GetActiveOleObject('Excel.Application');
  except
    try
      Excel := CreateOleObject('Excel.Application');
    except
      LastException.Message := 'CreateOleObject(''Excel.Application'') - ' +
        LastException.Message;
      raise(LastException.Message);
    end;
  end;
  try
   Excel.Application.EnableEvents := false;
   Excel.WorkBooks.Add(ExtractFilePath(FileLog) + 'UfebsReports\ED221.xlt');
   // exchange #2496 - добавление параметра к скрипту шаблона
   Excel.Application.Run('Module.Run', ED, FileRep, vReportConvertTimeToUTC);
  finally
    Excel := Null;
  end;
end; {End LoadED221}

procedure LoadED215(ED: Variant);
var
  i: Integer;
  procedure LoadEDCopy(EDCopy: Variant);
  var
    Node: Variant;
  begin
    Msg := edtName[ED.EDType] + ' с кодом (' + EDCopy.CtrlCode + ') на ' +
      edtName[EDCopy.ED.EDType] + Format(' № %5d', [EDCopy.ED.EDNo]) + ' Дата: ' +
      FormatDateTime('dd.mm.yyyy', EDCopy.ED.EDDate);
    Sql := 'Select P.Id, P.Amount, P.DocumentClass_Id, P.Version, P.DispStatus_Id, P.ExtStatus_Id' +
      ', D.Id Document_Id, D.DispStatus_Id, E.Exch_Restore, P.Budget_Id' +
      ', E.Exch_Number' +
      ' From Exch_Document E' +
      ' Left Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
      ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
      ' Where E.Exch_Date = ? And E.Exch_Number = ? And Exch_Name = ?';
    Xml := QueryXml(Sql, [EDCopy.ED.EDDate, EDCopy.ED.EDNo, Exch_Name]);
    if Xml.documentElement.ChildNodes.length = 0 then
    begin
      WriteInfo(Msg + ' - ЭД не найден в базе');
      Exit;
    end;
    Node := Xml.documentElement.childNodes.item[0];
    if Node.getAttribute('EXCH_RESTORE') <> 0 then
    begin
      WriteInfo(Msg + ' - ЭД уже был восстановлен из архива');
      Exit;
    end;
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml := Xml.appendChild(Xml.createElement('EXCHARHIV'));
    Xml.setAttribute('action', 'rest');
    Xml := Xml.appendChild(Xml.ownerDocument.createElement('ROW'));
    Xml.setAttribute('EXCH_DOCUMENTREF', Node.getAttribute('ID'));
    Xml.setAttribute('EXCH_CLASSREF', Node.getAttribute('DOCUMENTCLASS_ID'));
    Xml.setAttribute('VERSION', Node.getAttribute('VERSION'));
    ExecXml(Xml.ownerDocument.documentElement.xml);
    WriteInfo(Msg + ' - ЭД восстановлен из архива');
  end; {End LoadEDInfo}
begin
  WriteInfo(edtName[ED.EDType] + Format(' № %d', [ED.EDNo]) +
    ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.EDDate) +
    ' Количество: ' + Format('%d', [ED.QuantityED]) +
    ' Сумма: ' + Format('%.2f', [ED.Sum]) +
    ' - (' + scName[StrToIntDef(ED.StatusCode, 12)] + ')');
  for i := 0 to ED.Count - 1 do
  begin
    if ED.EDCopy[i].ED.EDType = edtED101 then
      LoadEDCopy(ED.EDCopy[i]);
    if ED.Count <> 1 then
    begin
      SetProgressBarMax(ED.Count);
      ShowProgress(i + 1);
    end;
  end;
//  for i := 0 to ED.Count - 1 to
//    if EDCopy[i].ED.EDType = ED101 then
end; {End LoadED215}

procedure LoadED243(ED: Variant);
var
  s: string;
  xBudgetID: string;
begin
  // описание обмена см. в "Обмен ED243 - ED244.doc"
  WriteInfo(edtName[ED.EDType] + ' - Запрос на получение информации по ЭПД участника' +
    Format(' № %d', [ED.EDNo]) + ' на ' + edtName[edtED243{101}] +
      Format(' № %d', [ED.OriginalEPD.EDNo]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.OriginalEPD.EDDate));
  // Поиск ЭД в архиве выгрузок
  { ПП ищется только среди выгруженных ПП из УФЕБС. из ФК не ищутся!
    при выгрузке ПП через УФЕБС поля ED.OriginalEPD.EDDate, ED.OriginalEPD.EDNo
    заполняются эксчем и передаются в пакете выгрузки.
    при подтверждении, в запросе ED243 эти данные передаются эксчу для
    поиска ПП среди выгруженных эксчем. эти поля не соответствуют номеру ЭД ПП
    и дате, а равны номеру пакета выгрузки и дате выгрузки ПП.}
  Sql := 'Select P.Id, P.Doc_Number, P.Doc_Date, P.Amount, P.DocumentClass_Id' +
    ', P.DispStatus_Id, P.ExtStatus_Id, D.Id Document_Id, D.DispStatus_Id' +
    ', E.Exch_Restore, B.Caption, E.Exch_Number, P.Budget_Id' +
    ' From Exch_Document E' +
    ' Left Join PayOrder P On (P.Id = E.Exch_DocumentRef And P.DocumentClass_Id = E.Exch_ClassRef)' +
    ' Left Join Document D On (D.Parent_Id = P.Document_Id And D.DispStatus_Id > -1)' +
    ' Join Budget B on B.Id = P.Budget_Id' +
    ' Where E.Exch_Date = ? And E.Exch_Name = ? And E.Exch_Number = ?' +
    '   and E.Exch_Restore = 0';
{
// отладка
showmessage('отладка: Exch_Name="'+Exch_Name+'"; ED.OriginalEPD.EDDate="'
+FormatDateTime('yyyy/mm/dd', ED.OriginalEPD.EDDate)+'"; ED.OriginalEPD.EDNo="'
+inttostr(ED.OriginalEPD.EDNo)+'"');
}
  // exchange #3033
  // по умолчанию (если эд не найден однозначно), бюджет берем прилогиненный
  xBudgetID := Budget_Id;

  Xml := QueryXml(Sql, [ED.OriginalEPD.EDDate, Exch_Name, ED.OriginalEPD.EDNo]);
  if Xml.documentElement.ChildNodes.length <> 1 then
  begin
    { exchange #2409.
      exchange #2547
      поменялись форматы в 2.5.9, поэтому для 2.5.9 ответ будет формироваться по
      новому (#2547) а для старых схем - по старому (#2409).
      exchange #3033
      добавлен бюджет загрузки - прилогиненный бюджет и идентификатор формата}
    if (Version_CompareEx( Ufebs.FormatVer, '2.5.9') >= 0)
      then begin
        if Exch2547_GenerateAnswerED244OnED243( ED, '', xBudgetID, Exch_Name)
          then EXIT;
      end else begin
        if Exch2409_GenerateAnswerED244OnED243( ED, '', xBudgetID, Exch_Name)
          then EXIT;
      end;
    WriteInfo('ЭД не найден в базе');
    Exit;
  end;
  Xml := Xml.documentElement.ChildNodes.Item[0];
  Msg := 'Запрос по платежному документу'  +
    Format(' № %s', [Trim(Xml.getAttribute('DOC_NUMBER'))]) + ' Дата: ' +
      FormatDateTime('dd.mm.yyyy', XmlToDateTime(Xml.getAttribute('DOC_DATE'))) +
      Format(' Сумма: %.2f', [StrToCurr(Xml.getAttribute('AMOUNT'))]);

  // exchange #3033
  // если эд найден однозначно, бюджет берем из выгрузки этого эд.
  // при этом автонумерация выгружаемых эд может быть нарушена,
  // xBudgetID := Xml.getAttribute('BUDGET_ID');

  // exchange #2547
  // добавлена расшифровка кода запроса в виде:
  // ... код запроса - N [Запрашиваемая информация - ]
  s := ED243_RequestCode_Name( StrToInt( ED.EDDefineRequestCode));
  if (LENGTH( s) > 0)
    then s := ' Запрашиваемая информация - ' + s;
  WriteInfo(Msg + '. Код запроса - ' + ED.EDDefineRequestCode + '.' + s);
  {
  if ED.EDDefineRequestCode in [0..8] then
    WriteInfo(Msg + '. Запрашиваемая информация - ' +
      scRequestCode[StrToInt(ED.EDDefineRequestCode)])
  else
    WriteInfo(Msg + '. Код запроса - ' + ED.EDDefineRequestCode);
    }

  { exchange #2409
    если включена опция конвертирования ED243 в ED244 то выполняем
    конвертирование и выходим из подпрограммы.
    если функция не выполнялась - выполняется работа по старому варианту
    (на будующее).
    exchange #2547
    поменялись форматы в 2.5.9, поэтому для 2.5.9 ответ будет формироваться по
    новому (#2547) а для старых схем - по старому (#2409).
    exchange #3033
    добавлен бюджет загрузки - прилогиненный бюджет и идентификатор формата}
  if (Version_CompareEx( Ufebs.FormatVer, '2.5.9') >= 0)
    then begin
      if Exch2547_GenerateAnswerED244OnED243( ED,
                                              Xml.GetAttribute('ID'),
                                              xBudgetID,
                                              Exch_Name)
        then EXIT;
    end else begin
      if Exch2409_GenerateAnswerED244OnED243( ED,
                                              Xml.GetAttribute('ID'),
                                              xBudgetID,
                                              Exch_Name)
        then EXIT;
    end;
end;

procedure LoadED244(ED: Variant);
begin
  WriteInfo(edtName[ED.EDType] + ' - Ответ на запрос участника' +
    Format(' № %d', [ED.EDNo]) + ' на ' + edtName[edtED101] +
      Format(' № %d', [ED.OriginalEPD.EDNo]) +
      ' Дата: ' + FormatDateTime('dd.mm.yyyy', ED.OriginalEPD.EDDate));
  if ED.EDDefineRequestCode in [0..8] then
    Msg := 'Запрашиваемая информация - ' +
      scRequestCode[StrToInt(ED.EDDefineRequestCode)]
  else
    Msg := 'Код запроса - ' + ED.EDDefineRequestCode;
  if ED.EDDefineAnswerCode in [0..8] then
    Msg := Msg + '. Ответ - ' + scAnswerCode[StrToInt(ED.EDDefineAnswerCode)]
  else
    Msg := Msg + '. Код ответа - ' + ED.EDDefineAnswerCode;
  WriteInfo(Msg);
end;


procedure Initialize(Xml: Variant);
var
  SL: TStringList;
begin
  fsScript := Null;
  QueryInitialization;
  // Проверяем регистрацию библиотеки УФЭБС: Ufebs.ocx
  try
    Ufebs := CreateOleObject('Ufebs.PacketEPD');
  except
    raise('Ошибка инициализации обьекта из библиотеки УФЭБС.' +
      ''#13#10'Зарегистрируйте библиотеку: regsvr32.exe Ufebs.ocx');
  end;
  if CompareVersionEx(Ufebs.Version, WorkUfebsVersion) < 0 then
    raise('Скрипты работают с Ufebs.ocx начиная с версии: ' +
      WorkUfebsVersion + ''#13#10'Текущая версия Ufebs.ocx: ' + Ufebs.Version);

  SL := TStringList.Create;
  try
    with Xml.documentElement, SL do begin
      // Каталог скриптов и настроек, используется для поиска дополнительных
      // файлов и создания каталогов по умолчанию
      DirMain := ExtractFilePath(getAttribute('INI_FILE'));
      // Файлы основного лога и информационного лога текущей сессии
      FileLog := DirMain + 'UfebsLoad.Log';
      FileInfo := DirMain + 'UfebsInfo.Log';
      // Удаляем информационный лог в начале сессии
      if FileExists(FileInfo) then
        DeleteFile(FileInfo);
      WriteLog('===     НАЧАЛО ЗАГРУЗКИ     ===');
      WriteLog('Версия сборки импорта/экспорта формата УФЭБС: ' + UfebsVersion);
      WriteLog('Инициализация параметров конфигурации', True);
      // Параметры конфигурационного файла
      CommaText := getAttribute('CONFIG');
      // Наименование идентификатора формата, для однозначности поиска
      // загруженных/выгруженных документов
      Exch_Name := getAttribute('EXCH_NAME');
      // Признак использования фильтра по бюджету
      FiltrBudget := Trim(Values['Фильтр по бюджету']) = 'Да';
      // Каталог поиска с маской или полным именем файла
      DirIn := Trim(Values['Каталог поиска']);
      // Настройка на архивный каталог
      DirArh := Trim(Values['Архивный каталог']);
      if DirArh = '' then DirArh := 'Arh';
      DirArh := StringReplace(DirArh + '\', '\\', '\');
      if ExtractFileDrive(DirArh) = '' then
        DirArh := DirMain + DirArh;
      ForceDirectories(DirArh);
      if not DirectoryExists(DirArh) then
        raise('Ошибка при определении архивного каталога: ' + DirArh);
      // Настройка на каталог ошибок
      DirErr := Trim(Values['Каталог ошибок']);
      if DirErr = '' then DirErr := 'Err';
      DirErr := StringReplace(DirErr + '\', '\\', '\');
      if ExtractFileDrive(DirErr) = '' then
        DirErr := DirMain + DirErr;
      ForceDirectories(DirErr);
      if not DirectoryExists(DirErr) then
        raise('Ошибка при определении каталога ошибок: ' + DirErr);
      // Настройка на каталог отчётов
      DirRep := Trim(Values['Каталог отчётов']);
      if DirRep = '' then DirRep := 'Rep';
      DirRep := StringReplace(DirRep + '\', '\\', '\');
      if ExtractFileDrive(DirRep) = '' then
        DirRep := DirMain + DirRep;
      ForceDirectories(DirRep);
      if not DirectoryExists(DirRep) then
        raise('Ошибка при определении каталога отчётов: ' + DirRep);
      FFileRepED211 := Trim(Values['Шаблон ED211']);
      if FFileRepED211 = '' then FFileRepED211 := 'UfebsReports\ed211.xlt';
      if ExtractFileDrive(FFileRepED211) = '' then
        FFileRepED211 := DirMain + FFileRepED211;
      if not FileExists(FFileRepED211) then
        raise('Не найден шаблон отчёта ED211: ' + FFileRepED211);
      // Определяем версию форматов УФЭБС (1.1.3 или 2.1.0)
      Ufebs.FormatVer := Trim(Values['Версия формата']);
      // Настраиваемся на каталог схем
      Ufebs.DirSchems := DirMain + 'UfebsSchems\' + Ufebs.FormatVer;
      // Настройка проверки ЭЦП(ЗК) для кадого ЭД в отдельности
      Ufebs.SignType := stNone;
      if Trim(Values['Проверять ЭЦП(ЗК)']) = 'Да' then Ufebs.SignType := stED;
      // настройка на обработку служебных конвертов
      FEnvelope := (Trim(Values['Обрабатывать служебный конверт']) = 'Да');
      // Признак использования шифрования и упаковки ЭД в служебном конверте
      Ufebs.EnvelopeCrypted := Trim(Values['Расшифровывать Object']) = 'Да';
      Ufebs.EnvelopeCompessed := Trim(Values['Распаковывать Object']) = 'Да';
      // Настройка проверки ЭЦП(КА) для служебного конверта
      FSigEnvelope := Trim(Values['Обрабатывать конверт ЭЦП(КА)']) = 'Да';
      if FEnvelope then FSigEnvelope := True;
      FVerifySigEnvelope := Trim(Values['Проверять ЭЦП(КА)']) = 'Да';
      // Настройки использования префиксов для пространств имён
      Ufebs.NSType[nstEd] := Trim(Values['urn:cbr-ru:ed:v1.1']);
      Ufebs.NSType[nstDsig] := Trim(Values['urn:cbr-ru:dsig:v1.1']);
      Ufebs.NSType[nstDsigEnv] := Trim(Values['urn:cbr-ru:dsig:env:v1.1']);
      Ufebs.NSType[nstSoap] := Trim(Values['http://www.w3.org/2003/05/soap-envelope']);
      Ufebs.NSType[nstMsg] := Trim(Values['urn:cbr-ru:msg:props:v1.1']);
      // Признак отсутствия ЭД ED222 - тогда кассовые документы создаются на основании выписки
      FNotED222 := Trim(Values['Отсутствует ED222']) = 'Да';
      //ищем 13 класс для линковки при загрузке ED211
      FAnswerEd211 := Trim(Values['Ответы в ED211']) = 'Да';
      // (Трабла в Ангарске, несколько финорганов пользуются одним счётов в РКЦ)
      FAccountLoginBudget := Trim(Values['Счет выбирать из прилогиненного бюджета']) = 'Да';
      FED211OperType := Trim(Values['Внутренний кредитовый на взнос наличными']);
      FFillNumberEd101 := Trim(Values['Добавлять нули в номер ПП до 3-х симолов']) = 'Да';
      if FED211OperType <> '' then
        if not ValidInt(FED211OperType)then
          raise('Параметр <Внутренний кредитовый на взнос наличными> - ЧИСЛОВОЕ ЗНАЧЕНИЕ');
      // exchange #2409 - инициализация параметров
      Exch2409_Initialize( SL, Xml);
      // exchange #2538
      // 6. В конфиг. файл UfebsLoad.cfg  добавить параметр "Учитывать счет Плательщика".
      // 6.1 параметр должен срабатывать только если в параметре Ответы в "ED211" стоит значение "Да"
      if FAnswerEd211
        then vCfgPayerAccountConsider:= Trim(Values['Учитывать счет Плательщика']) = 'Да'
        else vCfgPayerAccountConsider:= FALSE;
      // exchange #2583
      vCfgDateBank2583 := (Trim(Values[ 'В 24 классе заполнять дату по банку из EDDate при загрузке ed 108'])
                            = 'Да');
      // exchange #2696
      vCfgConvertTimeToUTC := (Trim(Values[ 'Преобразовывать время из всемирного в локальное для ed 211, 217, 221'])
                               = 'Да');

      // exchange #2696
      // параметр перевода времени UTC передаем в параметре к скрипту.
      // шаблоны будут доработаны с учетом доп. параметра.
      if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') < 0)
        then vReportConvertTimeToUTC := '0'
        else
      if vCfgConvertTimeToUTC
        then vReportConvertTimeToUTC := '1'
        else vReportConvertTimeToUTC := '0';

      // exchange #2769
      vCfgLoadED108by2769:= (Trim(Values[ 'Формировать одно Приложение к выписке кредитовое по ed108'])
                             = 'Да');

      // exchange #3061
      // проверяем год прилогиненного бюджета.
      // выставляем флаг=true если год бюджета >=2016.

      vBudgetYear2016andAbove :=
              (StrToInt(
                  QueryField( 'select FINYEAR X from budget where id=?',
                              [ Budget_ID],
                              'X')) >= 2016);


      // exchange #3068
      vCfg_CreateDocExLoadED211:=
              (Trim(Values[ 'Формировать итоговые обороты по выписке банка'])
               = 'Да');

      // exchange #3080
      vCfg_LoadED206_3080:=
              (Trim(Values[ 'LoadED206_3080'])
               = 'Да');

      // настройка работает только с версией 2016.1.1 и выше.
      if (Version_CompareEx( Ufebs.FormatVer, '2016.1.1') < 0)
        then vCfg_LoadED206_3080 := FALSE;


      // По совокупности настроек признак инициализации криптографических функций
      if (Ufebs.SignType <> stNone) or (FSigEnvelope and FVerifySigEnvelope) or
        (FEnvelope and Ufebs.EnvelopeCrypted) then
      begin
        WriteLog('Инициализация "СКАД Сигнатура"', True);

        Ufebs.VCERTLocalPath := Trim(Values['Каталог справочников ЭЦП']);

        Ufebs.VCERTInitialize;
      end;
      fsScriptName := Trim(Values['Подключаемый модуль']);
      if fsScriptName <> '' then
      begin
        fsScriptName := DirMain + fsScriptName;
        fsScript := TFsScript.create(nil);
        fsScript.Parent := fsGlobalUnit;
        fsScript.Load(fsScriptName);
        fsScript.Exec('Initialize', [Xml]);
      end;
    end;
    // exchange 2547 - инициализация конфигурации
    Initialize_2547_StringList( SL);
    finally
      SL.Free;
  end;
end; {Initialize}

procedure Finalize;
begin
  Exch2409_Finalize;     // exchange #2409
  QueryFinalization;
  Ufebs.VCERTUnInitialize;
  if fsScript <> Null then
  try
    fsScript.Exec('Finalize', Null);
  finally
    fsScript.Free;
  end;
  WriteLog('===   ЗАВЕРШЕНИЕ ЗАГРУЗКИ   ===');
end; {End Finalize}

begin
  Xml := CreateOleObject('Microsoft.XmlDom');
  FileTest := 'C:\Temp\UfebsLoad.Xml';
  if not FileExists(FileTest) then
  begin
    ShowMessage('Не найден тестовый пример: ' + FileTest);
    Exit;
  end;
  if not Xml.Load(FileTest) then
  begin
    ShowMessage('Ошибка при загрузке: ' + FileTest);
    Exit;
  end;
  IsDebug := True;
  Main(Xml);
end.
