Montando a Aplicação
Crie uma nova aplicação e insira os seguintes componentes:
Componente |
Database |
AliasName |
Alias apontando para DBDemos |
|
|
Componente |
SQLQuery |
Name |
qryOrders |
SQL |
Select * from ORDERS Order by CustNo, OrderNo |
|
|
Componente |
SQLQuery |
Name |
qryItems |
SQL |
Select I.*, P.Description, P.ListPrice, ((I.Qty * P.ListPrice) - I.Discount) as TotalItem From Items I Inner Join Parts P on P.PartNo = I.PartNo Where I.OrderNo = :OrderNo Order by ItemNo |
|
|
Componente |
SQLQuery |
Name |
qryCustomer |
SQL |
Select * from Customer C Where C.CustNo = :CustNo |
|
|
Insira um DataSource para cada SQLQuery, logo teremos três DataSource (dtsOrders, dtsItems e dtsCustomer); associe o DataSource dtsOrders na propriedade “DataSource” das Querys qryItems e qryCustomer.
Importante: Não esqueça de verificar se foi gerado um parâmetro (CustNo para Query Customer e OrderNo para a Query Items) propriedade Params e se esses parâmetros estão configurados como DataType = ftFloat e ParamType = ptInput.
Agora, insira uma grid para demonstrar o conteúdo da query Orders e ligue essa grid ao DataSource correspondente a Query, insira também um DBNavigator associado a esse mesmo DataSource, faça esses mesmos passos para demonstrar o conteúdo da Query Items e Customer.
Por fim, insira dois botões, um chamado “Result” e o outro “Report”, sua tela ficará parecida com a imagem abaixo:
Tudo bem, tudo bem a sua deve ter ficado mais bonita, ahahaha, mas como o intuito desse artigo não é montar uma tela bonita e sim um relatório, não vamos nos prender a esse pequeno detalhe (ufa...).
Insira o código abaixo no clique do botão “Result”:
qryOrders.Close;
qryOrders.Open;
E no evento After Open da Query qryOrders insira o seguinte código:
qryCustomer.Close;
qryCustomer.Open;
qryCustomer.Close;
qryCustomer.Open;
Rode a aplicação, clique sobre o botão e verifique se o mestre-detalhe está funcionando.
Montando o Relatório
Bom, agora vamos para a parte que realmente nos interessa nesse artigo, o relatório.
Insira um componente RVSystem e configure as seguintes propriedades:
SystemPrinter |
|
|
Units à unCM |
|
MarginLeft à 1 |
|
MarginRight à 1 |
|
MarginTop à 1 |
|
MarginBottom à 1 |
|
|
SystemPreview |
FormState à wsMaximized |
No Evento OnBeforePrint do RVSystem, vamos configurar a página e criar os tabs que serão a estrutura do nosso relatório. Com o seguinte código:
with Sender as TBaseReport do
begin
SetPaperSize(DMPAPER_A4, 0, 0);
//Customer / Employee
ClearTabs;
SetTab(1.2, pjLeft, 3, 0, BOXLINEHORIZ, 0); //CustNo
SetTab(NA , pjLeft, (PageWidth – 5.2), 0, BOXLINEHORIZ, 0); //Company
SaveTabs(1);
//Orders
ClearTabs;
SetTab(1.5, pjLeft, 2.0, 0, BOXLINENONE, 0); //OrderNo
SetTab(NA , pjLeft, 2.5, 0, BOXLINENONE, 0); //SaleDate (data venda)
SetTab(NA , pjLeft, 2.5, 0, BOXLINENONE, 0); //ShipDate (data entrega)
SetTab(NA , pjLeft, 2.0, 0, BOXLINENONE, 0); //ShipVia (Forma de Entrega)
SetTab(NA , pjLeft, 3.0, 0, BOXLINENONE, 0); //PaymentMethod (Forma de Pagamento)
SetTab(NA , pjLeft, 3.0, 0, BOXLINENONE, 0); //ItemsTotal (Total Venda)
SaveTabs(2);
//Items
ClearTabs;
SetTab(2.0, pjLeft, 1.5, 0, BOXLINENONE, 0); //ItemNo
SetTab(NA , pjLeft, 2.0, 0, BOXLINENONE, 0); //PartNo (código do produto)
SetTab(NA , pjLeft, 5.0, 0, BOXLINENONE, 0); //description (descrição)
SetTab(NA , pjLeft, 2.0, 0, BOXLINENONE, 0); //ListPrice (Valor Unitário)
SetTab(NA , pjLeft, 1.5, 0, BOXLINENONE, 0); //qty (quantidade)
SetTab(NA , pjLeft, 2.0, 0, BOXLINENONE, 0); //discount (Desconto)
SetTab(NA , pjLeft, 2.0, 0, BOXLINENONE, 0); //TotalItem (total)
SaveTabs(3);
end;
Verifique que utilizamos o SetPaperSize para configurar o tamanho que será a página do relatório e o SetTab para montar a estrutura do relatório.
Importante: Não esqueça de executar um ClearTabs sempre antes de iniciar a montagem de uma nova estrutura.
No evento OnPrintHeader montaremos o cabeçalho do relatório, insira o código abaixo:
with Sender as TBaseReport do
begin
SetFont('Arial',8);
PrintRight('Página ' + Macro(midCurrentPage) + ' de ' + Macro(midTotalPages), PageWidth - MarginRight);
NewLine;
SetFont('Arial',12);
Bold := True;
PrintCenter('Relatório de Vendas', PageWidth / 2);
Bold := False;
NewLine;
MoveTo(1.0, 2.0);
LineTo(20.0, 2.0);
end;
Importante: Para entender melhor a função “Macro” leia o artigo “Rave Reports Code Based”.
E para finalizar a parte de estrutura da página vamos montar o rodapé com o código abaixo:
with Sender as TBaseReport do
begin
MoveTo(1.0, 28.5);
LineTo(20.0, 28.5);
YPos := 29.0;
SetFont('Arial',8);
PrintCenter('Data de Impressão: ' + Macro(midCurrDateShort) + ' ' + Macro(midCurrTimeShort), PageWidth/2);
end;
Execute a aplicação e verifique se o cabeçalho e rodapé ficarão corretos.
Agora vamos montar o corpo do relatório, o objetivo desse relatório como já dito anteriormente é demonstrar as vendas separadas por cliente, então nossa preocupação nesse relatório é a mudança do código do cliente e a mudança no código da venda, pois como fizemos no inicio desse artigo, já estamos trazendo as vendas ordenadas pelo código do cliente e pelo código da venda, logo toda vez que mudar de cliente temos que iniciar uma nova página, e enquanto o código da venda for igual teremos que carregar os itens dessa venda.
No evento OnPrint insira o seguinte código:
var
intOrderNo, intCustNo : Integer;
begin
intOrderNo := 0;
intCustNo := 0;
with Sender as TBaseReport do
begin
qryOrders.DisableControls;
qryOrders.First;
while not qryOrders.Eof do
begin
if (intCustNo <> qryOrdersCustNo.AsInteger) then
begin
if intCustNo > 0 then
NewPage;
with qryCustomer do
begin
Close;
Params.ParamByName('CustNo').AsInteger := qryOrdersCustNo.AsInteger;
Prepare;
Open;
end;
SetFont('Arial', 10);
NewLine;
Bold := True;
PrintLeft('Cliente',MarginLeft);
Bold := False;
NewLine;
RestoreTabs(1);
PrintTab('Código .: ' + qryCustomerCustNo.AsString);
PrintTab('Nome .: ' + qryCustomerCompany.AsString);
end;
if intOrderNo <> qryOrdersOrderNo.AsInteger then
begin
if LinesLeft < 3 then
NewPage;
SetFont('Arial',10);
NewLine;
Bold := True;
RestoreTabs(2);
PrintTab('Venda'); //OrderNo
PrintTab('Data Venda');//SaleDate (data venda)
PrintTab('Data Entrega');// ShipDate (data entrega)
PrintTab('Entrega');/// ShipVia (Forma de Entrega)
PrintTab('Pagamento');// PaymentMethod (Forma de Pagamento)
PrintTab('Total');// ItemsTotal (Total Venda)
Bold := False;
NewLine;
RestoreTabs(2);
PrintTab(qryOrdersOrderNo.AsString); //OrderNo
PrintTab(qryOrdersSaleDate.AsString);//SaleDate (data venda)
PrintTab(qryOrdersShipDate.AsString);// ShipDate (data entrega)
PrintTab(qryOrdersShipVIA.AsString);/// ShipVia (Forma de Entrega)
PrintTab(qryOrdersPaymentMethod.AsString);// PaymentMethod (Forma de Pagamento)
PrintTab(FormatFloat('R$ 0.00', qryOrdersItemsTotal.AsFloat));// ItemsTotal (Total Venda)
end;
if LinesLeft < 3 then
NewPage;
NewLine;
RestoreTabs(3);
SetFont('Arial',8);
Bold := True;
PrintTab('Item');//ItemNo
PrintTab('Código');//PartNo (código do produto)
PrintTab('Nome');//description (descrição)
PrintTab('Vl. Unit.');//ListPrice (Valor Unitário)
PrintTab('Qtde.');//qty (quantidade)
PrintTab('Desconto');//discount (Desconto)
PrintTab('Total');//TotalItem (total)
Bold := False;
with qryItems do
begin
Close;
Params.ParamByName('OrderNo').AsInteger := qryOrdersOrderNo.AsInteger;
Prepare;
Open;
end;
while not qryItems.Eof do
begin
if LinesLeft < 3 then
NewPage;
SetFont('Arial',8);
NewLine;
RestoreTabs(3);
PrintTab(qryItemsItemNo.AsString);//ItemNo
PrintTab(qryItemsPartNo.AsString);//PartNo (código do produto)
PrintTab(qryItemsDescription.AsString);//description (descrição)
PrintTab(FormatFloat('R$ 0.00', qryItemsListPrice.AsFloat));//ListPrice (Valor Unitário)
PrintTab(qryItemsQty.AsString);//qty (quantidade)
PrintTab(FormatFloat('R$ 0.00', qryItemsDiscount.AsFloat));//discount (Desconto)
PrintTab(FormatFloat('R$ 0.00', qryItemsTotalItem.AsFloat));//TotalItem (total)
qryItems.Next;
end;
intOrderNo := qryOrdersOrderNo.AsInteger;
intCustNo := qryOrdersCustNo.AsInteger;
NewLine;
qryOrders.Next;
end;
qryOrders.EnableControls;
end;
Entendendo o código:
Declaramos duas variáveis ( intOrderNo, intCustNo ) para controlar o código da Venda e o código do Cliente, dentro do loop da query Orders verificamos se o conteúdo da variável intCustNo é igual ao registro atual da Query, se for diferente significa que ocorreu uma mudança de Cliente, e de acordo com o escopo do nosso relatório, toda vez que isso ocorrer temos que iniciar uma nova página (NewPage) e demonstrar quem é esse novo cliente, então restauramos a tab correspondente para escrevermos no relatório o código e o nome desse cliente.
Após isso verificamos se o conteúdo da variável intOrderNo é diferente do registro atual da query Orders se for diferente precisamos montar o titulo das colunas e inserir as informações dessa nova venda.
Se o cliente for o mesmo e a venda for a mesma o relatório vai montar os itens dessa venda.
Execute a aplicação e clique sobre o botão “Report” para verificar o resultado do relatório, deverá ficar parecido com a imagem abaixo:
Conclusão
È isso pessoal, espero que tenha dado tudo certo e que esse artigo tenha te ajudado!!! Até o próximo.