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.