//Exchange #2295
function CheckPayOrder(cds: TClientDataSet; IniPath: String): Boolean;
var
  sql: String;
  Xml: Variant;
  //FindIndustryGrantInvestCode - результат поиска отраслевого кода и кода субсиди
  //для счетов в 5,6 разряде которых указано 10 или 20, значения:
  //0 - не нашли ни отр.код ни кода субсидии
  //1 - нашли что то одно: либо код субсидии либо отр.код
  //2 - нашли и код субсидии и отраслевой код.
  i, FindIndustryGrantInvestCode: Integer;
  Unclassified, isOneMask, ls1020, ls1121, ls1223: Boolean;
  procedure SetMessage(Text: String);
  begin
    cds.Edit;
    cds.FieldByName('ResText').AsString := Text;
    cds.Post;
  end;
begin
  Result := False;
  if AzkCompareVersion('2.26.46.11') < 0 then
  begin
    SetMessage('Модуль проверки работает начиная с версии АЦК-Финансы 2.26.46.11');
    Exit;
  end;
  Xml := CreateOleObject('Microsoft.XmlDom');
  //проверяются только документы, у которых счет получателя совпал со счетом
  //указанным в справочнике Бухгалтерия-Настройка счетов, поле расчетный счет,
  //тип счета "Счет для учета операций БУ/АУ".
  sql := 'Select P.Rec_Acc_Id, Oa.Org_Id' +
    ' From Payorder P' +
    ' Join BudgetOrgAccount B on P.Rec_Acc_Id = B.OrgAccount_Id' +
    '   and P.Budget_Id = B.Budget_Id' +
    ' Join OrgAccount Oa on Oa.Id = B.OrgAccount_Id' +
    ' Where P.Id = ? and B.BudgetOrgAccountType_Id = 1';
  Query.AddStr(cds.FieldByName('Id').asString);
  Xml.LoadXML(Query.Run(sql));
  Xml := Xml.documentElement.childNodes;
  if (Xml.Length = 1) and (Xml.Item[0].getAttribute('REC_ACC_ID') <> '') then
  begin
    cds.Edit;
    cds.FieldByName('Rec_Acc_Id').Value := Xml.Item[0].getAttribute('REC_ACC_ID');
    cds.FieldByName('Rec_Id').Value := Xml.Item[0].getAttribute('ORG_ID');
    cds.Post;
  end
  else begin
    SetMessage('Счет не совпадает со счетом для учета операций по БУ, АУ' +
      ' или не найден в базе');
    Exit;
  end;
  cds.Edit;
  cds.FieldByName('Enroll').Value := Null;
  cds.Post;
  //устанавливаем флаг неклассифицированных поступлений
  Unclassified := False;
  //определяет Id получателя из выписки
  if cds.FieldByName('Org_Id').asString = '' then
  begin
    if cds.FieldByName('Org_TaxCode').asString = '' then
    begin
      SetMessage('Не заполнен ИНН в блоке "Получатель из выписки"' +
        ' ЭД "Приложение к выписке кредитовое"');
      Exit;
    end;
    sql := 'Select O.Id' +
      ' From Org O' +
      ' Join Orgroles Orl on Orl.Org_Id = O.Id' +
      ' Where O.Taxcode = ? and O.Close_Date is null and Orl.OrgRole_Id in (18, 19)';
    Query.AddStr(cds.FieldByName('Org_Taxcode').asString);
    if cds.FieldByName('Org_Kpp').asString <> '' then
    begin
      sql := sql + ' and O.Kpp = ?';
      Query.AddStr(cds.FieldByName('Org_Kpp').asString);
    end;
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    Xml := Xml.documentElement.childNodes;
    if Xml.Length = 1 then
    begin
      cds.Edit;
      cds.FieldByName('Org_Id').AsString := Xml.items[0].getAttribute('ID');
      cds.Post;
    end
    else begin
      SetMessage('Id получателя из выписки в базе не найден');
      Unclassified := True;
    end;
  end;
  //лс
  if (not Unclassified) then
  begin
    //Определяем список лицевых счетов открытых на б/с счете получателя 24 класса
    sql := 'Select Ls.Account_Number, Ls.Id' +
      ' From OrgAccount Ls' +
      ' Join Org O on O.Id = Ls.Org_Id' +
      ' Join OrgAccount Bs on Bs.Id = Ls.KeeperAcc_Id' +
      ' Where Ls.Org_Id = ? and Bs.Id = ? and Ls.OrgAccType_Id = 1' +
      '   and Ls.Close_Date is null and Ls.Budget_Flag = 0' +
      ' Union' +
      ' Select Ls.Account_Number, Ls.Id' +
      ' From OrgAccount Ls' +
      ' Join Org O on O.Id = Ls.Org_Id' +
      ' Join OrgAccount Bs on Bs.Id = Ls.ExecuterAcc_Id' +
      ' Where Ls.Org_Id = ? and Bs.Id = ? and Ls.OrgAccType_Id = 5' +
      '   and Ls.Close_Date is null and Ls.Budget_Flag = 0';
    Query.AddStr(cds.FieldByName('Org_Id').AsString);
    Query.AddStr(cds.FieldByName('Rec_Acc_Id').asString);
    Query.AddStr(cds.FieldByName('Org_Id').AsString);
    Query.AddStr(cds.FieldByName('Rec_Acc_Id').asString);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    if Xml.documentElement.childNodes.Length = 0 then
    begin
      SetMessage('Лицевой счет у организации получателя из выписки не найден в базе');
      Unclassified := True;
    end
    else begin
      if not isSearchAccount(cds, Xml) then
      begin
        SetMessage('Не удалось получить счет из наименования получателя из выписки');
        Unclassified := True;
      end;
    end;
  end;

  //инициализирует значения отраслевого кода, косгу и кода субсидии
  cds.Edit;
  cds.FieldByName('Industry_Code').AsString := '';
  cds.FieldByName('Industrycode_Id').AsString := '';
  cds.FieldByName('Kesr_Code').AsString := '';
  cds.FieldByName('GrantInvestment_Code').AsString := '';
  cds.FieldByName('Grantinvestment_Id').AsString := '';
  cds.Post;
  FindIndustryGrantInvestCode := 0;
  
  //флаги необходимых номеров в нужных разрядах лицевых счетов
  ls1020 := Copy(cds.FieldByName('Ls_Number').asString, 5, 2) in ['10', '20'];
  ls1121 := Copy(cds.FieldByName('Ls_Number').asString, 5, 2) in ['11', '21'];
  ls1223 :=
    Copy(cds.FieldByName('Ls_Number').asString, 5, 2) in ['12', '13', '22', '23'];
    
  //получает код субсидии
  if (not Unclassified) then
  begin
    if (ls1121) or (ls1020) then
    begin
      if (not isParceDescription(cds, 'код субсидии')) then
      begin
        if ls1121 then
        begin
          SetMessage('Не удалось получить код субсидии из назначения платежа');
          Unclassified := True;
        end;
      end
      else begin
        if StringReplace(cds.FieldByName('GrantInvestment_Code').AsString, '0', '') = '' then
        begin
          SetMessage('В назначении платежа указан нулевой код субсидии');
          Unclassified := True;
        end
        else
          if ls1020 then Inc(FindIndustryGrantInvestCode);
      end;
    end
    else begin
      //если код субсидии указан в других счетах то неклассифицированные
      if isParceDescription(cds, 'код субсидии') then
      begin
        SetMessage('Указан код субсидии в назначении для счетов, у которых' +
          ' в 5 и 6 разряде лс нет значений 10, 11, 20, 21');
        Unclassified := True;
      end
      else begin
        cds.Edit;
        cds.FieldByName('GrantInvestment_Code').AsString := '0';
        cds.Post;
      end;
    end;
  end;
  
  //проверяет код субсидии в базе
  if (not Unclassified) then
  begin
    if cds.FieldByName('GrantInvestment_Code').AsString <> '' then
    begin
      if cds.FieldByName('GrantInvestment_Code').AsString = '0' then
      begin
        //получает Id системного(0-го) кода субсидии и инвестиции
        sql := ' Select Id, FType' +
          ' From GrantInvestment' +
          ' Where Org_Id = 0 and Budget_Id = ? and Code = ?';
        Query.AddStr(cds.FieldByName('Budget_Id').asString);
        Query.AddStr(cds.FieldByName('Grantinvestment_Code').asString);
      end
      else begin
        sql := 'Select G.Id, G.FType' +
          ' From Grantinvestment G' +
          ' Join Org O on O.Manager_Id = G.Org_id' +
          ' Where G.Budget_Id = ? and O.Id = ? and G.Code = ?';
        Query.AddStr(cds.FieldByName('Budget_Id').AsString);
        Query.AddStr(cds.FieldByName('Org_Id').AsString);
        Query.AddStr(cds.FieldByName('Grantinvestment_Code').AsString);
      end;
      Xml := CreateOleObject('Microsoft.XmlDom');
      Xml.LoadXML(Query.Run(sql));
      if Xml.documentElement.childNodes.Length = 1 then
      begin
        cds.Edit;
        cds.FieldByName('Grantinvestment_Id').AsString :=
          Xml.documentElement.childNodes.Item[0].getAttribute('ID');
        cds.FieldByName('Grantinvestment_Type').AsString :=
          Xml.documentElement.childNodes.Item[0].getAttribute('FTYPE');
        cds.Post;
      end
      else begin
        if cds.FieldByName('GrantInvestment_Code').AsString = '0' then
        begin
          SetMessage('Не найден ID системного кода субсидии с нулевым значением');
          Exit;
        end
        else begin
          Unclassified := True;
          SetMessage('Код субсидии: ' + cds.FieldByName('Grantinvestment_Code').AsString
            + ' не найден в базе данных');
        end;
      end;
    end;
  end;
  
  //получает косгу и отраслевой код
  if (not Unclassified) and (cds.FieldByName('Pi_Budget_Code').asString <> '') then
  begin
    //ищет отраслевой код если в 5 и 6 разрядах лс стоит 10, 20, 12, 13, 22, 23
    if (ls1223) or (ls1020) then
    begin
      cds.Edit;
      //отраслевой код
      cds.FieldByName('Industry_Code').AsString :=
        Copy(cds.FieldByName('Pi_Budget_Code').asString, 1, 17);
      //Косгу
      cds.FieldByName('Kesr_Code').AsString :=
        Copy(cds.FieldByName('Pi_Budget_Code').asString, 18, 3);
      cds.Post;
      if ls1020 then Inc(FindIndustryGrantInvestCode);
    end;
  end
  else if (not Unclassified) and (cds.FieldByName('Pi_Budget_Code').asString = '') then
  begin
    if (ls1223) or (ls1020) then
    begin
      if not isParceDescription(cds, 'отр.код') then
      begin
        if ls1223 then
        begin
          SetMessage('Не удалось получить отраслевой код и КОСГУ из назначения платежа');
          Unclassified := True;
        end;
      end
      else begin
        if ls1020 then Inc(FindIndustryGrantInvestCode);
      end;
    end;
  end;
  
  if (not Unclassified) and (ls1020) then
  begin
    if FindIndustryGrantInvestCode <> 1 then
    begin
      Unclassified := True;
      if FindIndustryGrantInvestCode = 0 then
        SetMessage('Не указан ни отраслевой код ни код субсидии  для счетов,' +
          ' у которых в 5 и 6 разряде лс есть значения 10 или 20')
      else
        SetMessage('Указан отраслевой код и код субсидии  для счетов, у которых' +
          ' в 5 и 6 разряде лс есть значения 10 или 20');
    end;
  end;
  
  //проверяет отраслевой код в базе
  if (not Unclassified) then
  begin
    if cds.FieldByName('Industry_Code').AsString <> '' then
    begin
      sql := 'Select I.Id' +
        ' From IndustryCode I' +
        ' Join Org O on O.Manager_Id = I.Org_id' +
        ' Where I.Budget_Id = ? and O.Id = ? and I.Code = ?' +
        ' Union Select I.Id' +
        ' From IndustryCode I' +
        ' Where I.Budget_Id = ? and I.Org_Id = 0 and I.Code = ?';
      Query.AddStr(cds.FieldByName('Budget_Id').AsString);
      Query.AddStr(cds.FieldByName('Org_Id').AsString);
      Query.AddStr(cds.FieldByName('Industry_Code').AsString);
      Query.AddStr(cds.FieldByName('Budget_Id').AsString);
      Query.AddStr(cds.FieldByName('Industry_Code').AsString);
      Xml := CreateOleObject('Microsoft.XmlDom');
      Xml.LoadXML(Query.Run(sql));
      if Xml.documentElement.childNodes.Length = 1 then
      begin
        cds.Edit;
        cds.FieldByName('Industrycode_Id').AsString :=
          Xml.documentElement.childNodes.Item[0].getAttribute('ID');
        cds.Post;
      end
      else begin
        SetMessage('Отраслевой код ' + cds.FieldByName('Industry_Code').AsString
          + ' не найден в базе');
        Unclassified := True;
      end;
    end;
  end;
  
  //косгу
  if (not Unclassified) then
  begin
    if cds.FieldByName('Kesr_Code').AsString = '' then
    begin
      cds.Edit;
      cds.FieldByName('Kesr_Code').AsInteger := 180;
      cds.Post;
    end
    else begin
      //перевод полученного КОСГУ в число.
      cds.Edit;
      try
        cds.FieldByName('Kesr_Code').AsInteger :=
          StrToInt(StringReplace(cds.FieldByName('Kesr_Code').AsString, ' ', ''));
        if cds.FieldByName('Kesr_Code').AsInteger = 0 then
        begin
          cds.FieldByName('ResText').AsString := 'Получен нулевой КОСГУ';
          Unclassified := True;
        end;
      except
        cds.FieldByName('Kesr_Code').AsInteger := 0;
        cds.FieldByName('ResText').AsString :=
          'Не удалось преобразовать КОСГУ в числовой тип';
        Unclassified := True
      end;
      cds.Post;
    end;
  end;
  //проверка косгу в базе
  if (not Unclassified) then
  begin
    sql := 'Select Id From Kes Where Budget_Id = ? and Code = ?';
    Query.AddStr(cds.FieldByName('Budget_Id').AsString);
    Query.AddStr(cds.FieldByName('Kesr_Code').AsString);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    if Xml.documentElement.childNodes.Length <> 1 then
    begin
      SetMessage('КОСГУ: ' + cds.FieldByName('Kesr_Code').AsString
        + ' не найден в базе данных');
      Unclassified := True;
    end;
  end;
  
  //квфо
  if (not Unclassified) then
  begin
    //проверяем найденные счет и отраслевой код подпадает под маски
    sql := 'Select Accountnumber_Mask, Industrycode_Mask, Fsr_Id' +
      ' From AubuclassifiersRules';
    if (cds.FieldByName('Grantinvestment_Code').AsString <> '0')
      and (cds.FieldByName('Grantinvestment_Code').AsString <> '') then
    begin
      sql := sql + ' Where GrantinvestmentType = ?';
      Query.AddStr(cds.FieldByName('Grantinvestment_Type').AsString);
    end;
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    Xml := Xml.documentElement;
    isOneMask := False;
    for i := 0 to Xml.childNodes.Length - 1 do
    begin
      Xml := Xml.childNodes.Item[i];
      if cds.FieldByName('Industrycode_Id').AsString = '' then
      begin
        if (MatchesMask(cds.FieldByName('LS_Number').asString,
          Xml.getAttribute('ACCOUNTNUMBER_MASK'))) then
          if not isOneMask then
          begin
            isOneMask := True;
            cds.Edit;
            cds.FieldByName('Fsr_Id').AsString := Xml.getAttribute('FSR_ID');
            cds.Post;
          end
          else begin
            isOneMask := False;
            SetMessage('Маска счета не совпадает с правилом соответствия классификаторов');
            Break;
          end;
      end
      else begin
        if (MatchesMask(cds.FieldByName('LS_Number').asString,
          Xml.getAttribute('ACCOUNTNUMBER_MASK')))
            and (MatchesMask(cds.FieldByName('Industry_Code').asString,
              Xml.getAttribute('INDUSTRYCODE_MASK'))) then
          if not isOneMask then
          begin
            isOneMask := True;
            cds.Edit;
            cds.FieldByName('Fsr_Id').AsString := Xml.getAttribute('FSR_ID');
            cds.Post;
          end
          else begin
            isOneMask := False;
            SetMessage('Маски счета и отраслевого кода не совпадают с правилом' +
              ' соответствия классификаторов');
            Break;
          end;
      end;
      Xml := Xml.parentNode;
    end;
    Unclassified := not isOneMask;
    if Unclassified then
    begin
      if (cds.FieldByName('Grantinvestment_Code').AsString <> '0')
        and (cds.FieldByName('Grantinvestment_Code').AsString <> '') then
        SetMessage('Не найдены правила соответствия классификаторов' +
          ' по типу Кода субсидии или маска счета не совпадает с полученными' +
          ' правилами')
      else
        SetMessage('Не найдены правила соответствия классификаторов' +
          ' или маска счета не совпадает с полученными правилами');
    end;
  end;
  
  //формирование данных неклассифицированых поступлений
  if Unclassified then
  begin
    //получает лс и организацию для некласифицированных поступлений
    sql := 'Select O.Id Unclass_Org_Id, O.Taxcode Unclass_Org_Taxcode,' +
      '   O.Kpp Unclass_Org_Kpp, O.Description Unclass_Org_Name, Oa.Id Ls_Id,' +
      '   Oa.Account_Number Ls_Number' +
      ' From Payorder P' +
      ' Join BudgetOrgAccount B on P.Rec_Acc_Id = B.OrgAccount_Id' +
      '   and P.Budget_Id = B.Budget_Id' +
      ' Join OrgAccount Oa on Oa.Id = B.Unclassified_Id' +
      ' Join Org O on O.Id = Oa.Org_Id' +
      ' Where P.Id = ? and B.BudgetOrgAccountType_Id = 1';
    Query.AddStr(cds.FieldByName('Id').asString);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    Xml := Xml.documentElement.childNodes;
    if (Xml.Length = 1) and (Xml.Item[0].getAttribute('LS_ID') <> '') then
    begin
      cds.Edit;
      cds.FieldByName('Unclass_Org_Id').asString :=
        Xml.Item[0].getAttribute('UNCLASS_ORG_ID');
      cds.FieldByName('Unclass_Org_Taxcode').asString :=
        Xml.Item[0].getAttribute('UNCLASS_ORG_TAXCODE');
      cds.FieldByName('Unclass_Org_Kpp').asString :=
        Xml.Item[0].getAttribute('UNCLASS_ORG_KPP');
      cds.FieldByName('Unclass_Org_Name').asString :=
        Xml.Item[0].getAttribute('UNCLASS_ORG_NAME');
      cds.FieldByName('Ls_Id').asString :=
        Xml.Item[0].getAttribute('LS_ID');
      cds.FieldByName('Ls_Number').asString :=
        Xml.Item[0].getAttribute('LS_NUMBER');
      cds.Post;
    end
    else begin
      SetMessage('Зачисление неклассифицированных, причина: ' +
        cds.FieldByName('ResText').asString +
        '. Контроль не пройден: Не заполнен лицевой счет для учета' +
        ' невыясненных');
      Exit;
    end;
    //получает данные по кодам для неклассифицированных из системных параметров
    Xml := GetValueFromSysparam('aubu.unclassified.rules.' +
      cds.FieldByName('Budget_Id').asString);
    if VarIsNull(Xml) then
    begin
      SetMessage('Зачисление неклассифицированных, причина: ' +
        cds.FieldByName('ResText').asString +
        '. Контроль не пройден: Не задана настройка классификации для' +
        ' невыясненных');
      Exit;
    end;
    if (Xml.documentElement.getAttribute('KESR_CODE') <> '')
      and (Xml.documentElement.getAttribute('INDUSTRYCODE_ID') <> '')
      and (Xml.documentElement.getAttribute('FSR_ID') <> '') then
    begin
      cds.Edit;
      cds.FieldByName('Kesr_Code').AsString :=
        Xml.documentElement.getAttribute('KESR_CODE');
      cds.FieldByName('Industrycode_Id').AsString :=
        Xml.documentElement.getAttribute('INDUSTRYCODE_ID');
      cds.FieldByName('Fsr_Id').AsString :=
        Xml.documentElement.getAttribute('FSR_ID');
      cds.Post;
    end
    else begin
      SetMessage('Зачисление неклассифицированных, причина: ' +
        cds.FieldByName('ResText').asString +
        '. Контроль не пройден: Не заполнена настройка классификации для' +
        ' невыясненных');
      Exit;
    end;
    //получает Id системного(0-го) кода субсидии и инвестиции
    sql := ' Select Id' +
      ' From GrantInvestment' +
      ' Where Org_Id = 0 and Budget_Id = ? and Code = ''0''';
    Query.AddStr(cds.FieldByName('Budget_Id').asString);
    Xml := CreateOleObject('Microsoft.XmlDom');
    Xml.LoadXML(Query.Run(sql));
    if Xml.documentElement.childNodes.Length = 1 then
    begin
      cds.Edit;
      cds.FieldByName('Grantinvestment_Id').AsString :=
        Xml.documentElement.childNodes.Item[0].getAttribute('ID');
      cds.Post;
    end
    else begin
      SetMessage('Зачисление неклассифицированных, причина: ' +
        cds.FieldByName('ResText').asString +
        '. Контроль не пройден: Не найден ID системного кода субсидии с' +
        ' нулевым значением');
      Exit;
    end;
    cds.Edit;
    cds.FieldByName('Enroll').AsInteger := 1;
    cds.FieldByName('Unclassified').AsInteger := 1;
    cds.Post;
    SetMessage('Зачисление неклассифицированных, причина: ' +
      cds.FieldByName('ResText').asString);
    Result := True;
  end
  else begin
    cds.Edit;
    cds.FieldByName('Enroll').AsInteger := 1;
    cds.FieldByName('Unclassified').AsInteger := 0;
    cds.Post;
    SetMessage('Контроль пройден');
    Result := True;
  end;
end;

function ObjectName: String;
begin
  Result := 'ДФ г. Екатеринбурга';
end; {End ObjectName}

//Ищет Id л/с. По номеру счета ищем его вхождение
//в наименование получателя из выписки.
//Нашли - вернули True и Id записали в cds LS_ID, иначе вернули False.
function isSearchAccount(cds: TClientDataSet; Xml: Variant): Boolean;
var
  i: Integer;
  isFound: Boolean;
begin
  Result := False;
  cds.Edit;
  cds.FieldByName('LS_ID').asString := '';
  cds.Post;
  Xml := Xml.documentElement;
  isFound := False;
  //ищем в наименовании получателя из выписки
  for i := 0 to Xml.ChildNodes.Length - 1 do
  begin
    Xml := Xml.ChildNodes.Item[i];
    isFound := Pos(Xml.getAttribute('ACCOUNT_NUMBER'),
      cds.FieldByName('Org_Name').asString) > 0;
    if (not Result) and (isFound) then
    begin
      Result := True;
      cds.Edit;
      cds.FieldByName('LS_ID').asString := Xml.getAttribute('ID');
      cds.FieldByName('LS_Number').asString := Xml.getAttribute('ACCOUNT_NUMBER');
      cds.Post;
    end
    else if isFound then
    begin
      //нашелся дубль
      Result := False;
      cds.Edit;
      cds.FieldByName('LS_ID').asString := '';
      cds.FieldByName('LS_Number').asString := '';
      cds.Post;
      Xml := Xml.parentNode;
      Break;
    end;
    Xml := Xml.parentNode;
  end;
  Xml := Xml.ownerDocument;
end;

//разбирает основание платежа.
//параметры:
//cds - набор данных
//keyword - ключевое слово
//MustBeSpace - должен быть пробел между ключевым словом и значением
//если в основании платежа не встречаются ключевые слова или встречаются более
//одного раза то False. В зависимости от ключевого слова заполняются поля в наборе
//данных
function isParceDescription(cds: TClientDataSet; Keyword: String;
  MustBeSpace: Boolean = True): Boolean;
var
  i, DescLength, offsetKeyword: Integer;
  Description, Code: String;
begin
  Result := False;
  Code := '';
  Description := cds.FieldByName('Description').asString;
  DescLength := Length(Description);
  if MustBeSpace then
    offsetKeyword := Length(Keyword) + 1
  else
    offsetKeyword := Length(Keyword);
  Keyword := LowerCase(Keyword);
  i := Pos(Keyword, LowerCase(Description));
  if (i > 0) and
    (Pos(Keyword, Copy(LowerCase(Description), i + 1, DescLength - i)) > 0) then
    //дубль
    Exit
  else if i > 0 then
  begin
    //увеличиваем индекс на длину ключевого слова (+ пробел в зависимости от MustBeSpace)
    i := i + offsetKeyword;
    if MustBeSpace then
    begin
      //между ключевым словом и кодом должен быть пробел
      if (i <= DescLength) and (Description[i - 1] = ' ') then
        while (i <= DescLength) and (Description[i] <> ' ') do
        begin
          Code := Code + Description[i];
          inc(i);
        end;
    end
    else begin
      while (i <= DescLength) and (Description[i] <> ' ') do
      begin
        Code := Code + Description[i];
        inc(i);
      end;
    end;
  end;
  Result := Code <> '';
  if Result then
  begin
    case Keyword of
      'код субсидии':
        begin
          cds.Edit;
          cds.FieldByName('GrantInvestment_Code').asString := Code;
          cds.Post;
        end;
      'отр.код':
        begin
          cds.Edit;
          cds.FieldByName('Industry_Code').asString := Copy(Code, 1, 17);
          cds.FieldByName('Kesr_Code').asString := Copy(Code, 18, 3);
          cds.Post;
        end;
      'косгу':
        begin
          cds.Edit;
          cds.FieldByName('Kesr_Code').asString := Copy(Code, 1, 3);
          cds.Post;
        end;
    end;
  end;
end;

//получает данные по кодам невыясненных поступлений из системных параметров
function GetValueFromSysparam(param_name: String): Variant;
var
  Xml: Variant;
begin
  Result := null;
  Xml := CreateOleObject('Microsoft.XmlDom');
  Xml := Xml.appendChild(Xml.createElement('EXCH_UTILS_PROCESSOR'));
  Xml.setAttribute('action', 'get_sys_param_value');
  Xml := Xml.appendChild(Xml.ownerDocument.createElement('SYSPARAM'));
  Xml.setAttribute('NAME', param_name);
  Xml := Xml.ownerDocument;
  Xml.loadXml(ExecXml(Xml.xml));
  Xml := Xml.getElementsBytagName('PARAM_VALUE');
  if Xml.length = 1 then
  begin
    Result := CreateOleObject('Microsoft.XmlDom');
    Result.loadXml(Xml.items[0].firstChild.data);
  end;
end;

begin
end.