Jump to content
Fórum Script Brasil
  • 0

(Resolvido) Relatório Composto


robinhocne

Question

Boa tarde a todos,

Sempre tenho dificuldades em relatórios, aparentemente algo simples, mas não consigo:

Estou tentando fazer um relatório com quebra por cliente e os detalhes das parcelas deles;

Eu utilizo o Delphi 7, BD Firebird e para fazer relatório o Quick Report 4.05.

No relatório eu preciso mostrar assim:

-------------------------------------------------------------

Relatório de Contas á Receber

-------------------------------------------------------------

Cliente : Robinho Telefone : 00-0000-0000

E-mail : robinho@relatorio.com

Parcela Vencimento Valor

-------------------------------------------------------------

1ª Parcela 10/01/2012 150,36

2ª Parcela 10/02/2012 150,36

3ª Parcela 10/03/2012 150,36

4ª Parcela 10/04/2012 150,36

Total de Parcelas : 4 Valor Total : 601,44

-------------------------------------------------------------

Cliente : Joao Telefone : 00-0000-0000

E-mail : joao@relatorio.com

Parcela Vencimento Valor

-------------------------------------------------------------

3ª Parcela 15/01/2012 201,00

4ª Parcela 15/02/2012 201,00

5ª Parcela 15/03/2012 201,00

Total de Parcelas : 3 Valor Total : 603,00

-------------------------------------------------------------

Cliente : Maria Telefone : 00-0000-0000

E-mail : maria@relatorio.com

Parcela Vencimento Valor

-------------------------------------------------------------

1ª Parcela 17/02/2012 85,00

2ª Parcela 17/03/2012 85,00

3ª Parcela 17/04/2012 85,00

Total de Parcelas : 3 Valor Total : 255,00

-------------------------------------------------------------

e assim vai pelo total de clientes que vier da pesquisa.....no final um totalizador...

-------------------------------------------------------------

Total de Parcelas : 10 Valor Total : 1.459,44

Para ligar o BD com o sistema eu utilizo um IBTable, IBTransaction e IBQuery.

para consultar o Relatório eu utilizo uma IBQuery1 que está ligado ao IBTable:

Eu fiz assim:

O DataSet do relatório está ligado ao IBQuery1 e os seus respectivos campos;

-------------------------------------------------------------

**rbTitle**

Relatório de Contas á Receber

-------------------------------------------------------------

**rbDetail**

Cliente : Robinho Telefone : 00-0000-0000

E-mail : robinho@relatorio.com

Parcela Vencimento Valor

-------------------------------------------------------------

**rbSubDetail**

**FooterBand ligado com o rbGroupFooter**

1ª Parcela 10/01/2012 150,36

2ª Parcela 10/02/2012 150,36

3ª Parcela 10/03/2012 150,36

4ª Parcela 10/04/2012 150,36

-------------------------------------------------------------

**rbGroupFooter**

Total de Parcelas : 4 Valor Total : 601,44

-------------------------------------------------------------

e assim vai pelo total de clientes que vier da pesquisa.....no final um totalizador...

-------------------------------------------------------------

**rdSummary**

Total de Parcelas : 10 Valor Total : 1.459,44

mas ai sai só um cliente

e as parcelas dele não tem nada haver....já vi o Demo do Quick, tentei segui mas não consegui.....

Uma ajuda ai......

Edited by robinhocne
Link to comment
Share on other sites

14 answers to this question

Recommended Posts

  • 0

Olá robinhocne.

Montar relatórios no Quick Report é mesmo muito simples. Voce apenas tem que tentar captar a ideia de como as coisas se encadeiam lá - e é muito parecido com a estrutura do relacionamento de suas tabelas. Logo, se voce montar elas corretamente, montará seu relatório também.

Olhe esta figura:

relaciona2py4.png

Voce diz que está usando um IBTable e um IBQuery e que o DataSet do relatório está ligado ao IBQuery1.

Isto me leva a pensar que você vinculou todos os campos do seu relatório aos campos existentes no IBQuery1. Não é que você não possa fazer tudo em uma única consulta, mas dai você tem que ter mais atenção a como isto deverá ser desmenbrado no relatório - se via usar subdetail ou group band.

A forma mais simples de você montá-lo (e entendê-lo) é seguindo a estrutura do banco de dados. Isso implicar em usar mais datasets, mas facilitará a compreensão.

Assim, o dataset principal (no seu caso, aquele que trará tantos clientes quanto você deseje) é aquele ligado ao QuickRep. Quando você adiciona uma Detail band, o quickreport irá imprimí-la para cada linha deste dataset.

Seguindo a estrutura de dados do banco, as tabelas relacionadas à esta utilizada no dataset principal serão aquelas a serem colocadas nos agrupamentos abaixo da detail band.

No seu caso, voce teria uma consulta que estaria buscando as informações da tabela parcelas utilizando como filtro a tabela principal. Voce pode fazer isto ustilizando a ligação via DataSource (acredito que você entanda do que estou falando). Estas informações seriam mostradas no seu relatório utilizando uma banda subdetail.

Dê também uma lida neste post e veja se ele lhe ajuda um pouco mais a entender o que quero dizer. Depois que você pegar a filosofia da coisa, você não vai mais ter problemas com relatório. ;)

Link to comment
Share on other sites

  • 0

Micheus, estou quase conseguindo de acordo com suas dicas.....

Eu consulto o relatorio dessa maneira:

procedure TFrmLisRelCtaReceber.ConsultaRelatorio;
begin

  SQLCondicao  := '';

  SQLInstCli   := 'Select A.CodCli, A.NomCli From Contas_Receber A';


  SQLInstrucao := 'Select A.CodCli, A.Parcela, A.Vencimento, A.Receber, A.Recebido, A.Valor From Contas_Receber A';

  {Faz o filtro de data de vencimento ...}
  if ((TxtDtVenIni.Text <> '  /  /    ') or (TxtDtVenFin.Text <> '  /  /    ')) then
    begin

      if SQLCondicao = '' then
        begin
          SQLCondicao := ' where A.Vencimento Between (' +#39+ FormatDateTime('dd.mm.yyyy', TxtDtVenIni.Date) + #39 + ') and ' +
                                                     '(' +#39+ FormatDateTime('dd.mm.yyyy', TxtDtVenFin.Date) + #39 + ') ';
        end
        else
        begin
          SQLCondicao := ' and A.Vencimento Between (' +#39+ FormatDateTime('dd.mm.yyyy', TxtDtVenIni.Date) + #39 + ') and ' +
                                                   '(' +#39+ FormatDateTime('dd.mm.yyyy', TxtDtVenFin.Date) + #39 + ') ';
        end;

    end;
  {... Faz o filtro de data de vencimento}


  {Busca os Clientes ...}
  SQLInstCli := SQLInstCli + SQLCondicao + ' and A.SituBaixado = '+#39+'N'+#39+' group by A.CodCli, A.NomCli';

  with QryRec do
    begin
      close;
      sql.Clear;
      sql.Add(SQLInstCli);
      open;
    end;

  TblCli.Close;
  TblCli.Active := true;
  while not QryRec.Eof do
    begin

      with TblCli do
        begin
          insert;
          TblCliCliente.AsString := QryRec.FieldByName('CodCli').AsString;
          TblCliNome.AsString    := QryRec.FieldByName('NomCli').AsString;
          post;
        end;

      QryRec.Next;
    end;

  Memo1.Text := SQLInstCli;

  TblCli.SortOnFields('Cliente', true, false);
 {... Busca os Clientes}



  {Busca as Parcelas ...}
  SQLInstrucao := SQLInstrucao + SQLCondicao + ' and A.SituBaixado = '+#39+'N'+#39;

  with QryRec do
    begin
      close;
      sql.Clear;
      sql.Add(SQLInstrucao);
      open;
    end;
 {... Busca as Parcelas}



end;

na tabela temporária TblCli eu coloquei o código do cliente e nome do cliente e na Query QryRec está as parcelas, mas ao listar no relatório está saindo misturando as parcelas dos clientes, na imagem abaixo veja que a parcela do Robson saiu para a Deise e vice versa.

Coloquei assim:

------------------

rbTitle

-----------------

rdDetail

----------------

rdSubDetail

DataSet: QryRec

FooterBand : GroupFooterBand1

Master: QuickRep

------------------

rbGroupFooter

LinkBand : QRSubDetail1

------------------

TOTAL GERAL ?

Sem_ttulo.png

Imagem?

Link to comment
Share on other sites

  • 0

robinhocne, antes de comentar qualquer coisa, vou lhe perguntar: este código é o que você está usando mesmo ou você removeu alguma parte dele (sem problemas - eu só preciso saber para dar mais ou menos pitacos ;))

E uma pergunta que já precisarei de uma resposta: Observei que nas suas consultas, voce sempre usa a tabela Contas_Receber. É isto mesmo? Voce tem todas as informações na mesma tabela?

Link to comment
Share on other sites

  • 0

robinhocne, antes de comentar qualquer coisa, vou lhe perguntar: este código é o que você está usando mesmo ou você removeu alguma parte dele (sem problemas - eu só preciso saber para dar mais ou menos pitacos ;))

É esse código mesmo Micheus.

E uma pergunta que já precisarei de uma resposta: Observei que nas suas consultas, voce sempre usa a tabela Contas_Receber. É isto mesmo? Voce tem todas as informações na mesma tabela?

Sim, a minha tabela Contas_Receber tem o codigo do cliente e nome também, além das informações da parcela, valor, vencimento, recebido, receber...etc.

Link to comment
Share on other sites

  • 0
É esse código mesmo Micheus.
Bom, neste caso...

Observe que você inicializa -> SQLCondicao := '';

e não muda ela antes de chegar no -> if SQLCondicao = '' then

logo, este if será sempre validado.

O if anterior -> if ((TxtDtVenIni.Text <> ' / / ') or (TxtDtVenFin.Text <> ' / / ')) then

está permitindo que um dos valores seja nulo, porque você está usando um OR e não um AND. A menos que você possa realmente informar apenas uma data no período, isto deveria ser corrigido. Neste caso, a montagem da string (concatenação) deveria levar isto em conta, pois se uma das datas pode ser nula, então ela não deveria ser incluída no filtro.

Voce provavelmente estaria filtrando um perído (between), ou datas maiores que a inicial (>=) ou as menores que a final (<=)

Dê uma avaliada nisto.

Sim, a minha tabela Contas_Receber tem o codigo do cliente e nome também, além das informações da parcela, valor, vencimento, recebido, receber...etc.
Como voce tem todas as informações em uma única tabela, no meu entender, é desnecessário muito do que você está usando.

Basicamente a sua consulta é apenas esta:

Select A.CodCli, A.NomCli, A.Parcela, A.Vencimento, A.Receber, A.Recebido, A.Valor 
From Contas_Receber A
where A.Vencimento Between <dd.mm.yyyy> and <dd.mm.yyyy>
order by A.NomCli

Em uma modelagem de dados usual, as informações do cliente estariam em outra tabela e você faria a ligação entre elas utilizando CodCli.

Esta consulta estará trazendo repetidamente o CodCli e NomCli, enquanto que os outros campos (pela lógica) devem ser diferentes. Assim, para montar este relatório utilizando o QuickReport, voce irá precisar apenas de uma group band e uma detail.

O dataset (que nesta configuração seria apenas 1) seria vinculado ao QuickRep; Na group band, voce deverá indicar o campo de quebra que neste caso será o CodCli e nela voce adiciona o CodCli e NomCli a serem impressos.

Na banda detalhe voce coloca os demais campos referentes às parcelas.

Qual é a lógica:

- o quick irá varrer o dataset a ele associado;

- a banda detail será impressa para cada item no dataset;

- como adicionamos uma group band, ela será impressa a cada vez que o campo a ela associado sofrer alteração. Como ordenamos a consulta pelo nome do cliente, automaticamente o código também ficou repetido e agrupado. Assim, a group band irá observer o momento em que este campo é alterado e "se" imprime.

Link to comment
Share on other sites

  • 0
Bom, neste caso...

Observe que você inicializa -> SQLCondicao := '';

e não muda ela antes de chegar no -> if SQLCondicao = '' then

logo, este if será sempre validado.

O if anterior -> if ((TxtDtVenIni.Text <> ' / / ') or (TxtDtVenFin.Text <> ' / / ')) then

está permitindo que um dos valores seja nulo, porque você está usando um OR e não um AND. A menos que você possa realmente informar apenas uma data no período, isto deveria ser corrigido. Neste caso, a montagem da string (concatenação) deveria levar isto em conta, pois se uma das datas pode ser nula, então ela não deveria ser incluída no filtro.

Voce provavelmente estaria filtrando um perído (between), ou datas maiores que a inicial (>=) ou as menores que a final (<=)

Dê uma avaliada nisto.

Micheus, realmente vocês está certo sobre o or o correto é and, sobre o "if SQLCondicao" eu já deixei preparado o código pois vou incluir mais tipo de filtro.

Sobre o agrupamento do relatório ficou show de bola, do jeito que eu queria, agora só não estou conseguindo fazer que para cada agrupador(cliente) apareça um "subtotal", pois um "total" eu já coloquei em um rbSummary e deu certo, para o subtotal eu havia colocado uma child, mas para cada registro foi somando um resultado (legal), mas não o que quero...testei entre outras BandType e não consegui, você poderia me ajudar ?

Obrigado.

Edited by robinhocne
Link to comment
Share on other sites

  • 0
Sobre o agrupamento do relatório ficou show de bola, do jeito que eu queria, agora só não estou conseguindo fazer que para cada agrupador(cliente) apareça um "subtotal", pois um "total" eu já coloquei em um rbSummary e deu certo, para o subtotal eu havia colocado uma child, mas para cada registro foi somando um resultado (legal), mas não o que quero...testei entre outras BandType e não consegui, você poderia me ajudar ?

A banda sumário, é como diz o nome: sumariza/totaliza tudo! Ou seja, soma todos os registros que ele mostrar na banda detalhe.

Isto que voce quer está claramente relacionado à quebra do cabeçalho, não é mesmo. Vinculada à uma GroupBand voce terá uma GroupFooter (ou apenas footerband - já não lembro, mas você a achará). Esta banda deverá ser vinculada à group em questão. Isso é necessário porque o QuickReport tem que saber a quem ela "pertence" para imprimí-la na hora certa. Lembre-se que voce poderia ter vários destes conjuntos em um relatório mais compléxo.

Observe ainda, que há uma propriedade nos componente de totalização (TQrExpr) que voce usará onde você diz que ele deve ser zerado após impresso (acho que é algo como ResetAfterPrint). Do contrário, ele poderá funcionar como um sumario.

Abraços

Link to comment
Share on other sites

  • 0
um outro detalhe é que informei:

order by A.NomCli, A.Parcela

Pela imagem daquele relelatório inicial, parece que este campo é string e não numérico. Sendo string, dependendo como está o texto isto poderia acontecer. Vai ficar de eu avaliar isto daqui.

Eventualmente, voce não poderia utilizar a data? Em teoria, a ordem de vencimento é a orde das parcelas - crescente

Link to comment
Share on other sites

  • 0

Coloquei uma QRBand e mudei o BandType para rbGroupFooter, liguei o LinkBand com a QRGroup1, nele eu coloquei os QrExpr :

sum(valor), sum(recebido) e sum(receber).

mesmo assim não trouxe nada, testei como rbGroupHeader, mas também não deu, o que posso estar fazendo de errado ?

um outro detalhe é que informei:

order by A.NomCli, A.Parcela
Pela imagem daquele relelatório inicial, parece que este campo é string e não numérico. Sendo string, dependendo como está o texto isto poderia acontecer. Vai ficar de eu avaliar isto daqui. Eventualmente, voce não poderia utilizar a data? Em teoria, a ordem de vencimento é a orde das parcelas - crescente
Nesse caso eu tenho o campo
A.NumParc
que traz o numero da parcela, é um campo numeric, coloquei ele e o CodCli como order by também, ai deu certo. Ficou então
order by A.CodCli, A.NomCli, A.NumParc

Link to comment
Share on other sites

  • 0
Coloquei uma QRBand e mudei o BandType para rbGroupFooter, liguei o LinkBand com a QRGroup1, nele eu coloquei os QrExpr :

sum(valor), sum(recebido) e sum(receber).

mesmo assim não trouxe nada, testei como rbGroupHeader, mas também não deu, o que posso estar fazendo de errado ?

só para confirmar, o QRGroup1 deve ter as propriedades Expression contendo o campo de quebra do dataset (CodCli) e a propriedade FooterBand apontando para a QRBand que você definiu para rbGroupFooter.

No QRExp além de configurar a Expression e setar ResetAfterPrint = True.

Estamos chegando naquele ponto em que eu não vendo o seu código, não consigo depurá-lo. A lógica é esta ai que discutimos aqui.

Nesse caso eu tenho o campo
A.NumParc
que traz o numero da parcela, é um campo numeric, coloquei ele e o CodCli como order by também, ai deu certo.

Ficou então

order by A.CodCli, A.NomCli, A.NumParc

Se voce quer que a listagem seja ordenada pelo nome do cliente, então aquele CodCli não deve ser colocado. No caso de voce querer ordenar pelo CodCli mesmo, então retire NomCli porque ele torna-se redundante e também, pelo fato de que se a sua tabela tiver um índice contendo os campos CodCli + NunParc, este índice será utilizado na ordenação agilizando-a.

Link to comment
Share on other sites

  • 0
só para confirmar, o QRGroup1 deve ter as propriedades Expression contendo o campo de quebra do dataset (CodCli) e a propriedade FooterBand apontando para a QRBand que você definiu para rbGroupFooter.

faltava setar a propriedade FooterBand......

Agora está ordenando na quebra e campos de detalhes, está somando cada quebra (SubTotal) e retornando um total geral...por fim....completo :D

Nossa Micheus, cara muito obrigado mesmo pela ajuda, paciência, me ajudou muito e entendi várias coisas com suas explicações.....obrigado mais uma vez.....

:lol: :D ^_^

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Forum Statistics

    • Total Topics
      152.2k
    • Total Posts
      652k
×
×
  • Create New...