//Постановка: Exchange #1994
//Доработка: Exchange #2389
uses
  'Un_Import',
  'Un_Imp_Doc195_from_Doc5', // exchange #2831: обязательно перед модулем Un_Import!
  'Un_Import_AuBu',       // exchange #3081
  'Un_DepartmentalInfo',     // требуется для exchange #2831
  'Un_ImportKBK',
  'Un_Org',                // требуется для exchange #2831
  'Un_Exch2405',   // обязательно перед модулем Un_Import!
  'Un_Exch2389',   // обязательно перед модулем Un_Import!
  'Un_ExportKBK',     // exchange #3062
  'Un_Exch2410',   // обязательно перед модулем Un_Import!
  'Un_Default',
  'Un_Class215',
  'Un_OrgAccountGetter',
  'QueryWork',
  'QueryKbk',
  'Un_SysParams',     // exchange #2412
  'QueryTools',
  'Un_MessageValidForm',
  'Un_VersionSupport',
  'Un_Schems',
  'Un_ToolsXml',
  'Un_Tools',
  'Un_ConstRef',
  'Un_Progress',
  'Un_System',
  'Un_Log',
  'Un_Debug';
{uses 'Un_Import', 'Un_Default',
  'Un_Class215', 'Un_OrgAccountGetter', 'QueryKbk', 'QueryWork', 'QueryTools',
  'Un_Schems', 'Un_VersionSupport', 'Un_ToolsXml', 'Un_ConstRef';}
const
  TestFileName = 'Imp_Fk_SF.Xml';
//  FormVer = 'TXSF090101';
var
  Vp_Date, BudgetId, IncReceiverId, FinYear: String;
  Adm, Doc: Variant;
  param_CreateDocuments: Boolean;

function Main(Xml: Variant): Boolean;
var
  Sr: TFileSearch;
begin
  Result := False;
  xml := InitializeMain( xml, TestFileName);
  if VarIsNull( xml) then exit;
  Sr := TFileSearch.Create;
  try
    try
      Initialize(Xml);
      // инициализация модуля описания счета.
      GetOrgAccountGetter_Initialize;
      if Sr.FindFirst(DirIn, faAnyFile) = 0 then
      begin
        repeat
          if (Sr.Name <> '.') and (Sr.Name <> '..') and (Sr.Attr <> faDirectory) then
          begin
            FirstInfo := True;
            FileIn := ExtractFilePath(DirIn) + Sr.Name;
            Data := CreateOleObject('Microsoft.XmlDom');
            Data.appendChild(Data.createElement('FORMAT'));
            if NOT TextFileToXml(FileIn) then begin
              WriteInfo( FORMAT( 'Файл %s не будет обрабатываться, поскольку он загружен с ошибками.',
                                  [ FileIn]));
              CONTINUE;
            end;
            if param_CtlValidOn then
              if not ValidateFormat then
              begin
                ShellExecute('NotePad', FileValidate, False);
                WriteLog('Не пройден контроль валидности отдельными документами');
                CONTINUE;//Exit;
              end;
            if LoadFile then

            begin
              CopyFile(FileIn, DirArh + Sr.Name, True);
              DeleteFile(FileIn);
              WriteInfo('Файл обработан.');
            end
            else
              WriteInfo('Файл оставлен в каталоге поиска: ' + FileIn);
          end;
        until Sr.FindNext <> 0;
        Sr.FindClose;
      end;
    except
      WriteInfo(LastException.Message);
      raise(LastException.Message);
    end;
    Result := True;
  finally
    Sr.Free;
    Finalize_Exch2389;
    Finalize(Xml);
//    ShowProgress(0);
//    StatusBarSimpleText('');
    ShowJournalEnd;
  end;
end; {end Main}

function LoadFile: Boolean;
var
  Xml, DocXml, Node: Variant;
  Vp_Date, FinYear: String;
  i, k: Integer;
begin
  Result := False;
  Data := Data.documentElement;
  WriteInfo('Обработка файла: ' + FileIn);
  WriteLog('Проверка версии формата', True);

  WriteLog('Определение финансового года по данным справки', True);
  Vp_Date := Data.childNodes.Item[3].getAttribute('DATE');
  FinYear := Copy(Vp_Date, 7, 4);
  // предварительные проверки, определение бюджета и т.п.
  WriteLog('Получение данных администратора', True);
  BudgetId := '';
  if Data.ChildNodes.Item[2].getAttribute('KOD_UBP') <> '' then
  begin
    IncReceiverId := '';
    // Exchange #2040
    Adm := GetOrgByAccNumOrgCode(Data.childNodes.Item[3].getAttribute('LS'),
      Data.childNodes.Item[2].getAttribute('KOD_UBP'), '7, 8', False, True, FinYear);
    if Adm.documentElement.childNodes.Length = 0 then
    begin
      WriteInfo(Format('Не найден администратор и его ЛС: код администратора' +
        ' <TO.KOD_UBP=%s>, номер лс <SF.LS=%s>; ',
        [Data.childNodes.Item[2].getAttribute('KOD_UBP'),
        Data.childNodes.Item[3].getAttribute('LS')]));
      Exit;
    end;
    if Adm.documentElement.childNodes.Length > 1 then
    begin
      WriteInfo(Format('Найдено несколько <%d> администраторов: код администратора ' +
        '<TO.KOD_UBP=%s>, номер лс <SF.LS=%s>;',
        [Adm.documentElement.childNodes.Length,
        Data.childNodes.Item[2].getAttribute('KOD_UBP'),
        Data.childNodes.Item[3].getAttribute('LS')]));
      Exit;
    end;
    Adm := Adm.documentElement.childNodes.item[0];
    WriteLog('Определение бюджета загрузки', True);
    if Adm.getAttribute('BUDGET_ID') <> '' then
    begin
      BudgetId := Adm.getAttribute('BUDGET_ID');
      WriteInfo('Бюджет загрузки определен по коду УБП');
    end
    else if Data.ChildNodes.Item[3].getAttribute('KOD_DOC') = 'VT' then
    //определяем бюджет по получателю доходов
    begin
      Xml := GetReceiverAttrByOrg(Adm.getAttribute('ORG_ID'));
      if Xml.documentElement.childNodes.Length <> 1 then
      begin
        WriteInfo('Бюджет загрузки не определен по организации: ' +
          Adm.getAttribute('ORG_DESCRIPTION') + ' Id = ' + Adm.getAttribute('ORG_ID')
          + '. У данной организации должен присутствовать один получатель доходов ' +
          'с галкой по умолчанию, в одном бюджете.');
        Exit;
      end;
      BudgetId := Xml.documentElement.childNodes.Item[0].getAttribute('BUDGET_ID');
      WriteInfo('Бюджет загрузки определен по получателю доходов');
      IncReceiverId := Xml.documentElement.childNodes.Item[0].getAttribute('ID');
    end
    else begin
      // определяем бюджет по настройке Settings\Budget_Admin.set
      with TIniFile.Create(DirIni + 'Settings\Budget_Admin.set') do
      begin
        BudgetId := ReadString('Администратор источников',
          Adm.getAttribute('ORG_ID'), '');
        if BudgetId = '' then
        begin
          WriteInfo(Format('Не задан бюджет в файле Budget_Admin.set для ' +
            'организации <%s> с id <%s>.',
            [Adm.getAttribute('ORG_DESCRIPTION'), Adm.getAttribute('ORG_ID')]));
          Exit;
        end;
        Xml := QueryXml(sqlBudgId + ' and FinYear = ?', [BudgetId, FinYear]);
        if Xml.documentElement.childNodes.Length = 0 then
        begin
          WriteInfo(Format('Не найден бюджет <%s>, указанный в настройке ' +
            'Budget_Admin.set, в справочнике бюджетов на <%s> год.',
              [BudgetId, FinYear]));
          Exit;
        end;
        if not IsActual(Adm.getAttribute('ORG_ID'), BudgetId) then
        begin
          WriteInfo(Format('Организация <%s> с id <%s> не является актуальной в бюджете <%s>.' +
            ' Загрузка остановлена',
              [Adm.getAttribute('ORG_DESCRIPTION'), Adm.getAttribute('ORG_ID'), BudgetId]));
          Exit;
        end;
        Free;
      end;
    end
  end
  else begin
    WriteInfo('Не удалось определить бюджет загрузки по коду организации.' +
      'Поле кода организации TO.KOD_UBP обязательно для заполнения.');
    Exit;
  end;
  //Проверка КБК
  WriteInfo('Проверка КБК в строках документов:', True);
  SetProgressBarMax( Data.childNodes.Length - 4);
  ShowProgress( 0);
  ChangeKbk := False;
  for i := 3 to Data.childNodes.Length - 1 do
  begin
    ShowProgressNext;//Bar.Position := ProgressBar.Position + 1;
    Data := Data.childNodes.item[i];
    if (Data.NodeName = 'SFST') then
    begin
      Default_F_Line(Data);
      // exchange #3062 - отмена косгу
      if CheckKBK(Data, 'KBK', BudgetId, '', FALSE, FALSE) then
        ChangeKbk := True;
    end;
    Data := Data.parentNode;
  end;
  if (ChangeKbk) and (not param_changeKBK) then
  begin
    WriteInfo('Найдены КБК в файле, которые отсутствуют в базе АЦК.');
    Exit;
  end;
  if ChangeKbk then
    WriteInfo('Отсутствующие КБК заменены на 0.')
  else
    WriteInfo('Пройдена успешно.');
  WriteInfo('Загрузка документов:');
  DocXml := CreateOleObject('Microsoft.XmlDom');
  DocXml := DocXml.appendChild(DocXml.createElement('ROOT'));
  for i:= 3 to Data.childNodes.length -1 do
  begin
    Node := Data.childNodes.items[i];
    if Node.nodeName = 'SF' then
    begin
      DocXml := DocXml.ownerDocument.documentElement;
      DocXml := DocXml.appendChild(Node.cloneNode(False));
    end
    else if Node.nodeName = 'SFDOC' then
    begin
      DocXml := DocXml.appendChild(Node.cloneNode(False));
      inc(k);
    end
    else if Node.nodeName = 'SFST' then
      DocXml.appendChild(Node.cloneNode(false));
  end;
  DocXml := DocXml.ownerDocument.documentElement;
  SetProgressBarMax(k);
  ShowProgress( 0);



  if param_CreateDocuments
    then
      begin
        //заполнение данных документов
        for i := 0 to DocXml.childNodes.Length - 1 do
        begin
          DocXml := DocXml.childNodes.Item[i];
          for k := 0 to DocXml.childNodes.Length - 1 do
          begin
            DocXml := DocXml.childNodes.Item[i];
            if DocXml.NodeName = 'SFDOC' then
            begin
              WriteInfo('---==============---');
              Doc := CreateOleObject('Microsoft.XmlDom');
              Doc := Doc.appendChild(Doc.createElement('DOCUMENT'));
              Doc.setAttribute('F_BUDGET_ID', BudgetId);
              Doc.setAttribute('F_ORIGINAL_TYPE', 'SF');
              SortDocument(Doc, DocXml.parentNode, DocXml);
            end;
            ShowProgressNext;
            DocXml := DocXml.parentNode;
          end;
          DocXml := DocXml.parentNode;
        end;
      end
    else
      begin
        WriteInfo('Не созданы дополнительные документы по блоку SF/SFDOC, ' +
                      'т.к параметр "Создавать справки ОрФК, прилагаемые к выписке из лицевого счета АДБ и АИФДБ" выключен ', True);
      end;
  Result := True;
end;

//разбор блока SFDOC на классы создаваемых документов
procedure SortDocument(Doc, xmlSF, DocXml: Variant);
var
  Doc35, Doc39, UFXml: Variant;
  i: Integer;
  s: string;
  xFlag: boolean;
begin

  // проверяем наличие уже обработанного документа с таким GUID
  // в указанном бюджете но только для класса 215
  if IsLoaded215( Doc.getAttribute('F_BUDGET_ID'),
                  DocXml.getAttribute('GUID_FK'))
    then begin
      WriteInfo('Блок SFDOC: Повторная загрузка документа 215 - пропущен', True);
      EXIT;
    end;

  Doc.setAttribute('DOC_NUMBER', DocXml.getAttribute('NOM_SF'));
  Doc.setAttribute('DOC_DATE', DocXml.getAttribute('DATE_OTCH'));
  Doc.setAttribute('GUID_FK', DocXml.getAttribute('GUID_FK'));

  WriteLog('Определение класса документа ...', True);
  for i := 0 to DocXml.childNodes.Length - 1 do
  begin
    DocXml := DocXml.childNodes.Item[i];

    s:= KadmCodeFormat(Adm.getAttribute('KADM_CODE'),Doc.getAttribute('F_BUDGET_ID'));

    if Copy(DocXml.getAttribute('KBK'), 0, 3) = s then
    begin
      { exchange 2593 пп.3
        При загрузке SF создание ЭД в системе осуществляется,
        если только в SFST поле NAME_DOC = «Справка органа ФК».
        Необходимо доработать: выполнять при значении поля NAME_DOC =
        «Справка органа Федерального казначейства» тот же алгоритм,
        что и сейчас }
      case LowerCase(DocXml.getAttribute('NAME_DOC')) of
        'справка органа фк',
        'справка органа федерального казначейства': begin
            DocXml.setAttribute('NUM_DOC', DocXml.getAttribute('NOM_DOC'));
            UFXml := GetAnswerUf(Doc, DocXml);
            if UFXml.documentElement.childNodes.Length = 1 then
            begin
              WriteInfo('Строка справки не создана, т.к найдено Уведомление об уточнении' +
                ' вида и принадлежности платежа', True);
              DocXml := DocXml.parentNode;
            end
            else begin
              if  (Data.childNodes.Item[3].getAttribute('KOD_DOC') = 'VA') and
                (DocXml.getAttribute('TYPE_KBK') = '31') then
                if VarIsNull(Doc39) then
                begin
                  Doc39 := CreateOleObject('Microsoft.XmlDom');
                  Doc39 := Doc39.appendChild(Doc.cloneNode(False));
                  Doc39 := Doc39.appendChild(DocXml.cloneNode(False));
                  Doc39 := Doc39.parentNode;
                end
                else begin
                  Doc39 := Doc39.appendChild(DocXml.cloneNode(False));
                  Doc39 := Doc39.parentNode;
                end;
              if (Data.childNodes.Item[3].getAttribute('KOD_DOC')= 'VT') and
                (DocXml.getAttribute('TYPE_KBK') = '20') then
                if VarIsNull(Doc35) then
                begin
                  Doc35 := CreateOleObject('Microsoft.XmlDom');
                  Doc35 := Doc35.appendChild(Doc.cloneNode(False));
                  Doc35 := Doc35.appendChild(DocXml.cloneNode(False));
                  Doc35 := Doc35.parentNode;
                end
                else begin
                  Doc35 := Doc35.appendChild(DocXml.cloneNode(False));
                  Doc35 := Doc35.parentNode;
                end;
            end;
            DocXml := DocXml.parentNode;
          end;
        else begin
          WriteInfo('Строки справки с наименованием документа <' + DocXml.getAttribute('NAME_DOC') +
            '> не обрабатываются', True);
          DocXml := DocXml.parentNode;
        end;
      end;//case//
    end
    else
      DocXml := DocXml.parentNode;
  end;



  if (not VarIsNull(Doc39)) and (Doc39.childNodes.length <> 0) then
  begin
    WriteInfo('---==============---');
    // проверка на повторную загрузку
    if param_CreateDocuments215
      then xFlag := FALSE
      else xFlag := IsLoaded(Doc39.getAttribute('F_BUDGET_ID'), '39',
        Doc39.getAttribute('GUID_FK'), null, True);
    if xFlag then begin
        WriteInfo('АЦК: "Справка по источникам" № ' +
          Doc39.getAttribute('DOC_NUMBER') + ' Дата: ' +
          Doc39.getAttribute('DOC_DATE'), True);
        WriteInfo('Повторная загрузка документа - пропущен', True)
      end else
        CreateDoc39(xmlSf, Doc39);
  end;
  if (not VarIsNull(Doc35)) and (Doc35.childNodes.length <> 0) then
  begin
    WriteInfo('---==============---');
    // проверка на повторную загрузку
    if param_CreateDocuments215
      then xFlag := FALSE
      else xFlag := IsLoaded(Doc35.getAttribute('F_BUDGET_ID'), '35',
        Doc35.getAttribute('GUID_FK'), null, True);
    if xFlag then begin
        WriteInfo('АЦК: "Справка по доходам" № ' +
          Doc35.getAttribute('DOC_NUMBER') + ' Дата: ' +
          Doc35.getAttribute('DOC_DATE'), True);
        WriteInfo('Повторная загрузка документа - пропущен', True)
      end else
        CreateDoc35(xmlSF, Doc35);
  end;
  Doc35 := null;
  Doc39 := null;

end;

//заполнение полей документа 35 класса
procedure CreateDoc35(xmlSF, DocXml: Variant);
var
  i: Integer;
  XmlOrg, Receiver: Variant;
  xMsgLog: string;
begin
  // Exchange #2335
  // DocXml содержит в своем составе узел SFST с описанием строки.
  // оттуда нужно вытащить информацию о платежном документе
  PreparePayDocParams215( DocXml.selectSingleNode('//SFST'), 'SFST');

  WriteLog('Формирование документа ...', True);

  // Exchange #2335
  // поправлен текст в логе для разных классов документов
  if param_CreateDocuments215
    then xMsgLog := 'АЦК: "Справка по внебанковским операциям" № %s  Дата: %s'
    else xMsgLog := 'АЦК: "Справка по доходам" № %s  Дата: %s';
  WriteInfo( Format( xMsgLog,
                     [ DocXml.getAttribute('DOC_NUMBER'),
                       DocXml.getAttribute('DOC_DATE')]),
             True);

  Doc := CreateOleObject('Microsoft.XmlDom');
  Doc := Doc.appendChild(DocXml.cloneNode(False));;
  Doc.setAttribute('action', 'insert');
//  Doc.setAttribute('class', 35);
  SetClassDocument215( Doc, 35, 'SF');
  Doc.setAttribute('BUDGET_ID', DocXml.getAttribute('F_BUDGET_ID'));
  Doc.setAttribute('DOC_NUMBER', Trim(DocXml.getAttribute('DOC_NUMBER')));
  Doc.setAttribute('DOC_DATE', DateTimeToXml(StrToDate(DocXml.getAttribute('DOC_DATE'))));
  //инициализация сумм в шапке
  Doc.setAttribute('AMOUNT', 0.00);
  Doc.setAttribute('PASS_AMT', 0.00);
  Doc.setAttribute('KDT_CODE', '1'); // всегда "Доходы"
  Doc := Doc.appendChild(Doc.ownerDocument.createElement('LINES'));
  for i := 0 to DocXml.childNodes.Length - 1 do
  begin
    DocXml := DocXml.childNodes.Item[i];
    Doc := Doc.appendChild(Doc.ownerDocument.createElement('LINE'));
    //инициализация сумм в строке
    Doc.setAttribute('AMOUNT', 0.00);
    Doc.setAttribute('PASS_AMT', 0.00);
    WriteLog('Заполнение данных получателя');
    Doc.setAttribute('RECEIVER_ID', '');
    if IncReceiverId <> '' then
      Doc.setAttribute('RECEIVER_ID', IncReceiverId)
    else begin
      Receiver := GetReceiverAttrByOrg(Adm.getAttribute('ORG_ID'), Doc.parentNode.
        parentNode.getAttribute('BUDGET_ID'));
      if Receiver.documentElement.childNodes.Length = 1 then
       Doc.setAttribute('RECEIVER_ID', Receiver.documentElement.childNodes.Item[0].getAttribute('ID'));
    end;
    Doc.setAttribute('ORGACCOUNT_ID', Adm.getAttribute('ACC_ID'));
    WriteLog('Заполнение данных плательщика');
    Doc.setAttribute('PAYER_TAXCODE', DocXml.getAttribute('INN_PAY'));
    Doc.setAttribute('PAYER_KPP', DocXml.getAttribute('KPP_PAY'));
    Doc.setAttribute('PAYER_ID', '');
    Doc.setAttribute('PAYER_NAME', '');
    if Trim(DocXml.getAttribute('INN_PAY')) <> '' then
    begin
      WriteLog('Поиск референса плательщика по ИНН и КПП', True);
      XmlOrg := GetOrgByTaxKpp(Doc.getAttribute('PAYER_TAXCODE'),
        Doc.getAttribute('PAYER_KPP'));
      if XmlOrg.documentElement.childNodes.Length = 1 then
      begin
        XmlOrg := XmlOrg.documentElement.childNodes.item[0];
        Doc.setAttribute('PAYER_ID', XmlOrg.getAttribute('ID'));
        Doc.setAttribute('PAYER_NAME', XmlOrg.getAttribute('DESCRIPTION'));
        WriteLog('Найден плательщик с референсом: ' + XmlOrg.getAttribute('ID'));
      end
      else
        WriteLog('Референс получателя не опеределен', True);
    end;
    Doc.setAttribute('TERRITORY_ID', GetTerritory_IdByOkato(DocXml.getAttribute('OKATO')));
    Doc.setAttribute('DESCRIPTION', 'Создано на основании Справки ОрФК, прилагаемой к' +
      ' выписке из лицевого счета АДБ и АИФДБ №' + DocXml.parentNode.getAttribute('DOC_NUMBER') +
      ' от ' + DocXml.parentNode.getAttribute('DOC_DATE'));
    Doc.setAttribute('DESCRIPTION_LINES', DocXml.getAttribute('OPER'));
    //копируем КБК
    AddReplaceAttrVal(DocXml, Doc);
    //принудительно проставляем КИФ-по постановке, всегда = 1
    Doc.setAttribute('FSD_ID', 1);
    if isPurposeFulgrantAutoFill('35', 'INC_RULE') then
//      Doc.setAttribute('PURPOSEFULGRANT_ID',
      Doc.setAttribute('PURPOSEFULGRANTD_ID',
        PurposeFulgrantAutoFill(Doc, Doc.parentNode.parentNode.getAttribute('BUDGET_ID')));
    if Format('%0.2f', [StrToCurr(DocXml.getAttribute('SUM_SFST'))]) > '0.00' then
      Doc.setAttribute('AMOUNT', DocXml.getAttribute('SUM_SFST'))
    else
      Doc.setAttribute('PASS_AMT', abs(DocXml.getAttribute('SUM_SFST')));

    // exchange #2389 - доходы
    Exch2389_Update_PURPOSEFULGRANT_ID(
//          Doc.parentNode.parentNode,
          Doc,
          '20',
          Doc.parentNode.parentNode.GetAttribute('BUDGET_ID'),
          'PURPOSEFULGRANTD_ID',
          Doc.parentNode.parentNode.getAttribute('class'),
          Doc.parentNode.parentNode.GetAttribute('KDT_CODE'));

    // Exchange #2335
    // прочие поля для документа 215
    if NOT UpdateFieldsForDocClass215( Doc, xmlSF, DocXml, 35, 'SFST')
      then EXIT;

    Doc.parentNode.parentNode.setAttribute('AMOUNT',
      Doc.parentNode.parentNode.getAttribute('AMOUNT') + StrToCurr(Doc.getAttribute('AMOUNT')));
    Doc.parentNode.parentNode.setAttribute('PASS_AMT',
      Doc.parentNode.parentNode.getAttribute('PASS_AMT') + StrToCurr(Doc.getAttribute('PASS_AMT')));
    Doc.parentNode.parentNode.setAttribute('DESCRIPTION', Doc.getAttribute('DESCRIPTION'));
    Doc.parentNode.parentNode.setAttribute('DESCRIPTION', Doc.getAttribute('DESCRIPTION'));
    Doc := Doc.parentNode;
    DocXml := DocXml.parentNode;
  end;
  Doc.parentNode.setAttribute('AMOUNT',
    Format('%.2f', [StrToCurr(Doc.parentNode.getAttribute('AMOUNT'))]));
  Doc.parentNode.setAttribute('PASS_AMT',
    Format('%.2f', [StrToCurr(Doc.parentNode.getAttribute('PASS_AMT'))]));
  Doc := Doc.ownerDocument.documentElement;
  //Вставка и обработка
  Exec_ChildDoc(Doc.getAttribute('BUDGET_ID'), '', Doc);
  DocXml := null;
end;

//заполнение полей документа 39 класса
procedure CreateDoc39(xmlSF, DocXml: Variant);
var
  i: Integer;
  XmlOrg, XmlAcc: Variant;
  xMsgLog: string;
begin
  // Exchange #2335
  // разбор параметров первичного документа из SPD/SFST
  // DocXml содержит в своем составе узел SFST с описанием строки.
  // оттуда нужно вытащить информацию о платежном документе
  PreparePayDocParams215( DocXml.selectSingleNode('//SFST'), 'SFST');

  WriteLog('Формирование документа ...', True);

  // Exchange #2335
  // поправлен текст в логе для разных классов документов
  if param_CreateDocuments215
    then xMsgLog := 'АЦК: "Справка по внебанковским операциям" № %s  Дата: %s'
    else xMsgLog := 'АЦК: "Справка по источникам" № %s  Дата: %s';
  WriteInfo( Format( xMsgLog,
                     [ DocXml.getAttribute('DOC_NUMBER'),
                       DocXml.getAttribute('DOC_DATE')]),
             True);

  Doc := CreateOleObject('Microsoft.XmlDom');
  Doc := Doc.appendChild(DocXml.cloneNode(False));;
  Doc.setAttribute('action', 'insert');
//  Doc.setAttribute('class', 39);
  SetClassDocument215( Doc, 39, 'SF');
  Doc.setAttribute('BUDGET_ID', DocXml.getAttribute('F_BUDGET_ID'));
  Doc.setAttribute('DOC_NUMBER', Trim(DocXml.getAttribute('DOC_NUMBER')));
  Doc.setAttribute('DOC_DATE', DateTimeToXml(StrToDate(DocXml.getAttribute('DOC_DATE'))));
  // --- ФО/Гл. администратор ---
  Doc.setAttribute('ORG_ID', Adm.getAttribute('ORG_ID'));
  Doc.setAttribute('ORG_TAXCODE', Adm.getAttribute('TAXCODE'));
  Doc.setAttribute('ORG_KPP', Adm.getAttribute('KPP'));
  Doc.setAttribute('ORG_NAME', Adm.getAttribute('ORG_DESCRIPTION'));
  //счет
  Doc.setAttribute('ORG_ACCOUNT_ID', Adm.getAttribute('ACC_ID'));
  Doc.setAttribute('ORG_ACCOUNT', Adm.getAttribute('ACCOUNT_NUMBER'));
  Doc.setAttribute('ORG_OFK_NAME', Adm.getAttribute('OFK_DESCRIPTION'));
  Doc.setAttribute('ORG_UFK_NAME', Adm.getAttribute('UFK_DESCRIPTION'));
  // Exchange #2040
  if (DocXml.childNodes.item[0].getAttribute('BS') <> '') and
    (DocXml.childNodes.item[0].getAttribute('BS') = Adm.getAttribute('UFK_ACCOUNT_NUMBER')) then
  begin
    Doc.setAttribute('ORG_UFK_ACC_ID', Adm.getAttribute('UFK_ACC_ID'));
    Doc.setAttribute('ORG_UFK_ACCOUNT', Adm.getAttribute('UFK_ACCOUNT_NUMBER'));
    Doc.setAttribute('ORG_CORACCOUNT', Adm.getAttribute('CORACCOUNT'));
    Doc.setAttribute('ORG_BIC', Adm.getAttribute('BIC'));
    Doc.setAttribute('ORG_B_NAME', Adm.getAttribute('B_NAME'));
    Doc.setAttribute('ORG_FILIAL_NAME', Adm.getAttribute('UFK_FILIAL_NAME'));
  end
  else begin
    Doc.setAttribute('ORG_UFK_ACC_ID', Adm.getAttribute('INCUFK_ACC_ID'));
    Doc.setAttribute('ORG_UFK_ACCOUNT', Adm.getAttribute('INCUFK_ACCOUNT_NUMBER'));
    Doc.setAttribute('ORG_CORACCOUNT', Adm.getAttribute('INCCORACCOUNT'));
    Doc.setAttribute('ORG_BIC', Adm.getAttribute('INCBIC'));
    Doc.setAttribute('ORG_B_NAME', Adm.getAttribute('INCB_NAME'));
    Doc.setAttribute('ORG_FILIAL_NAME', Adm.getAttribute('INCUFK_FILIAL_NAME'));
  end;
  Doc.setAttribute('COUNTERAGENT_ID', '');
  //инициализация сумм в шапке
  Doc.setAttribute('AMOUNT', 0.00);
  Doc.setAttribute('OUT_AMT', 0.00);
  Doc := Doc.appendChild(Doc.ownerDocument.createElement('LINES'));
  for i := 0 to DocXml.childNodes.Length - 1 do
  begin
    DocXml := DocXml.childNodes.Item[i];
    Doc := Doc.appendChild(Doc.ownerDocument.createElement('LINE'));
    //инициализация сумм в строке
    Doc.setAttribute('AMOUNT', 0.00);
    Doc.setAttribute('OUT_AMT', 0.00);
    Doc.setAttribute('ORG_UFK_NAME', Doc.parentNode.parentNode.getAttribute('ORG_UFK_NAME'));
    //контрагент
    Doc.setAttribute('COUNTERAGENT_ID', '');
    if Trim(DocXml.getAttribute('INN_PAY')) <> '' then
    begin
      WriteLog('Поиск референса контрагента по ИНН и КПП', True);
      XmlOrg := GetOrgByTaxKpp(DocXml.getAttribute('INN_PAY'),
        DocXml.getAttribute('KPP_PAY'));
      if XmlOrg.documentElement.childNodes.Length = 1 then
      begin
        XmlOrg := XmlOrg.documentElement.childNodes.item[0];
        Doc.setAttribute('COUNTERAGENT_ID', XmlOrg.getAttribute('ID'));
        WriteLog('Найден контрагент с референсом: ' + XmlOrg.getAttribute('ID'));
      end
      else
        WriteLog('Референс контрагента не опеределен', True);
    end;
    //копируем КБК
    AddReplaceAttrVal(DocXml, Doc);

    // exchange #2389 - источники
    Exch2389_Update_PURPOSEFULGRANT_ID(
//          Doc.parentNode.parentNode,
          Doc,
          '31',
          Doc.parentNode.parentNode.GetAttribute('BUDGET_ID'),
          'PURPOSEFULGRANTI_ID',
          Doc.parentNode.parentNode.getAttribute('class'),
          '');   // для источников тип дохода не указывается

    // Exchange #2335
    // прочие поля для документа 215
    if NOT UpdateFieldsForDocClass215( Doc, xmlSF, DocXml, 39, 'SFST')
      then EXIT;

    //принудительно проставляем КИФ-по постановке, всегда = 1
    Doc.setAttribute('FSI_ID', 1);
    Doc.setAttribute('DESCRIPTION', 'Создано на основании Справки ОрФК, прилагаемой к' +
      ' выписке из лицевого счета АДБ и АИФДБ №' + DocXml.parentNode.getAttribute('DOC_NUMBER') +
      ' от ' + DocXml.parentNode.getAttribute('DOC_DATE'));
    Doc.setAttribute('DESCRIPTION_LINES', DocXml.getAttribute('OPER'));
    if Format('%0.2f', [StrToCurr(DocXml.getAttribute('SUM_SFST'))]) > '0.00' then
      Doc.setAttribute('AMOUNT', DocXml.getAttribute('SUM_SFST'))
    else
      Doc.setAttribute('OUT_AMT', abs(DocXml.getAttribute('SUM_SFST')));
    Doc.parentNode.parentNode.setAttribute('AMOUNT',
      Doc.parentNode.parentNode.getAttribute('AMOUNT') + StrToCurr(Doc.getAttribute('AMOUNT')));
    Doc.parentNode.parentNode.setAttribute('OUT_AMT',
      Doc.parentNode.parentNode.getAttribute('OUT_AMT') + StrToCurr(Doc.getAttribute('OUT_AMT')));
    Doc.parentNode.parentNode.setAttribute('DESCRIPTION', Doc.getAttribute('DESCRIPTION'));
    Doc := Doc.parentNode;
    DocXml := DocXml.parentNode;
  end;
  Doc.parentNode.setAttribute('AMOUNT',
    Format('%.2f', [StrToCurr(Doc.parentNode.getAttribute('AMOUNT'))]));
  Doc.parentNode.setAttribute('OUT_AMT',
    Format('%.2f', [StrToCurr(Doc.parentNode.getAttribute('OUT_AMT'))]));
  Doc := Doc.ownerDocument.documentElement;
  //Вставка и обработка
  Exec_ChildDoc(Doc.getAttribute('BUDGET_ID'), '', Doc);
  DocXml := null;
end;

procedure Initialize(Xml: Variant);
begin
  with TStringList.Create do
  try
    CommaText := InitializeDefault(Xml, ChangeFileExt(TestFileName, ''), False);
    // переход на новую функцию загрузки схем
//    LoadSchema(DirIni + 'Schems\sf_txsf090101.xml');
    LoadSchema( GetFileNameSchemaTFF( 'sf_txsf*'));

{    param_CreateDocuments := Values['Создавать справки ОрФК, прилагаемые ' +
      'к выписке из лицевого счета АДБ и АИФДБ'] = 'Да';}

    // Exchange #2335
    // проверяем по опции, какой документ нужно создавать по параметру
    // "Создавать справки ОрФК, прилагаемые к выписке из лицевого счета АДБ и АИФДБ" в cfg.
    // если выбрано НЕТ - выходим. сообщение уже создано в подпрограмме.
    param_CreateDocuments := FALSE;
    if (ParseParameterCreateDocument(
         Values['Создавать справки ОрФК, прилагаемые к выписке из лицевого счета АДБ и АИФДБ']) <> 0)
      then param_CreateDocuments := TRUE;

    // поскольку документ 215 объединяет в себе документы "справки по расходам,
    // доходам, источникам" вместе взятые, то при создании документа 215
    // будем пользоваться уже имеющимся кодом по созданию других документов.
    if param_CreateDocuments215
      then param_CreateDocuments := TRUE;

    // exchange #2389
    Initialize_Exch2389( DirIni, Values['Схема загрузки доп кодов из поля ADD_KLASS']);
  finally
    Free;
  end;
end; {End Initialize}

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

{var
  Xml: Variant;}

begin
  Main(NULL);{
  Xml := LoadXmlTest(TestFileName);
  if not VarIsNull(Xml) then
    Main(Xml);}
end.
