TCPDF - Customizável

Salve galera do Scriptcase

Venho neste fórum para compartilhar uma forma de extração de relatório usando a biblioteca TCPDF que construí com base em vídeo que assisti dos meus amigos da Avant Soluções. https://www.youtube.com/watch?v=08nlb6BmpDQ

Este formato baseia-se em uma biblioteca externa que leva basicamente o código em HTML e que constrói as colunas em HTML/TABLES usando a biblioteca externa(cabeçalho), a biblioteca interna(corpo) e o blank(dados do relatório) de impressão.

Crio uma biblioteca externa com o nome modelo e dentro desta biblioteca coloco um arquivo que me servirá de modelo para todos os relatórios, desde que o padrão seja requerido, com o nome de lib_modelo_prn.php.

Código lib_modelo_prn.php (biblioteca externa)

<?php class MYPDF extends TCPDF { var $grid = false; function DrawGrid() { if($this->grid===true){ $spacing = 5; } else { $spacing = $this->grid; } $this->SetDrawColor(204,255,255); $this->SetLineWidth(0.35); for($i=0;$i<$this->w;$i+=$spacing){ $this->Line($i,0,$i,$this->h); } for($i=0;$i<$this->h;$i+=$spacing){ $this->Line(0,$i,$this->w,$i); } $this->SetDrawColor(0,0,0); $x = $this->GetX(); $y = $this->GetY(); $this->SetTextColor(204,204,204); for($i=20;$i<$this->h;$i+=20){ $this->SetXY(1,$i-3); $this->Write(4,$i); } for($i=20;$i<(($this->w)-($this->rMargin)-10);$i+=20){ $this->SetXY($i-1,1); $this->Write(4,$i); } $this->SetXY($x,$y); } public function setIdHeader($titulo){ $this->IdHeader = $titulo; } function Header() { if($this->grid) $this->DrawGrid(); // Tipo de fonte $this->SetFont('helvetica', 'B', 14); $separa_titulos = explode("#",$this->IdHeader); $v_titulos = $separa_titulos[0]; $v_dataprn = $separa_titulos[1]; $v_horaprn = $separa_titulos[2]; $v_usuario = $separa_titulos[3]; $v_total_colunas = $separa_titulos[4]; //Pegando as colunas $v_horiz_col = array(); for ($i = 1; $i <= $v_total_colunas; $i++) { array_push($v_horiz_col, $separa_titulos[$i+4]); } //Pegando os percentuais $v_percen_col = array(); for ($ii=($i+4); $ii <= ($v_total_colunas+(($i+4)-1)); $ii++) { array_push($v_percen_col,$separa_titulos[$ii]); } //Pegando as alinhamentos $v_align_col = array(); //$passo = $ii+($v_total_colunas-3); for ($iii = $ii; $iii <= $ii + ($v_total_colunas-1); $iii++) { array_push($v_align_col,$separa_titulos[$iii]); } $hed_html = ' '; $hed_html .= ''; $hed_html .= ' '; $hed_html .= ' '; $hed_html .= ' '; $hed_html .= ''; $hed_html .= '
'.'
'.utf8_decode($v_titulos).'

Data: '.$v_dataprn.'
'.'Hora: '.$v_horaprn.'
'.$v_usuario.'
'; $this->writeHTML($hed_html, true, false, true, false,''); // Tipo de fonte $this->SetFont('helvetica', 'B', 14); $cab_html = ' '; $cab_html .= ''; for ($xx=1;$xx<=$v_total_colunas;$xx++){ $cab_html .= ' '; } $cab_html .= ''; $cab_html .= '
'.utf8_decode($v_horiz_col[$xx-1]).'
'; $this->writeHTML($cab_html, true, false, true, false,''); } } ?>

Agora crio uma biblioteca interna, em nível de projeto, com o nome de prn_tcpdf.php, nome apenas sugestivo com o seguinte conteúdo:

<?php function prn_open_table($arg_striped,$arg_color_y,$arg_color_x,$arg_line) { if ($arg_striped=='S'){ if ($arg_line % 2 == 0){ $arg_html = ' '; }else{ $arg_html = '
'; } }else{ $arg_html = '
'; } return $arg_html; } function prn_close_table() { $arg_html = '
'; return $arg_html; } function prn_set_ini_body() { $arg_html = ''; return $arg_html; } function prn_set_end_body() { $arg_html = ''; return $arg_html; } function prn_rampup_body($arg_element,$arg_element_perc,$arg_element_align,$arg_font_size) { $arg_html = '
'.$arg_element.'
'; return $arg_html; } ?>

Esta biblioteca interna é responsável pela montagem das colunas do corpo do relatório em HTML/TABLES

E agora chegamos ao BLANK, que é a única coisa que modificamos depois da implementação da biblioteca externa e da interna.

No código abaixo passo alguns parâmetros obrigatórios para as bibliotecas internas e externas, são eles:

$par_title => O título do relatório.
$par_data, $par_hora , $par_user => Data, hora e usuário responsável pela emissão.
$par_cols_ttl => Quantidade de colunas do seu relatório.
$par_tit => Os títulos das colunas deste relatório separados pelo símbolo da cerquilha #.
$par_tit => Os percentuais de cada coluna, vejam que se informamos 4 colunas precisamos de 4 valores percentuais, também separados pela cerquilha #.
$par_alg => O alinhamento das colunas e a regra é mesma, 4 valores para 4 colunas, também separados pela cerquilha #.
$v_paper => Se é Landscape (L) ou Portrait §
$v_striped => Se o relatório será Zebrado/Listrado.
$v_color_y => ‘ccf9d1’ => a cor da linha ímpar do relatório
$v_color_x= ‘ffffff’ => a cor da linha par do relatório
$v_sc_app, $v_idhash, $v_hash => Crio um identificador único para o relatório.

O código da BLANK:

$par_title = ‘RELAÇÃO DE PRODUTOS’;
$par_data = ‘24/03/2018’;
$par_hora = ‘10:05’;
$par_user = ‘ANDRE LUIZ’;
$par_cols_ttl = ‘4’;
$par_tit = ‘ID#PRODUTO#STK ATUAL#STK MÍNIMO’;
$par_per = ‘10#40#25#25’;
$par_alg = ‘left#left#center#center’;

/**********************************************************/
/
Parâmetros OBRIGATÓRIOS para MODIFICAR o cabeçalho ******/
$par_title = ‘RELAÇÃO DE PRODUTOS’;
$par_data = ‘24/03/2018’;
$par_hora = ‘10:05’;
$par_user = ‘ANDRE LUIZ’;
$par_cols_ttl = ‘4’;
$par_tit = ‘ID#PRODUTO#STK ATUAL#STK MÍNIMO’;
$par_per = ‘10#40#25#25’;
$par_alg = ‘left#left#center#center’;

$v_header = $par_title .’#’;
$v_header .= $par_data .’#’;
$v_header .= $par_hora.’#’;
$v_header .= $par_user.’#’;
$v_header .= $par_cols_ttl.’#’;
$v_header .= $par_tit.’#’;
$v_header .= $par_per.’#’;
$v_header .= $par_alg;

// L = Landscape or P = Portrait
$v_paper = ‘P’;
$v_striped= ‘S’;
$v_color_y= ‘ccf9d1’;
$v_color_x= ‘ffffff’;
$v_sc_app = ‘tcpdf_produtos’;
$v_idhash = rand(10000, 30000);
$v_hash = hash(‘tiger192,3’, $v_sc_app . $v_idhash . ‘6abb4c58b1464ebcc593554d61c1e73490781df78fb73407’);
/***************************************************************/

sc_include_lib (“tcpdf”);
sc_include_library(“prj”, “modelos”, “lib_modelo_prn.php”, true, true);

//UTF-8 ou ISO-8859-1
$pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, false, ‘ISO-8859-1’, false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor($par_user);
$pdf->SetTitle($par_title);
$pdf->SetSubject($v_hash);
$pdf->SetKeywords(‘Relatório de Sistema’);
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.’ 001’, PDF_HEADER_STRING, array(0,64,255), array(0,64,128));
$pdf->setFooterData(array(0,64,0), array(91,196,191));
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, ‘’, PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, ‘’, PDF_FONT_SIZE_DATA));
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
if ($v_paper==‘P’) {
$vlr_ini = 41;
} else {
$vlr_ini = 50;
}
$pdf->SetMargins(PDF_MARGIN_LEFT, $vlr_ini, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont(‘helvetica’, ‘’, 10, ‘’, true);
$pdf->grid = false;
$pdf->setIdHeader($v_header);
$pdf->AddPage($v_paper,‘A4’);

$check_sql = “SELECT id_prod, descricao, stkatual, stkminimo
FROM produtos”;

sc_select(meus_dados, $check_sql);

$html=’’;
$ll=1;
while (!{meus_dados}->EOF){
$pdf_00 = {meus_dados}->fields[0];
$pdf_01 = {meus_dados}->fields[1];
$pdf_02 = {meus_dados}->fields[2];
$pdf_03 = {meus_dados}->fields[2];

	$html .= prn_open_table($v_striped,$v_color_y,$v_color_x,$ll);

	  $html .= prn_set_ini_body();
		$html .= prn_rampup_body($pdf_00,'10','left',8);
		$html .= prn_rampup_body($pdf_01,'40','left',8);
		$html .= prn_rampup_body($pdf_02,'25','right',8);
		$html .= prn_rampup_body($pdf_03,'25','right',8);
	  $html .= prn_set_end_body();

	$html .= prn_close_table();	

$ll = $ll + 1;
{meus_dados}->MoveNext();

}
{meus_dados}->Close();

$pdf->writeHTML($html, true, false, true, false,’’);
$pdf->lastPage();
$pdf->Output(‘rel_final.pdf’, ‘I’);

Não esqueçam de habilitar a biblioteca interna nos BLANK`s com o conteúdo do relatório.

O resultado segue em anexo! Um forte abraço e até a próxima!


rel_final.pdf (72.8 KB)

Esqueci de mencionar para criar uma pasta “imagens” dentro da biblioteca externa com o logotipo em torno de 450px width e com o nome logo.png, se quiserem modificar esta estrutura, o código está dentro da Biblioteca externa:

Abraço.

Ola dominiquini

Obrigado pela colaboração. vou testar.

Muito interessante, dominiquini. Isto tende a ser melhorado, certo?

Olá Kleyber, boa tarde

A minha próxima ação é fazer os totalizadores e depois as quebras, mas estou um pouco atarefado agora e por contas destas tarefas procurei algo para me ajudar no desenrolar das listagens/relatórios mais simples. No caso dos totalizadores está fácil de fazer e controlar como fazíamos antigamente, mas com certeza terá novas implementações.

Abraço.

Muito obrigado por este caso. Ele foi extremamente útil.

Posso perguntar como imprimir uma tabela de duas linhas? Eu tenho 12 campos na tabela e precisaria de duas linhas para a impressão.

Obrigado pela sua resposta já.

Peço desculpas por escrever. Este é um tradutor do Google.

Rik

Nesse artigo exemplifica sua necessidade. No caso o uso do colspan.

http://www.scriptcaseblog.com.br/usando-biblioteca-externa-para-montar-datagrids-em-formularios-e-report-pdf/

Obrigado Harold,

mas acho que não fiz bem as perguntas. Eu estou procurando uma solução para exibir em 2 linhas.
Eu anexo uma foto.

se fez entender sim e a resposta que eu dei é a solução: colspan na classe do artigo citado.

Veja que o cabeçalho e a linha de total diferem em colunas das linhas do registro.

Você deve montar 2 linhas (rows) para cada registro, e adicionar o atributo colspan = 2 por exemplo na primeira célula da segunda linha.
Estará informando que a célula ocupará duas colunas da linha anterior, assim você pode mesclar colunas diferentes para cada linha.

Exatamente como fez na sua imagem.

https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_td_rowspan
https://www.w3schools.com/tags/tryit.asp?filename=tryhtml_td_colspan

Desculpe, Harold,
talvez eu tenha parecido mal ou há uma barreira de idioma aqui.
Agora vejo o que você tem em mente.
“TOTAL DE VENDAS” é a segunda linha.

O exemplo é ótimo, mas agora preciso encontrar uma maneira de ler os dados do banco de dados Mysql e usá-los neste caso.
Espero ter sucesso.

Obrigado novamente por ajuda.

Um sc_lookup retorna um array.
O artigo baseia os registros em um array.
Símples de tudo.

Obrigado Haroldo,

Você provavelmente pensou assim, mas não funciona comigo:
[iw] = new StdClass;

sc_lookup(my_data, “id, id_user, datum, ura from user_data_01”);
if ({my_data} === false)
{
echo “Access error. Message=”. {my_data_erro} ;
}
elseif (empty({my_data}))
{
echo “Select command didn’t return data”;
}
else
{
{id} = {my_data[0][0]};
{id_user} = {my_data[0][1]};
{datum} = {my_data[0][2]};
{ura} = {my_data[0][3]};
}

$_arr[] = {my_data}->fields[0];
$_arr[] = {my_data}->fields[1];
$_arr[] = {my_data}->fields[2];
$_arr[] = {my_data}->fields[3];

[iw]->arr=$_arr;
Error = Trying to get property of non-object

na verdade não.
vou montar um exemplo.

Na prática:

** clique em grade 2 para ver o resultado **
https://v9.infinitusweb.com.br/forum_sc/control_datagrid_sc_lookup/

O Artigo demonstra o uso da classe com TCPDF e com uma app Controle.

http://www.scriptcaseblog.com.br/usando-biblioteca-externa-para-montar-datagrids-em-formularios-e-report-pdf/

//tabela do banco de dados do projeto Samples
sc_lookup(ds,"SELECT
   customerid,
   companyname,
   contactname,
   contacttitle,
   country,
   stateid,
   city,
   phone,
   fax,
   creditlimit,
   birthdate
  FROM
   customers limit 15");  //sc_lookup retorno em $ds um array multi dimensional

$dg = new DataGrid(7); //INSTANCIANDO  A CLASSE COM 7 COLUNAS
/* PRIMEIRA LINHA DO CABEÇALHO */
$dg->setStyle('Header', 'style', 'background-color: #001B47'); // COR DA PRIMEIRA LINHA DO CABEÇALHO
$dg->setStyle('Header_Cell', 'colspan', '2'); //Como tinha dito uso do colspan // CODIGO IRÁ USAR 2 COLUNAS
$dg->addHeader("CODIGO");
$dg->setStyle('Header_Cell', 'colspan', '3'); // EMPRESA IRÁ USAR 3 COLUNAS
$dg->addHeader("EMPRESA");
$dg->addHeader(['CONTATO','FUNÇÃO']); // CONTATO E FUNÇÃO CADA UM OCUPA UMA COLUNA

/* SEGUNDA LINHA DO CABEÇALHO (7 COLUNAS) */
$dg->setStyle('Header', 'style', 'background-color: #002766'); // COR DA 2 LINHA DO CABEC
$dg->addHeader(['PAÍS','ESTADO','CIDADE','FONE','FAX','LIMITE CRÉD','DATA NASC']);

$dg->setStyle("Cell", 'style', 'text-align:center'); // ALINHAMENTO PARA TODAS AS CÉLULAS DAS LINHAS DE REGISTROS (DETALHE)
$dg->setStyle("Cell", 'style', 'padding:1px 2px'); // ESPAÇAMENTO ENTRE TEXT E BORDAS PARA TODAS AS CÉLULAS

/* QUARTO PARÂMETRO DE setStyle INFORMA A COLUNA QUE SE DESEJA APLICAR O ESTILO */


$Z=FALSE; /* COMO O DETALHE CONTERÁ DUAS LINHAS O ZEBRADO SERÁ CONTROLADO MANUALMENTE */


/* LOOP DE LEITURA LEITURA DOS REGISTROS QUE ESTÃO NO ARRAY RETORNADO PELO sc_lookup -> $ds */
foreach ($ds as $value) {
	
        /* FORMATANDO CAMPOS */

	$value[9] = number_format($value[9], 2, ',', '.');
	$date = date_create( $value[10]);
	$value[10] = date_format($date,"d/m/Y");
	
	/* APLICA ZEBRADO PARA PRIMEIRA LINHA DO DETALHE */
	if ($Z):
		$dg->setStyle("Row", 'style', 'background-color: WHITE');
	else:
		$dg->setStyle("Row", 'style', 'background-color: #D1EAFF');
	endif;
    	

	$dg->setStyle('Cell', 'colspan', '2'); //VALOR ID EMPRESA
	$dg->addCell($value[0]);
	$dg->setStyle('Cell', 'colspan', '3'); //VALOR EMPRESA
	$dg->addCell($value[1]);
	$dg->addCell($value[2]); //CONTATO
	$dg->addCell($value[3]); //FUNÇÃO
	
       /* APLICANDO ZEBRADO NA SEGUNDA LINHA DO DETALHE
	if ($Z):
		$dg->setStyle("Row", 'style', 'background-color: WHITE');
		$Z=FALSE;
	else:
		$dg->setStyle("Row", 'style', 'background-color: #D1EAFF');
		$Z=TRUE;
	endif;
	
        /* ESCREVENDO VALORES DA SEGUNDA LINHA DO DETALHE
        $dg->addCell($value[4]);
	$dg->addCell($value[5]);
	$dg->addCell($value[6]);
	$dg->addCell($value[7]);
	$dg->addCell($value[8]);
	$dg->addCell($value[9]);
	$dg->addCell($value[10]);

}

//HTML GERADO E APLICADO NO LABEL DE UM CAMPO DA APP CONTROLE
sc_label("Campo_DG") = $dg->create();

TAGS: HAROLDO, CLASSE, PHP, DATAGRID, BIBLIOTECA, EXTERNA, DIVIDINDO, CÉLULA, COLSPAN, TABELA, HTML, TCPDF

Eu tenho algo parecido com TCPDF, mas da pra fazer o mesmo com HTML. A única coisa que vai precisar é montar o SQL da consulta bem estruturado e montar o HTML ou TCPDF dependendo como queira que seja visualizado.

Harold, obrigada.

Eu tentei. Desculpe, eu tenho um erro novamente.Error: Invalid argument supplied for foreach()Vou tentar isso amanhã com um banco de dados de amostra e me avise.

FredKeyster
Eu não sei se entendi bem, mas estou interessado.
Rik

Poste seu código aqui.
Provavelmente esta errando em seu código.

veja:
http://www.scriptcase.com.br/forum/index.php/topic,8285.0.html

e veja também:
https://pt.stackoverflow.com/questions/156414/warning-invalid-argument-supplied-for-foreach

Este é o meu código:
sc_lookup(ds, “id, id_pacienta, ura_operacije, predviden_datum_operacije, zdravnik_kirurg, ekipa2, ekipa3, ekipa4, cave, opombe, zdravnik_v_ambulanti from kila_pot_01 limit 15”);

$dg = new DataGrid(7);

$dg->setStyle(‘Header’, ‘style’, ‘background-color: #001B47’);
$dg->setStyle(‘Header_Cell’, ‘colspan’, ‘2’); //Como tinha dito uso do colspan
$dg->addHeader(“CODIGO”);
$dg->setStyle(‘Header_Cell’, ‘colspan’, ‘3’);
$dg->addHeader(“EMPRESA”);

$dg->addHeader([‘CONTATO’,‘FUNÇÃO’]);
$dg->setStyle(‘Header’, ‘style’, ‘background-color: #002766’);

$dg->addHeader([‘PAÍS’,‘ESTADO’,‘CIDADE’,‘FONE’,‘FAX’,‘LIMITE CRÉD’,‘DATA NASC’]);

$dg->setStyle(“Cell”, ‘style’, ‘text-align:center’);
$dg->setStyle(“Cell”, ‘style’, ‘padding:1px 2px’);

$Z=FALSE;
foreach ($ds as $value) {

//$value[0] = number_format($value[0], 2, ',', '.');
//$date = date_create( $value[3]);
//$value[3] = date_format($date,"d/m/Y");


if ($Z):
    $dg->setStyle("Row", 'style', 'background-color: WHITE');
else:
    $dg->setStyle("Row", 'style', 'background-color: #D1EAFF');
endif;
    
$dg->setStyle('Cell', 'colspan', '2');
$dg->addCell($value[0]);
$dg->setStyle('Cell', 'colspan', '3');
$dg->addCell($value[1]);
$dg->addCell($value[2]);
$dg->addCell($value[3]);

if ($Z):
    $dg->setStyle("Row", 'style', 'background-color: WHITE');
    $Z=FALSE;
else:
    $dg->setStyle("Row", 'style', 'background-color: #D1EAFF');
    $Z=TRUE;
endif;

$dg->addCell($value[4]);
$dg->addCell($value[5]);
$dg->addCell($value[6]);
$dg->addCell($value[7]);
$dg->addCell($value[8]);
$dg->addCell($value[9]);
$dg->addCell($value[10]);

}

sc_label(“Campo_DG”) = $dg->create();

Você copiou meu código e só colocou o seu select?
Você tem que adaptar todo o codigo a sua situação.

Você tem conhecimentos em programação? PHP? HTML? CSS?

Sim, copiei apenas o código e organizei a instrução select para a minha situação.

Minhas habilidades de software, no entanto, são mais ruins.

Meus campos são:

id = int
id_pacienta = int
ura_operacije = TIME
predviden_datum_operacije = DATE
zdravnik_kirurg = int
ekipa2 = int
ekipa3 = int
ekipa4 = int
cave = varchar
opombe = varchar
zdravnik_v_ambulanti = int

// ******************************************************************************
No caso do primeiro tópico deste debate, eu uso isso e funciona para mim:

$check_sql = "SELECT
kila.id,
kila.ura_operacije,
kila.predviden_datum_operacije,
kila.id_pacienta,
kila.mesto_operacije,
diagnoza.naziv,
pacient.ime,
kila.zdravnik_kirurg,
osebje.ime_osebja

FROM
kila_pot_01 kila LEFT OUTER JOIN pacienti pacient ON kila.id_pacienta = pacient.id_pacienta
LEFT OUTER JOIN diagnoze diagnoza ON kila.mesto_operacije = diagnoza.id
LEFT OUTER JOIN osebje osebje ON kila.zdravnik_kirurg = osebje.id_osebja
WHERE koncano1 = ‘1’ AND predviden_datum_operacije > curdate()
ORDER BY
kila.predviden_datum_operacije ASC, kila.ura_operacije ASC";

sc_select(meus_dados, $check_sql);
// ******************************************************************************

mas não consigo definir 2 linhas.