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

  'Exp_FK_Report',   // выгрузка в DBF (для татарстана)
  'UfebsTools',

  'UfebsLog',
  'Un_Log',
  'UfebsMakeFileName',
  'UfebsConst',
  'Un_Progress',
  'Un_Version',
  'Un_Debug',
  'WorkUfebsVersion.inc',
  'WorkAppVersion.inc',
  'UfebsVersionInc.inc';

var
  // exchange #2521 - флаг выгрузки в DBF.
  vCfg_OutDbf: boolean;
  // exchange #2696 - номер рейса
  vCfg_RaiseNumber: string;
  // exchange #2919
  // Выгружать значения получателя и плательщика из поля «Наименование
  // по требованию банка»: true =да
  vCfg2919: boolean;

function Main(Xml: Variant): Boolean;
begin
  Result := False;
  InitializeDebug;
  if CompareVersionEx(AppVersion, WorkAppVersion) < 0 then
    raise('Скрипты работают с AzkEchange.Exe начиная с версии: ' + WorkAppVersion +
      ''#13#10'Текущая версия AzkEchange.Exe: ' + AppVersion);
  with Xml.documentElement do
  if getAttribute('TESTED') = 'True' then
  begin
    setAttribute('TESTED', 'False');
    Xml.save('C:\Temp\UfebsUnload.Xml');
    ShowMessage('Тестовый пример приготовлен: C:\Temp\UfebsUnload.Xml');
    Exit;
  end;
  try
    try

      Initialize(Xml);
      try
        if not MakeUfebs(Xml) then
          Exit;
      except
        DeleteFile(FileInfo);
        raise(LastException.Message);
      end;
      try
        FileTmp := DirTmp + ExtractFileName(FileOut);
        WriteLog('Сохранение во временном каталоге: ' + FileTmp, True);
        Ufebs.SaveToFile(FileTmp);
      except
        raise('Ошибка сохранения: ' + FileTmp);
      end;

      // exchange #2521 - флаг выгрузки в DBF.
      // выгрузка в DBF (для татарстана)
      if vCfg_OutDbf then
        try
          Xml.DocumentElement.SetAttribute('F_OUTFILENAME', FileOut);
          MakeReportTat(Xml);
          except
            DeleteFile(FileTmp);
            raise(LastException.Message);
        end;

      try
        WriteLog('Перенос документов АЦК в архив', True);
        Move_To_Arhiv(Xml);
      except
        DeleteFile(FileTmp);
        raise(LastException.Message);
      end;
      try
        WriteLog('Копирование в исходящий каталог: ' + FileOut, True);
        CopyFile(FileTmp, FileOut, False);
        if not FileExists(FileOut) then raise('');
      except
        raise('Ошибка сохранения: ' + FileOut + #13#10 + 'файл находиться: ' + FileTmp);
      end;
      FileArh := DirArh + FormatDateTime('yyyy-mm-dd', FEDDate) + '\Out\' +
        ExtractFileName(FileTmp);
      ForceDirectories(ExtractFilePath(FileArh));
      WriteLog('Копирование в архивный каталог: ' + FileArh, True);
      if not DirectoryExists(ExtractFilePath(FileArh)) then
        WriteInfo('Ошибка создания архивного каталога: ' + ExtractFilePath(FileArh))
      else
        CopyFile(FileTmp, FileArh, False);
      if not FileExists(FileArh) then
        WriteInfo('Ошибка сохранения: ' + FileArh);
      Result:= True;
      WriteLog('Удаление из временного каталога: ' + FileTmp, True);
      DeleteFile(FileTmp);
      try
        MakeUfebsRep;
      except
        WriteInfo('Ошибка создания отчёта:' + LastException.Message);
      end;
    except
      WriteLog(LastException.Message);
      raise(LastException.Message);
    end;
  finally
    Finalize(Xml, FLast or not Result);
    ShowProgress(0);
    StatusBarSimpleText('');
    // В случае наличия информационного лога, выводим в NotePad (для операциониста)
    if FileExists(FileInfo) then
      ShellExecute('NotePad', FileInfo, False);
  end;
end; {End Main}

function MakeUfebs(Xml: Variant): Boolean;
var
  i, FEDNo, n: Integer;
  Node, XmlVar: Variant;
  xPayKind: string;
begin
  Result := False;
  
  Node := Xml.documentElement;

  WriteLog('<ЭД/Пакет ЭД> - Создание по документам АЦК', True);
  SetProgressBarMax( Node.childNodes.length);

  Ufebs.EDNo := DPEDNo + StrToInt(Node.getAttribute('EXCH_PACKET'));
  Ufebs.EDDate := FEDDate;
  Ufebs.EDAuthor := FEDAuthor;
  Ufebs.SystemCode := FSystemCode;

  // exchange #2696 - для схем 2.6.0 и выше
  // Выгружать в поле установленное значение из параметра «Номер рейса»
  // конфигурации «Выгрузка по формату УФЭБС».
  // Если не заполнено – не выгружать.
  if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') >= 0) then
    if ( LENGTH( vCfg_RaiseNumber) > 0)
      then Ufebs.SessionID := vCfg_RaiseNumber;

  FEDNo := DPEDNo + StrToInt(Node.getAttribute('EXCH_PACKET'));
  
  for i := 0 to Node.childNodes.length - 1 do
  with Ufebs.addEDType(edtED101) do
  begin
    Node := Xml.documentElement.childNodes.item[i];
    EDNo := StrToInt(Node.getAttribute('EXCH_NUMBER'));
    EDDate := FEDDate;
    EDAuthor := FEDAuthor;

    // exchange #2696
    // номер рейса (из конфига) - для схем 2.6.0 и выше.
    if (Version_CompareEx( Ufebs.FormatVer, '2.6.0') >= 0) then begin
      if ( LENGTH( vCfg_RaiseNumber) > 0)
        then SessionID := vCfg_RaiseNumber;
      // При выгрузке 13 класса по формату 101 выгружать в поле значение
      // из поля системы «Уникальный идентификатор начисления» закладки
      // «ГИС ГМП», если оно заполнено (добавляется в АЦК-Ф 14080).
      // только для АЦК-Ф 2.33 и выше
      if ( LENGTH( VarToStr( Node.getAttribute( 'UIN'))) > 0)
        then PaymentID := VarToStr( Node.getAttribute( 'UIN'));
    end;

    { exchange #2547
      добавлена выгрузка Вида платежа для ED101 и только для 2.5.9.
      2-почтой**
      3-телеграфом**
      4-срочный*
      5-экстренный*
      причем выгрузка возможна с указанием в конфиге.
      если в конфиге указано пустая строка - выгрузка вида платежа не выполняется.
      на прочие значения полагаемся на схемы УФЭБС - проверка по ним выполняется
      при выгрузке.
      если указано значение "вид платежа" =0 в ЭД, то в файл тоже не выгружается}
{отладка
writelog( 'выгрузка ED101 Node:' + Node.xml);
// проставляем значение принудительно - для отладки
Node.SetAttribute('PAYKIND', '3');
{отладка_конец}
//    PaytKind := 1;    // по умолчанию для 2.5.8
    if (Version_CompareEx( Ufebs.FormatVer, '2.5.9') >= 0) then begin
      xPayKind := TRIM( ExpPayKind_2547( VarToStr( Node.getAttribute('PAYKIND'))));
{отладка
//showmessage( 'xPayKind = "'+xPayKind+'"');
writelog( 'выгрузка PaytKind в ED101 = "' + xPayKind + '".');
{отладка_конец}
      // если при выгрузке указана пустая строка - заменяем значение на 0.
      // в уфэбс в объекте TEPDComplete.makeXML значение 0 не выгружается.
      if ( LENGTH( xPayKind) <= 0)
        then PaytKind := 0
        else
          try
            n := STRTOINT( xPayKind);
            if NOT (n in [2,3,4,5]) then begin
              WriteInfo( '(ПП АЦК) - ID = ' + Node.getAttribute('ID')
                        + ' Номер: ' + Trim(Node.getAttribute('DOC_NUMBER'))
                        + ' Дата: ' + Node.getAttribute('DOC_DATE')
                        + ' Сумма: ' + Node.getAttribute('AMOUNT')
                        + ' - Не выгружается. Вид платежа имеет недопустимое значение.');
              Result := False;
              EXIT;
            end;
            PaytKind := n;
            except
              raise ( FORMAT( 'Не верно указано значение параметра "%s" в конфигурации.',
                              [ cnCfg_2547_ExpPaymentValue_Name]));
          end;
    end;
{отладка
writelog( 'версия УФЭБС = "' + Ufebs.FormatVer + '".');
writelog( 'Значение выгрузки PaytKind в ED101 = "' + inttostr(PaytKind) + '".');
{отладка_конец}

    // exchange #3022
    // поле AccDocNo стало =6 символов, поэтому берем последние 6 символов
    // номера документа. для версии меньше 2.8.6.2 - по старому: 3 символа
    AccDoc.AccDocNo := StrToInt(Copy(Node.getAttribute('DOC_NUMBER'),
      Length(Node.getAttribute('DOC_NUMBER')) - 8, 9));
    //if ( Ufebs.FormatVer = '2015.4.1') then begin
    if (Version_CompareEx( Ufebs.FormatVer, '2015.4.1') >= 0) then begin
      if Length(AccDoc.AccDocNo) > 6 then
        AccDoc.AccDocNo := StrToInt(Copy(AccDoc.AccDocNo, Length(AccDoc.AccDocNo) - 5, 6));
    end else begin
      if Length(AccDoc.AccDocNo) > 3 then
        AccDoc.AccDocNo := StrToInt(Copy(AccDoc.AccDocNo, Length(AccDoc.AccDocNo) - 2, 3));
    end;

    AccDoc.AccDocDate := XMLToDateTime(Node.getAttribute('DOC_DATE'));

    // exchange #2547 - убрано значение "вид платежа" = электронно
    // осталось только для схем ниже 2.5.9
    if (Version_CompareEx( Ufebs.FormatVer, '2.5.9') < 0)
      then PaytKind := 1;

    Sum := StrToCurr(Node.getAttribute('AMOUNT'));
    Priority := Node.getAttribute('QUEUE_KIND');
    if FOneED then SystemCode := FSystemCode;
    Payer.INN := Node.getAttribute('PAY_TAXCODE');
    Payer.KPP := Node.getAttribute('PAY_KPP');
    Payer.PersonalAcc := Node.getAttribute('PAY_ACCOUNT');
    Payer.Name := Node.getAttribute('PAY_NAME');
    Payer.Bank.BIC := Node.getAttribute('PAY_BIC');
    if not CheckBankStatus(Payer.Bank.BIC) then Exit;
    Payer.Bank.CorrespAcc := Node.getAttribute('PAY_CORACCOUNT');
    Payee.INN := Node.getAttribute('REC_TAXCODE');
    Payee.KPP := Node.getAttribute('REC_KPP');
    Payee.PersonalAcc := Node.getAttribute('REC_ACCOUNT');
    // Если получатель имеет роль Кредитная организация и счет - указан ниже
    // не выгружать (очищать), технический счёт из за проблем АЦК
    // (проплата на корсчёт организации в РКЦ)
    if VarToStr(Node.getAttribute('REC_ID')) <> '' then
    begin
      Sql := 'Select O.Id' +
        ' From Org O' +
        ' Join OrgRoles R On R.Org_Id = O.Id And R.OrgRole_Id = 6' +
        ' Where O.Id = ?';
      XmlVar := QueryXml(Sql, [Node.getAttribute('REC_ID')]);
      // exchange #2612
      // проверка счета вынесена не только для найденных в справочнике,
      // но и для заполненных вручную.
{      if (XmlVar.documentElement.ChildNodes.length = 1) and
        (Payee.PersonalAcc = '00000000000000000000') then
        Payee.PersonalAcc := '';}
    end;
    // exchange #2612
    // проверяем счет, не зависимо от того, есть описание организации в
    // справочнике или организация заведена вручную.
    // по схеме 2.5.10, в счете PersonalAcc первые 4 символа не должны
    // содержать символ "0" (одновременно быть 0000).
    // по схеме 2.5.9 и ниже, такого ограничения нет.
    // на первое время сделана проверка счета =0 во всех цифрах.
    // в дальнейшем проверка должна быть более мудреной (если необходимо).
    if (Payee.PersonalAcc = '00000000000000000000')
      then Payee.PersonalAcc := '';

    Payee.Name := Node.getAttribute('REC_NAME');
    if Copy(Payer.PersonalAcc, 1, 5) in ['30101', '30103', '30105', '30124', '30201', '30203'] then
      Priority := 0;
    if (Node.getAttribute('REC_UFK_ACCOUNT') <> '') and
      (Node.getAttribute('REC_UFK_ACCOUNT') <> Node.getAttribute('PAY_ACCOUNT')) then
    begin
      WriteInfo('Изменение счёта и наименования получателя при формировании ЭД.');
      WriteInfo('(ПП АЦК) - ID = ' + Node.getAttribute('ID') + ' Номер: ' +
        Trim(Node.getAttribute('DOC_NUMBER')) + ' Дата: ' + Node.getAttribute('DOC_DATE') +
        ' Сумма: ' + Node.getAttribute('AMOUNT'));
      WriteInfo('Счёт получателя (' + Node.getAttribute('REC_ACCOUNT') +
        ') заменён на счёт УФК (' + Node.getAttribute('REC_UFK_ACCOUNT') + ')');
      Payee.PersonalAcc := Node.getAttribute('REC_UFK_ACCOUNT');
      WriteInfo('Наименование получателя (в ПП АЦК): ' + Node.getAttribute('REC_NAME'));
      if FMakeRecName then
        Payee.Name := MakeRecName(Node);
    end;
    Payee.Bank.BIC := Node.getAttribute('REC_BIC');
    if not CheckBankStatus(Payee.Bank.BIC) then Exit;
    Payee.Bank.CorrespAcc := Node.getAttribute('REC_CORACCOUNT');
    Purpose := Node.getAttribute('DESCRIPTION');
    
    if (Node.getAttribute('PI_BUDGET_CODE') <> '0') and (Node.getAttribute('PI_BUDGET_CODE') <> '') then
      DepartmentalInfo.CBC := Node.getAttribute('PI_BUDGET_CODE');
    
    if (Node.getAttribute('AUTHOR_ID') <> '0') and (Node.getAttribute('AUTHOR_ID') <> '') then
    begin
      DepartmentalInfo.DrawerStatus := Format('%0.2d', [StrToInt(Node.getAttribute('AUTHOR_ID'))]);
      DepartmentalInfo.CBC := Node.getAttribute('PI_BUDGET_CODE');
      DepartmentalInfo.OKATO := Node.getAttribute('PAY_OKATO');
      DepartmentalInfo.PaytReason := Node.getAttribute('GROUND_ID');
      DepartmentalInfo.TaxPeriod := Node.getAttribute('TAXPERIOD');
      DepartmentalInfo.DocNo := Node.getAttribute('GRND_DOC_NUMBER');
      DepartmentalInfo.DocDate := Node.getAttribute('GRND_DOC_DATE');
      DepartmentalInfo.TaxPaytKind := Node.getAttribute('PAYTYPE_ID');
    end;
    if (DepartmentalInfo.DrawerStatus <> '') and (Payee.KPP = '') then
      Payee.KPP := 0;

    // exchange #2919
    // Если в параметре указано значение «Да»
    if vCfg2919 then begin
       // если поле «Наименование по требованию банка» блока «Плательщик»
       // выгружаемого ЭД класса 13 имеет непустое значение, то при
       // формировании выгрузки ED101 в поле «Наименование плательщика» (8)
       // выгружать значение поля «Наименование по требованию банка»
       // блока «Плательщик». Иначе, выгрузку формировать по текущей реализации.
       if (LENGTH( VarToStr( Node.getAttribute( 'PAY_NAME_BANK_REQUEST'))) > 0)
         then begin
           Payer.Name := VarToStr( Node.getAttribute( 'PAY_NAME_BANK_REQUEST'));
           WriteInfo('Наименование плательщика взято из поля «Наименование по требованию банка» блока «Плательщик»');
         end;
       // если поле «Наименование по требованию банка» блока «Получатель»
       // выгружаемого ЭД класса 13 имеет непустое значение, то при
       // формировании выгрузки ED101 в поле «Наименование получателя» (16)
       // выгружать значение поля «Наименование по требованию банка»
       // блока «Получатель». Иначе, выгрузку формировать по текущей реализации.
       if (LENGTH( VarToStr( Node.getAttribute( 'REC_NAME_BANK_REQUEST'))) > 0)
         then begin
           Payee.Name := VarToStr( Node.getAttribute( 'REC_NAME_BANK_REQUEST'));
           WriteInfo('Наименование получателя взято из поля «Наименование по требованию банка» блока «Получатель»');
         end;
    end;

    ShowProgress( i + 1);
  end;

  WriteLog('<ЭД/Пакет ЭД> - Формирование', True);
  Ufebs.makeXML;
  
  UfebsRep := Ufebs;
  
  MakeFileName(Xml);

  if FOneED then
    Ufebs := Ufebs.ED[0]
  else
    Msg := ' Количество: ' + Format('%6d',[Ufebs.EDQuantity]);
  WriteLog(edtName[Ufebs.EDType] + ' № ' + Format('%9d',[Ufebs.EDNo]) +
    ' Дата: ' + FormatDateTime('dd.mm.yyyy', Ufebs.EDDate) + Msg +
    ' Сумма: ' + Format('%12.2f', [Ufebs.Sum]));

  if Ufebs.SignType in [stED, stPacket] then
  begin
    WriteLog('<ЭД/Пакет ЭД> - Установка ЭЦП(ЗК)', True);
    Ufebs.Sign;
  end;

  if FFormatXML then
  begin
    WriteLog('<ЭД/Пакет ЭД> - Форматирование', True);
    Ufebs.FormatXML;
  end;

  WriteLog('<ЭД/Пакет ЭД> - Контроль валидности', True);
{отладка
writelog( '---------------- выгружаемый ED >>');
writelog( Ufebs.XMLText);
writelog( '----------------');
{отладка_конец}
  if not Ufebs.Validate then
  begin
    if Ufebs.EDType = edtPacketEPD then
    begin
      for i := 0 to Ufebs.count - 1 do
      begin
        if not Ufebs.ED[i].Validate then
          with Ufebs.ValidateError do
            raise('<ЭД/Пакет ЭД> - Не прошёл контроль валидности' + #13#10 +
              'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
      end;
      Ufebs.Validate;
    end;
    with Ufebs.ValidateError do
      raise('<ЭД/Пакет ЭД>  - Не прошёл контроль валидности' + #13#10 +
        'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
  end;

  if FSigEnvelope then
  begin
    FileArh := DirArh + FormatDateTime('yyyy-mm-dd', FEDDate) + '\Out\Xml\' +
      ExtractFilename(FileOut) + '.xml';
    ForceDirectories(ExtractFilePath(FileArh));
    if DirectoryExists(ExtractFilePath(FileArh)) then
      Ufebs.SaveToFile(FileArh);

    WriteLog('<Конверт ЭЦП(КА)> - Создание', True);
    Ufebs := Ufebs.makeSigEnvelope;
    WriteLog('<Конверт ЭЦП(КА)> - Формирование', True);
    Ufebs.makeXML;
    WriteLog('<Конверт ЭЦП(КА)> - Установка ЭЦП(КА)', True);
    Ufebs.Sign;
    if FFormatXML then
    begin
      WriteLog('<Конверт ЭЦП(КА)> - Форматирование', True);
      Ufebs.FormatXML;
    end;
    WriteLog('<Конверт ЭЦП(КА)> - Контроль валидности', True);
    if not Ufebs.Validate then
      with Ufebs.ValidateError do
        raise('<Конверт ЭЦП(КА)> - Не прошёл контроль валидности' + #13#10 +
          'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
  end;

  if FEnvelope then
  begin
    WriteLog('<Служебный конверт> - Создание', True);
    Ufebs := Ufebs.makeEnvelope;
    WriteLog('<Служебный конверт> - Формирование', True);
    Ufebs.MessageInfo.SendTo := FTo;
    Ufebs.MessageInfo.SendFrom := FFrom;
    Ufebs.MessageInfo.MessageType := FMessageType;
    Ufebs.MessageInfo.Priority := FPriority;
    //DocInfo
    Ufebs.DocInfo.DocFormat := 1; //Всегда 1 - УФЭБС
    if not FOneED then
      Ufebs.DocInfo.DocType := 'PacketEPD';
    Ufebs.DocInfo.EDRefID.EDNo := FEDNo;
    Ufebs.DocInfo.EDRefID.EDDate := FEDDate;
    Ufebs.DocInfo.EDRefID.EDAuthor := FEDAuthor;

    if FTransportFileName then
      Ufebs.MessageInfo.LegacyTransportFileName := ExtractFileName(FileOut);

    if FMessageID then Ufebs.MessageInfo.MessageID := 'guid:' + Ufebs.genGuid;
    if FAppMessageID then Ufebs.MessageInfo.AppMessageID := 'guid:' + Ufebs.genGuid;

    Ufebs.makeXML;
    if FFormatXML then
    begin
      WriteLog('<Служебный конверт> - Форматирование', True);
      Ufebs.FormatXML;
    end;
    WriteLog('<Служебный конверт> - Контроль валидности', True);
    if not Ufebs.Validate then
      with Ufebs.ValidateError do
        raise('<Служебный конверт> - Не прошёл контроль валидности' + #13#10 +
          'Причина: ' + reason + #13#10 + 'XML: ' + srcText);
  end;

  Result := True;
end; {End MakeUfebs}

function MakeRecName(Node: Variant; IsRepeat: Boolean = false): String;
var
  FType: Integer;
  Caption: String;
  Xml: Variant;
begin
  Sql := 'Select A.Account_Number Account, K.Id ID, K.Account_Number KAccount' +
    ', A.OrgAcctype_Id AType, OAT.Caption ACaption' +
    ', K.OrgAcctype_Id KType, KT.Caption KCaption' +
    ', A.Cash_Flag, Case When A.Cash_Flag  = 1 Then '' (Для выдачи наличных)'' Else '''' End CashCaption' +
    ' From OrgAccount A' +
    ' Left Join OrgAccType OAT On (OAT.Id = A.OrgAcctype_Id)' +
    ' Left Join OrgAccount K On (K.Id = A.KeeperAcc_Id)' +
    ' Left Join OrgAccType KT On (KT.Id = K.OrgAcctype_Id)' +
    ' Where A.Id = ?';
  Xml := QueryXml(Sql, [Node.getAttribute('REC_ACC_ID')]);
  with Xml.documentElement.ChildNodes.item[0] do
  // Если счёт ПБС с типом "Лицевой" или "Лицевой счёт по источникам ФО",
  // открытый на 02 или 01 или 04 счете ФО с типом "Ближний  счёт в органах ФК".
  if (getAttribute('KTYPE') <> '') and (getAttribute('KACCOUNT') <> '')
    and (getAttribute('ATYPE') in [1, 6]) and (getAttribute('KTYPE') = 5)
    and ((Copy(getAttribute('KACCOUNT'), 1, 2) = '01')
      or (Copy(getAttribute('KACCOUNT'), 1, 2) = '02')
      or (Copy(getAttribute('KACCOUNT'), 1, 2) = '04')) then
    FType := 1
  // Если счёт ПБС с типом "Счёт в органах ФК", "Ближний счёт в органах ФК"
  // или "Лицевой счёт по источникам ФК".
  else if (getAttribute('ATYPE') in [3, 5, 7]) then
  begin
    // Если с установленным признаком "Для выдачи наличных"
    if (getAttribute('CASH_FLAG') = 1) then
      FType := 3
    else
      FType := 2
  end
  // Если счёт ПБС с типом "Лицевой", открытый  на банковском счёте ФО.
  else if (getAttribute('KTYPE') <> '') and (getAttribute('ATYPE') = 1) and (getAttribute('KTYPE') = 2) then
    FType := 4
  else
    FType := 0;
  with Xml.documentElement.ChildNodes.item[0] do
  begin
    WriteInfo('Счёт получателя: ' + getAttribute('ACCOUNT') + ' (ID = ' +
      Node.getAttribute('REC_ACC_ID') +') - ' + getAttribute('ACAPTION') +
      getAttribute('CASHCAPTION'));
    WriteInfo('Счёт организации в блоке финорган: ' + getAttribute('KACCOUNT') +
      ' (ID = ' + getAttribute('ID') + ') - ' + getAttribute('KCAPTION'));
  end;
  case FType of
    0:
      begin
        Result := Node.getAttribute('REC_NAME');
        WriteInfo('Наименование получателя не изменено.');
      end;
    1:
      begin
        // Краткое наименование УФК счета ФО, на котором открыт лицевой счёт ПБС,
        // а в скобках, через запятую, краткое наименование ФО (Уполномоченного органа),
        // краткое наименование ПБС (из документа), а так же номер счета ФО, на
        // котором открыт лицевой счёт ПБС с приставкой л/с.
        Sql := 'Select KEO.Caption UFKName, KO.Caption OFKName, O.Caption OName, K.Account_Number' +
          ' From OrgAccount A' +
          ' Left Join Org O On (O.Id = A.Org_Id)' +
          ' Left Join Org KO On (KO.Id = A.Keeper_Id)' +
          ' Left Join OrgAccount K On (K.Id = A.KeeperAcc_Id)' +
          ' Left Join Org KEO On (KEO.Id = K.Executer_Id)' +
          ' Where A.Id = ?';
        Xml := QueryXml(Sql, [Node.getAttribute('REC_ACC_ID')]);
        with Xml.documentElement.ChildNodes.item[0] do
        Result := Format('%s (%s, %s, л/с %s)', [getAttribute('UFKNAME'),
          getAttribute('OFKNAME'), Node.getAttribute('REC_NAME'), getAttribute('ACCOUNT_NUMBER')]);
        WriteInfo('Наименование получателя заменено на: ' + Result);
      end;
    2, 3:
      begin
        Sql := 'Select KEO.Caption UFKName, O.Caption OName, A.Account_Number' +
          ' From OrgAccount A' +
          ' Left Join Org O On (O.Id = A.Org_Id)' +
          ' Left Join Org KEO On (KEO.Id = A.Executer_Id)' +
          ' Where A.Id = ?';
        Xml := QueryXml(Sql, [Node.getAttribute('REC_ACC_ID')]);
        with Xml.documentElement.ChildNodes.item[0] do
        if FType = 2 then
          // Краткое наименование УФК, в котором открыт счёт ПБС, а в скобках,
          // через запятую, краткое наименование ПБС (из документа), а также номер
          // счёта ПБС с  приставкой л/с.
          Result := Format('%s (%s, л/с %s)', [getAttribute('UFKNAME'),
            getAttribute('ONAME'), getAttribute('ACCOUNT_NUMBER')])
        else
          // Краткое наименование УФК, в котором открыт счёт ПБС, а в скобках
          // краткое наименование ПБС (из документа).
          Result := Format('%s (%s)', [getAttribute('UFKNAME'), Node.getAttribute('REC_NAME')]);
        WriteInfo('Наименование получателя заменено на: ' + Result);
      end;
    4:
      begin
        // Краткое наименование ФО (уполномоченного органа) в котором открыт лицевой
        // счёт ПБС, а в скобках, через запятую, краткое  наименование ПБС и номер
        // лицевого счёта ПБС с приставкой л/с.'
        Sql := 'Select KO.Caption OFKName, O.Caption OName, A.Account_Number' +
          ' From OrgAccount A' +
          ' Left Join Org O On (O.Id = A.Org_Id)' +
          ' Left Join Org KO On (KO.Id = A.Keeper_Id)' +
          ' Where A.Id = ?';
        Xml := QueryXml(Sql, [Node.getAttribute('REC_ACC_ID')]);
        with Xml.documentElement.ChildNodes.item[0] do
        Result := Format('%s (%s, л/с %s)', [getAttribute('OFKNAME'),
          Node.getAttribute('REC_NAME'), getAttribute('ACCOUNT_NUMBER')]);
        WriteInfo('Наименование получателя заменено на: ' + Result);
      end;
  end;
  if not IsRepeat and (Length(Result) > 160) then
  begin
    Sql := 'Select O.Caption From Org O Where O.Id = ?';
    Caption := QueryField(Sql,[Node.getAttribute('REC_ID')], 'CAPTION');
    Msg := 'В результате наименование получателя превысило 160 символов.'  + #13 + #13 +
      'Наименование получателя в ПП: ' + Node.getAttribute('REC_NAME') + #13 +
      'Краткое наименование получателя из справочника организаций: ' + Caption + #13 + #13 +
      'БУДЕТЕ ЗАМЕНЯТЬ НА КРАТКОЕ НАИМЕНОВАНИЕ ИЗ СПРАВОЧНИКА ОРГАНИЗАЦИЙ ?' + #13;
    WriteInfo(Msg);
    if MessageDlg(Msg, mtConfirmation, mbYes + mbNo, 0) = mrYes then
    begin
      WriteInfo('Ответ - ДА');
      Node.setAttribute('REC_NAME', Caption);
      Result := MakeRecName(Node, true);
    end
    else
    begin
      WriteInfo('Ответ - НЕТ');
      raise('Бессмысленно продолжать выгрузку' + #13 +
        'Банк не пропустит наименование получателя больше 160 символов.');
    end;
  end;
end; {End MakeRecName}

procedure MakeUfebsRep;
var
  Excel: Variant;
begin
  if FFileUfebsRep = '' then Exit;
  FileRep := DirRep + FormatDateTime('yyyy-mm-dd', FEDDate) + '\' +
    ChangeFileExt(ExtractFileName(FFileUfebsRep), '') + IntToStr(UfebsRep.EDNo) + '.xls';
  ForceDirectories(ExtractFilePath(FileRep));

  WriteLog('Формирование отчёта по шаблону: ' + ExtractFileName(FFileUfebsRep), 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(FFileUfebsRep);
   Excel.Application.Run('Module.Run', UfebsRep, Budget_Name, FileRep);
   WriteLog('Отчёт сохранён: ' + FileRep, True);
  finally
    Excel := Null;
  end;
end; {End MakeUfebsRep}

function CheckBankStatus(Bic: String): boolean;
var
  Value: String;
begin
  Result := True;
  Value := VarToStr(QueryField('Select Status From Bank Where Bic = ?', [Bic], 'STATUS'));
  if Value in ['ЗСЧТ', 'ОТЗВ', 'ИЗМР', 'ИСКЛ', 'ЛИКВ', 'ИНФО'] then
  begin
    Msg := 'Обнаружен банк с БИК: "' + Bic + '" со статусом: "' + Value +
      '", ограничивающим проведение расчетных операций.';
    WriteLog(Msg);
    if MessageDlg(Msg + #13 + 'Игнорировать ?', mtConfirmation, mbYes + mbNo, 0) <> mrYes then
    begin
      WriteLog('Выгрузка прервана пользователем');
      Result := False;
    end;
  end;
end; {End CheckBankStatus}

procedure Initialize(Xml: Variant);
begin
  QueryInitialization(Xml);
  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);
  with Xml.documentElement, TStringList.Create do
  try
    FileLog := ExtractFilePath(getAttribute('INI_FILE')) + 'UfebsUnLoad.Log';
    FileInfo := ExtractFilePath(getAttribute('INI_FILE')) + 'UfebsInfo.Log';
    if FileExists(FileInfo) then
      DeleteFile(FileInfo);
    WriteLog('===   НАЧАЛО ВЫГРУЗКИ   ===');
    WriteLog('Версия сборки импорта/экспорта формата УФЭБС: ' + UfebsVersion);
    WriteLog('Инициализация параметров конфигурации', True);
    CommaText := getAttribute('CONFIG');

    FEDDate := StrToDate(getAttribute('DATE'));
    FOneED := Trim(Values['Ограничение на количество документов в пакете']) = '1';
    FFirst := getAttribute('PACKETFIRST') = 'True';
    FLast := getAttribute('PACKETLAST') = 'True';

    FMakeRecName := Trim(Values['Формировать наименование получателя']) = 'Да';

    FModuleFileName := ExtractFilePath(getAttribute('INI_FILE')) + 'UfebsFileName.pfe';
    FFunctionFileName := Trim(Values['Правило формирование имени файла']);

    FFileUfebsRep := Trim(Values['Шаблон отчёта']);
    if FFileUfebsRep <> '' then
    begin
      if ExtractFileDrive(FFileUfebsRep) = '' then
        FFileUfebsRep := ExtractFilePath(getAttribute('INI_FILE')) + FFileUfebsRep;
      if not FileExists(FFileUfebsRep) then
      begin
        WriteInfo('Не найден по указанному пути шаблон отчёта: ' + FFileUfebsRep);
        FFileUfebsRep := '';
      end;
    end;

    DirTmp := Trim(Values['Временный каталог']);
    if DirTmp = '' then DirTmp := 'Temp';
    DirTmp := StringReplace(DirTmp + '\', '\\', '\');
    if ExtractFileDrive(DirTmp) = '' then
      DirTmp := ExtractFilePath(getAttribute('INI_FILE')) + DirTmp;
    ForceDirectories(DirTmp);
    if not DirectoryExists(DirTmp) then
      raise('Ошибка при определении временного каталога: ' + DirTmp);
    DirOut := Trim(Values['Исходящий каталог']);
    if DirOut = '' then DirOut := 'Output';
    DirOut := StringReplace(DirOut + '\', '\\', '\');
    if ExtractFileDrive(DirOut) = '' then
      DirOut := ExtractFilePath(getAttribute('INI_FILE')) + DirOut;
    ForceDirectories(DirOut);
    if not DirectoryExists(DirOut) then
      raise('Ошибка при определении исходящего каталога: ' + DirOut);
    DirArh := Trim(Values['Архивный каталог']);
    if DirArh = '' then DirArh := 'Arhiv';
    DirArh := StringReplace(DirArh + '\', '\\', '\');
    if ExtractFileDrive(DirArh) = '' then
      DirArh := ExtractFilePath(getAttribute('INI_FILE')) + DirArh;
    ForceDirectories(DirArh);
    if not DirectoryExists(DirArh) then
      raise('Ошибка при определении архивного каталога: ' + DirArh);
    DirRep := Trim(Values['Каталог отчётов']);
    if DirRep = '' then DirRep := 'Rep';
    DirRep := StringReplace(DirRep + '\', '\\', '\');
    if ExtractFileDrive(DirRep) = '' then
      DirRep := ExtractFilePath(getAttribute('INI_FILE')) + DirRep;
    ForceDirectories(DirRep);
    if not DirectoryExists(DirRep) then
      raise('Ошибка при определении каталога отчётов: ' + DirRep);

    Ufebs.FormatVer := Trim(Values['Версия формата']);

    Ufebs.DirSchems := ExtractFilePath(getAttribute('INI_FILE')) +
      'UfebsSchems\' + Ufebs.FormatVer;

    if Trim(Values['Устанавливать ЭЦП(ЗК)']) = 'Не устанавливать' then
      Ufebs.SignType := stNone
    else if Trim(Values['Устанавливать ЭЦП(ЗК)']) = 'На каждый ЭД в пакете' then
      Ufebs.SignType := stED
    else if Trim(Values['Устанавливать ЭЦП(ЗК)']) = 'На весь пакет' then
      Ufebs.SignType := stPacket;

    FSigEnvelope := Trim(Values['Формировать конверт ЭЦП(КА)']) = 'Да';

    FEnvelope := (Trim(Values['Формировать служебный конверт']) = 'Да') And FSigEnvelope;

    Ufebs.EnvelopeCrypted := Trim(Values['Шифровать Object']) = 'Да';
    Ufebs.OIDEncrypt := Trim(Values['OID ключа адресата шифрования']);
    Ufebs.EnvelopeCompessed := Trim(Values['Упаковывать Object']) = 'Да';

    FEDAuthor := Trim(Values['Идентификатор составителя']);
    FTo := Trim(Values['Адрес получателя']);
    FFrom := Trim(Values['Адрес отправителя']);
    FSystemCode := Trim(Values['Признак системы обработки']);
    FMessageType := Trim(Values['Тип сообщения']);
    FPriority := Trim(Values['Приоритет сообщения']);
    FAppMessageID := Trim(Values['Прикладной идентификатор']) = 'Да';
    FMessageID := Trim(Values['Идентификатор сообщения']) = 'Да';
    FTransportFileName := Trim(Values['Передавать имя файла']) = 'Да';

    FFormatXML := Trim(Values['Форматировать XML']) = 'Да';

    vCfg2919 := 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']);

    if ((Ufebs.SignType in [stED, stPacket]) or FSigEnvelope) and FFirst then
    try
      WriteLog('Инициализация "СКАД Сигнатура"', True);
      Ufebs.VCERTLocalPath := Trim(Values['Каталог справочников ЭЦП']);
      Ufebs.VCERTInitialize;
      except
        ExceptionLog( 'Сбой: Инициализация "СКАД Сигнатура"');
    end;

    // exchange #2521 - параметр выгрузки в DBF
    vCfg_OutDbf := (LOWERCASE( TRIM(Values['Выгрузка платежных поручений в DBF']))
                      = 'да');

    // exchange 2547 - инициализация конфигурации
    Initialize_2547( Text);

    // exchange #2696
    vCfg_RaiseNumber := TRIM(Values['Номер рейса']);

    // exchange #3032
    // совместима только с версией УФЭБС OCX не ниже 2.2.0.0.0
    // exchange #3041
    // версия шифрования не нужна в 2.38, поэтому из конфига параметр будет
    // удален, а код в скрипте останется только в режиме отладки.
    // exchange #3107
    // требуется реализовать в 2.38 и 2.38.2
    case TRIM(Values['Режим шифрования']) of
      'PKCS7':  Ufebs.EncryptParam := 1;
      else      Ufebs.EncryptParam := 0;
    end;//case//

  finally
    Free;
  end;
end; {Initialize}

procedure Finalize(Xml: Variant; Full: Boolean);
begin
  QueryFinalization(Xml);
  if Full then
    Ufebs.VCERTUnInitialize;
  WriteLog('===   ЗАВЕРШЕНИЕ ВЫГРУЗКИ   ===');
end; {End Finalize}

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