Relatório Master-Detail no Quick Report

 

Salve Galera Delphiana!!!!   

Quanto tempo hein!!!?? Mas estamos de volta com mais essa matéria sobre relatórios no Quick e com muitas novidades.

Gostaria de aproveitar e agradecer a todos que tem me ajudado e incentivado a fortalecer a comunidade Delphi no Brasil e também para que eu possa de alguma forma continuar contribuindo com o sucesso dos meus amigos Delphianos. São eles: Gladstone Matos, Kaline, Guinther, Luciano Pimenta, Fábio Francelino e todo o pessoal da DevMedia pela constante confiança e apoio. Ao Sergio Werner e a ASSESPRO por estarem sempre investindo na comunidade de TI e nos permitirem desfrutar de suas instalações para as reuniões do grupo de usuários.

Ao meu chefe André Valle (www.micrologos.com.br) e meus colegas de trabalho por sempre me incentivar e me liberar para ir nos eventos, na maioria das vezes em horário de trabalho. Ao Marco (ClubeDelphi – DelphiRio) e ao Edison. Ao pessoal da lista Delphi-br, a galera que tem comparecido as reuniões mensais do DelphiRio na ASSESPRO-RJ e aos participantes da lista, q mesmo com tantas dificuldades continuamos vivos e na luta. Ao pessoal do DUG-BR (Akira, Marco, Cantu, Marcelo, Facunte, Edu, Luiz Mattos e a galera toda) pelo carinho e confiança e pelas oportunidades de estar sempre nos eventos ajudando de alguma forma, vocês realmente são D+, muito obrigado!!!! A minha família e a minha noiva por me agüentarem os horários e as ausências. E acima de tudo, ao meu precioso Jesus, o motivo principal da minha vida, sem o qual nem mesmo estaria aqui.

Lembrando que no mês de Abril começaremos o grupo de SQL e não para por ai não, no dia 02/04/2005 estarei no 5º DDD (www.dugbr.com.br) em SP e no dia 16/04/2005 no SQL Tech Week (www.sqlmagazine.com.br/td). Galera, quem busca crescimento técnico e profissional, não existe nada melhor do que investir em si mesmo indo a esses eventos, quem vai sempre volta e quem não vai deveria ir. Isso não é “mercham” barato, realmente vale a pena ir e fazer muitos contatos.

Dados os recados vamos ao que interessa, lembrando que qualquer coisa basta passar um e-mail ou me encontrar num dos eventos. Estamos sempre as ordens.

O Relatório

Este tipo de relatório é baseado na projeção de dados relacionados em mais de um RecordSet de registros, fornecendo uma quebra de Mestre e Detalhe, Item e Sub-Item, obtidos em nosso sistema de informação. Ao longo desta etapa, a fim de consolidarmos o nosso aprendizado, os nossos exemplos serão baseados numa  situação proposta para confecção do relatório.

 O departamento financeiro da nossa empresa requisitou uma projeção de dados que possa demonstrar os pedidos feitos dentro de um espaço de tempo a ser definido, ou seja, compreendidos entre uma data inicial e uma data final que será fornecida pelo usuário. O relatório fornecerá o nome do cliente em ordem alfabética e os seus pedidos ordenados por data, do mais recente para o mais antigo. Serão visualizados o nome do cliente, a data do pedido, o total do pedido e os itens do pedido, compreendidos por descrição do produto, quantidade vendida, preço vendido e valor total da venda.

Para alcançarmos nosso objetivo, utilizaremos a tabela de Clientes, Itens, Produtos e Pedidos, cuja estrutura é apresentada abaixo:

 

CREATE TABLE CLIENTES (

    ID_CLIENTE    INTEGER NOT NULL,

    NOME          VARCHAR(60) NOT NULL,

    CPF           CHAR(11) NOT NULL,

    CIDADE        VARCHAR(25) NOT NULL,

    ESTADO        CHAR(2) NOT NULL,

    ENDERECO      VARCHAR(100) NOT NULL,

    CEP           CHAR(9) NOT NULL,

    DATACADASTRO  TIMESTAMP NOT NULL,

    FOTO          BLOB SUB_TYPE 0 SEGMENT SIZE 80);

 

CREATE TABLE PRODUTOS (

    ID_PRODUTO   INTEGER NOT NULL,

    DESCRICAO    VARCHAR(60) NOT NULL,

    ESTOQUE      INTEGER default 0 NOT NULL,

    PRECOCOMPRA  NUMERIC(15,2) NOT NULL);

 

CREATE TABLE PEDIDOS (

    ID_PEDIDO   INTEGER NOT NULL,

    ID_CLIENTE  INTEGER NOT NULL,

    DATAPED     TIMESTAMP NOT NULL);

 

CREATE TABLE ITENS (

    ID_PEDIDO   INTEGER NOT NULL,

    ID_PRODUTO  INTEGER NOT NULL,

    QUANTIDADE INTEGER NOT NULL,

    PRECOVENDA  NUMERIC(15,2) NOT NULL);

 

Crie uma nova aplicação, no formulário principal, além do panel com a propriedade visible igual a false para armazenar o

objeto QuickRep, coloque dois DateTimePickers, chame o primeiro de DtpInicial e o segundo de DtpFinal.

 

Passemos a obtenção dos dados. Podemos agrupar os dados em dois grupos: os dados dos pedidos(nome do cliente, data do pedido, total do pedido) e os itens(descrição do produto, quantidade vendida, preço de venda e total vendido do item). O grupo de pedido é o mestre e os itens os detalhes, pois existe uma relação de dependência dos itens para  com seu pedido. Tendo isto em vista, faremos dois DataSets, o primeiro(Mestre) para obter os pedidos compreendidos entre a data inicial e final fornecida pelo usuário, e um segundo(Detalhe) para obter os itens de cada pedido obtido pelo DataSet de pedidos. Para conseguirmos este objetivo vamos aplicar a técnica de criar DataSets relacionados.

Faça a conexão com o banco de dados, lembrando que em nosso exemplo estamos utilizando DBExpress com InterBase ou FireBird. Em seguida adicione ao formulário um SimpleDataSet e nomeio como SdsPedidos,  defina a propriedade SqlConnection para o objeto SqlConnection que foi utilizado para a conexão  com o banco de dados, em seguida escreva o seguinte comando sql na propriedade CommandText:

 

select   clientes.nome

        ,pedidos.dataped

        ,pedidos.id_pedido

        ,sum(itens.quantidade * itens.precovenda) as total_pedido

from     pedidos

        ,itens

        ,clientes

where    pedidos.dataped between :DATA_INICIAL and :DATA_FINAL

and      pedidos.id_pedido  = itens.id_pedido

and      pedidos.id_cliente = clientes.id_cliente

group by clientes.nome

        ,pedidos.dataped

        ,pedidos.id_pedido

order by clientes.nome

        ,pedidos.dataped desc

 

Onde: DATA_INICIAL e :DATA_FINAL serão os parâmetros preenchidos provenientes dos dois DateTimePickers. Falta-nos ainda uma configuração; precisamos definir o tipo de dado suportado pelos parâmetros que definimos no comando Sql deste objeto. Na propriedade DataSet, na subpropriedade Params estarão definidos os parâmetros que criamos no CommandText. Defina propriedade DataType de cada um como ftDate, referenciando que suportam dados do tipo data.

 

Para criarmos DataSets relacionados, fazemos uso de componentes DataSource para conecta-los. Coloque no formulário um DataSource, altere a sua propriedade name para DsPedidosItens e a sua propriedade DataSet para SdsPedidos. Esta foi a configuração do DataSet Mestre; façamos agora a configuração do DataSet Detalhe. Como definido anteriormente, este DataSet irá conter os dados dos itens dos pedidos obtidos no DataSet Mestre. É fato que identificamos os itens de um pedido através do campo id_pedido, é por esta razão que se tornou objeto de nosso interesse o campo id_pedido contido no SdsPedidos, justamente para através do valor armazenado nele obtermos os itens do pedido.

Inclua no formulário mais um SimpleDataSet, defina sua propriedade name como SdsItens, defina a propriedade DataSource dentro da propriedade DataSet para apontar para o DsPedidosItens, pois é no DataSet SdsPedidos que obtemos o valor do campo id_pedido que será passado automaticamente quando definimos este relacionamento através do DataSource e quando no comando sql, o nome do parâmetro que referencia o valor pelo qual pautamos a busca, possui o mesmo nome do campo existente no DataSet Mestre.

Continuando a configuração do componente, na propriedade CommandText que está dentro da propriedade DataSet, defina o seguinte comando sql:

 

select   produtos.descricao

        ,itens.quantidade

        ,itens.precovenda

        ,sum(itens.quantidade * itens.precovenda) as total_item

from     itens

        ,produtos

where    itens.id_pedido  = :ID_PEDIDO

and      itens.id_produto = produtos.id_produto

group by produtos.descricao

        ,itens.quantidade

        ,itens.precovenda

order by produtos.descricao

 

Neste comando o :ID_PEDIDO é o parâmetro pelo qual obtemos os itens do pedido, este não precisa ser configurado na propriedade params como no DataSet anterior pois como o SdsItens está relacionado ao SdsPedidos através do DataSource DsPedidosItens, é de propósito que o nome do parâmetro seja o mesmo nome do campo no DataSet Master. Deste modo, a associação de valores para execução do SdsItens é feita automaticamente através do relacionamento entre os DataSets.

Assim, acabamos de criar um relacionamento Master-Detail entre DataSets.

 

Passemos a construção do relatório pois já possuímos a fonte de dados. Configure o objeto QuickRep.

 

Na banda Page Header coloque o título do relatório utilizando um QRLabel para isto.

 

Passemos a montagem da visualização dos dados; defina a propriedade DataSet do objeto QuickRep para apontar para o SdsPedidos que é o nosso DataSet Master. Na banda Detail vamos fazer a amostragem dos dados referentes ao Pedido, provenientes do SdsPedidos. Desenhe um Retângulo usando o QRShape, e dentro deste retângulo posicione os QRLabels referentes aos dados a serem visualizados com relação aos pedidos.

 

Em seguida, para amostrar o conteúdo dos campos, posicione os QRDBText  referentes aos campos do SdsPedidos, a propriedade DataSet destes três QRDBText deverão apontar para o SdsPedidos e a propriedade DataField de cada um deverá referenciar o campo relacionado a posição do label que se encontra ao lado deste.

 

Em seguida criaremos nesta banda ainda o cabeçalho para exibir a tabela de itens do pedido, dados estes provenientes do SdsItens. Use componentes QRShape para desenhar o cabeçalho da tabela e use QRLabels para os títulos das colunas.

Implementemos agora a banda que irá exibir os dados do DataSet Detalhe, o SdsItens. Da palheta Qreport, adicione ao relatório um objeto QrSubDetail, que é uma banda de impressão. Esta funcionará sempre subjugada ao Mestre dos dados, em nosso caso o QuickRep que está ligado ao DataSet Master.

Aponte sua propriedade Master para QuickRep1 e a sua propriedade DataSet para SdsItens, em seguida desenhe através do uso de QRShape a continuação da tabela para exibir os itens do pedido.

 

Em cada célula que se formou coloque um QRDBText, aponte a propriedade DataSet de cada um deles para SdsItens de onde provêem os dados desta banda. A propriedade DataField de cada um será de acordo com o campo referenciado pelo cabeçalho da tabela de exibição que estamos montando.

 

Adicione a banda Page Footer a exibição do número de página.

 

Façamos agora o código do botão Gerar Relatório:

 

  try

    SdsPedidos.DataSet.Params[0].AsDate := DtpInicial.Date;

    SdsPedidos.DataSet.Params[1].AsDate := DtpFinal.Date;

    SdsPedidos.Open;

    SdsItens.Open;

    QuickRep1.Preview;

  finally

    SdsItens.Close;

    SdsPedidos.Close;

  end;

 

Este código passa por parâmetro as datas iniciais e finais para o DataSet Master, abre os dois DataSets, lembrando que o Mestre deve ser sempre aberto antes do Detalhe. No final fecha-se os dois DataSets.

Faça os retoques finais que desejar com relação a parte  visual e execute a aplicação para testar o relatório.

 

É isso pessoal!!!! Divirtam-se em seus relatórios e me contatem se necessário, as ordens e até a próxima!!!! Nos vemos nos grupos de usuários DelphiRio e SQLRio e nos eventos 5º DDD e no SQL Tech Week.