Problema para identificar produto com custo diferente se o valor tiver casas decimais.

PostgreSQL

Delphi

15/01/2021

Em um sistema de terceiro, existe uma condição no cadastro do produto que pode ser vinculado vários produtos por um grupo, e todos os produtos deste grupo vão ter o mesmo preço de custo e venda. Porém existe um bug que permite que exista preço de custo ou venda diferentes dentro do grupo. Então o que eu estou fazendo é tentar identificar os grupos que tem produtos com custo e venda diferentes para corrigir manualmente depois.

O que eu estou fazendo.

Fiz uma query que busca todos os grupos na tabela.
Em outra query eu trago os produtos que pertencem ao primeiro registro da query anterior.
A variável custo recebe o custo de todos os produtos do grupo. (Se tiver 5 produtos com o custo R$2,00 o valor da variável custo será R$10,00).
A variável i sempre soma + 1; então o valor dela sempre será a quantidade de produtos.
Se eu dividir o custo pela quantidade de produtos 10 / 5 o resultado será 2.

Então eu comparo a variável custo com o valor do produto na query se ele for diferente o produto tem erro... se não está certo..., porém do jeito que eu fiz ele traz como resultado 2990 grupos com erro, e no sistema existe 3361 grupos. Confiro manualmente e maioria está correta. O que eu observei foi que os produtos que tem valores inteiros ele calcula certo... os valores que tem casa decimal todos ele marca como erro.

Já usei variável double e currency, select com e sem cast, usei o formatfloat e também não tive sucesso. Alguém poderia me ajudar?

Estou usando Delphi 10.3 / PostgreSQL 9.6.9 / TFDQuery

var Custo,Venda : Double; i : Integer;
begin
    MemoCusto.Clear;
    MemoVenda.Clear;
    MemoCusto.Lines.Add('Problema no Preço Referencial');
    MemoVenda.Lines.Add('Problema no Preço de Venda');
    with qryGrupo do begin
      Close;
      Open('SELECT id,nome FROM gruporemarcacao');
      Active:=True;
      First;
    end;
    while not qryGrupo.EOF do begin
      with qryProduto do begin
        Close;
        Open('SELECT etiqueta,CAST(precoreferencial AS DECIMAL(6,2)),CAST(precovenda AS DECIMAL(6,2)) FROM embalagem WHERE gruporemarcacaoid = ' + qryGrupo.Fields[0].Text);
        //Open('SELECT etiqueta,precoreferencial,precovenda FROM embalagem WHERE gruporemarcacaoid = ' + qryGrupo.Fields[0].Text);
        Active:=True;
        First;
      end;
      Custo:=0;
      Venda:=0;
      i:=0;
      while not qryProduto.Eof do begin
        i:=i+1;
        Custo:= Custo + StrToFloat(qryProduto.Fields[1].Text);
        qryProduto.Next;
      end;
      Custo:= Custo / i;
      if Custo <> StrToFloat(qryProduto.Fields[1].Text) then begin
        MemoCusto.Lines.Add(qryGrupo.Fields[1].Text);
      end;
      qryGrupo.Next;
    end;
    StatusBar1.Panels[1].Text:=IntToStr(MemoCusto.Lines.Count-1) + ' Grupos com problema de custo';
end;
Paulo

Paulo

Curtidas 0

Respostas

Emerson Nascimento

Emerson Nascimento

15/01/2021

não precisa fazer todo esse cálculo. basta procurar por valores diferentes.

a forma abaixo já avalia as duas condições (custo e venda) com uma performance muito melhor do que fazer o cálculo da forma como estava sendo feito.
var
	strGrupo: string;
begin
    MemoCusto.Clear;
    MemoCusto.Lines.Add('Problema no Preço Referencial');

    MemoVenda.Clear;
    MemoVenda.Lines.Add('Problema no Preço de Venda');

    with qryGrupo do
	begin
      Close;
      SQL.Text := 'SELECT gr.id, gr.nome, '+
	              ' COUNT(DISTINCT CAST(e.precoreferencial AS DECIMAL(15,2))) precoref, '+
				  ' COUNT(DISTINCT CAST(e.precovenda AS DECIMAL(15,2))) precoven '+
	              'FROM gruporemarcacao gr '+
                  'INNER JOIN embalagem e ON e.gruporemarcacaoid = gr.id '+
                  'GROUP BY gr.id, gr.nome '+
                  'HAVING (COUNT(DISTINCT CAST(e.precoreferencial AS DECIMAL(15,2))) > 1) '+
                  'OR (COUNT(DISTINCT CAST(e.precovenda AS DECIMAL(15,2))) > 1) ';
      Open;

      // só haverá registros se algum preço estiver diferente, então não precisa condicionar
      while not EOF do
      begin
		strGrupo := FieldByName('nome').Text;
		
		// avalia o preco de custo
		if FieldByName('precoref').AsInteger > 1 then
			MemoCusto.Lines.Add(strGrupo);

		// avalia o preco de venda
		if FieldByName('precoven').AsInteger > 1 then
			MemoVenda.Lines.Add(strGrupo);

        Next;
      end;
    end;

    StatusBar1.Panels[1].Text := IntToStr(MemoCusto.Lines.Count-1) + ' grupos com problema de custo';
//    StatusBar1.Panels[2].Text := IntToStr(MemoVenda.Lines.Count-1) + ' grupos com problema de venda';
end;

GOSTEI 0
Paulo

Paulo

15/01/2021

Emerson realmente sua logica ficou muito melhor e mais simples... eu não tinha pensado em algo parecido, meu muito obrigado seu código funcionou perfeitamente e sua logica me deu uma visão diferente para o problema.

Obrigado, forte abraço.

Problema resolvido!

não precisa fazer todo esse cálculo. basta procurar por valores diferentes.

a forma abaixo já avalia as duas condições (custo e venda) com uma performance muito melhor do que fazer o cálculo da forma como estava sendo feito.
var
	strGrupo: string;
begin
    MemoCusto.Clear;
    MemoCusto.Lines.Add('Problema no Preço Referencial');

    MemoVenda.Clear;
    MemoVenda.Lines.Add('Problema no Preço de Venda');

    with qryGrupo do
	begin
      Close;
      SQL.Text := 'SELECT gr.id, gr.nome, '+
	              ' COUNT(DISTINCT CAST(e.precoreferencial AS DECIMAL(15,2))) precoref, '+
				  ' COUNT(DISTINCT CAST(e.precovenda AS DECIMAL(15,2))) precoven '+
	              'FROM gruporemarcacao gr '+
                  'INNER JOIN embalagem e ON e.gruporemarcacaoid = gr.id '+
                  'GROUP BY gr.id, gr.nome '+
                  'HAVING (COUNT(DISTINCT CAST(e.precoreferencial AS DECIMAL(15,2))) > 1) '+
                  'OR (COUNT(DISTINCT CAST(e.precovenda AS DECIMAL(15,2))) > 1) ';
      Open;

      // só haverá registros se algum preço estiver diferente, então não precisa condicionar
      while not EOF do
      begin
		strGrupo := FieldByName('nome').Text;
		
		// avalia o preco de custo
		if FieldByName('precoref').AsInteger > 1 then
			MemoCusto.Lines.Add(strGrupo);

		// avalia o preco de venda
		if FieldByName('precoven').AsInteger > 1 then
			MemoVenda.Lines.Add(strGrupo);

        Next;
      end;
    end;

    StatusBar1.Panels[1].Text := IntToStr(MemoCusto.Lines.Count-1) + ' grupos com problema de custo';
//    StatusBar1.Panels[2].Text := IntToStr(MemoVenda.Lines.Count-1) + ' grupos com problema de venda';
end;

GOSTEI 0
POSTAR