//Exchange #2325
function CheckPayOrder(cds: TClientDataSet; IniPath: String): Boolean;
var
  sql: String;
  Xml: Variant;
  i: Integer;
  Unclassified, isOneMask, ls1_flag, ls2_flag: 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';
    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;

  //получает отраслевой код, КОСГУ и код субсидии из назначения платежа
  if not Unclassified then
  begin
    //если счет плательщика равен 40204810100000000351, то после слова КОД, иначе сначала назначения
    if Copy(cds.FieldByName('Pay_Account').asString, 1, 20) = '40204810100000000351' then
    begin
      if not isParceDescription(cds, 'КОД') then
      begin
        SetMessage('Не удалось получить отраслевой код и КОСГУ из назначения платежа');
        Unclassified := True;
      end;
    end
    else begin
      cds.Edit;
      cds.FieldByName('Industry_Code').asString := Copy(cds.FieldByName('Description').asString, 1, 17);
      cds.FieldByName('Kesr_Code').asString := Copy(cds.FieldByName('Description').asString, 18, 3);
      cds.FieldByName('GrantInvestment_Code').AsString := Copy(cds.FieldByName('Description').asString, 14, 4);
      cds.Post;
    end;
  end;

  //проверяем полученные коды
  if not Unclassified then
  begin
    // отраслевой код
    //проверка отраслевого кода на 17 нулей и пустоту
    if (StringReplace(cds.FieldByName('Industry_Code').AsString, '0', '') = '')
      or (Trim(cds.FieldByName('Industry_Code').AsString) = '') then
    begin
      SetMessage('Не удалось получить отраслевой код или отраслевой код равен 0');
      Unclassified := True;
    end
    else 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
    cds.Edit;
    try
      cds.FieldByName('Kesr_Code').asInteger :=
        StrToInt(StringReplace(cds.FieldByName('Kesr_Code').asString, ' ', ''));
    except
      cds.FieldByName('Kesr_Code').asInteger := 0;
      cds.FieldByName('ResText').AsString :=
        'Не удалось преобразовать КОСГУ в числовой тип';
      Unclassified := True;
    end;
    cds.Post;
  end;
  if (not Unclassified) then
    if cds.FieldByName('Kesr_Code').AsInteger = 0 then
    begin
      SetMessage('Получен нулевой КОСГУ');
      Unclassified := True;
    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
    //проверка отраслевого кода на 17 нулей и пустоту
    if (StringReplace(cds.FieldByName('GrantInvestment_Code').AsString, '0', '') = '')
      or (Trim(cds.FieldByName('GrantInvestment_Code').AsString) = '') then
    begin
      SetMessage('Не удалось получить код субсидии или код субсидии равен 0');
      Unclassified := True;
    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);
      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
        SetMessage('Код субсидии: ' + cds.FieldByName('Grantinvestment_Code').AsString
          + ' не найден в базе данных');
        Unclassified := True;
      end;
    end;
  end;
  //КВФО
  if not Unclassified then
  begin
    //проверяем найденные счет и отраслевой код подпадает под маски
    sql := 'Select Accountnumber_Mask, Industrycode_Mask, Fsr_Id' +
      ' From AubuclassifiersRules';
    if cds.FieldByName('Grantinvestment_Code').AsString <> '0' 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 (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;
      Xml := Xml.parentNode;
    end;
    Unclassified := not isOneMask;
    if Unclassified then
    begin
      if cds.FieldByName('Grantinvestment_Code').AsString <> '0' 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 - ключевое слово
//если в основании платежа не встречаются ключевые слова или встречаются более
//одного раза то False. В зависимости от ключевого слова заполняются поля в наборе
//данных
function isParceDescription(cds: TClientDataSet; Keyword: String): Boolean;
var
  i, DescLength, offsetKeyword: Integer;
  Description, Code: String;
begin
  Result := False;
  Code := '';
  Description := cds.FieldByName('Description').asString;
  DescLength := Length(Description);
  offsetKeyword := Length(Keyword);
  i := Pos(Keyword, Description);
  if (i > 0) and
    (Pos(Keyword, Copy(Description, i + 1, DescLength - i)) > 0) then
    //дубль
    Exit
  else if i > 0 then
  begin
    //увеличиваем индекс на длину ключевого слова
    i := i + offsetKeyword;
    Code := Code + Copy(Description, i, 20);
  end;
  Result := Code <> '';
  if Result then
  begin
    cds.Edit;
    cds.FieldByName('Industry_Code').asString := Copy(Code, 1, 17);
    cds.FieldByName('GrantInvestment_Code').asString := Copy(Code, 14, 4);
    cds.FieldByName('Kesr_Code').asString := Copy(Code, 18, 3);
    cds.Post;
  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.