Générez vos factures avec HTML2PDF

J’ai terminé il y a quelques semaines la génération de factures téléchargeables pour StriveWeb, en utilisant, comme beaucoup, HTML2PDF.  Rien de bien exceptionnel en soit, mais quelques petits points peuvent s’avérer « prise de tête ». Du coup, puisque je suis bon et charitable (carrément !), je vous propose ce petit tutoriel. Grâce lui, vous serez en mesure de générer des factures téléchargeables au format PDF. Je tacherai de rester assez générique dans mes explications, de me détacher de tout framework, afin que vous puissiez facilement transposer le tuto à votre projet.

Installer HTML2PDF

Pour générer nos PDF, nous allons donc utiliser la librairie HTML2PDF. Vous pouvez trouver sa documentation sur GitHub ici : https://github.com/spipu/html2pdf. Pour l’installer c’est très simple. Ouvrez composer, et entrez la commande si dessous. C’est tout, pas de configuration supplémentaire nécessaire.

composer require spipu/html2pdf
 

Créer notre Facture

La librairie est installée, il ne reste plus qu’à instancier notre objet facture. On passe 3 paramètres au constructeur : l’orientation (P pour Portrait, L pour Landscape/Paysage), le format de notre facture (A4 dans notre cas, vous pouvez trouvez la liste des formats ici : https://github.com/tecnickcom/TCPDF/blob/master/include/tcpdf_static.php#L2097 ) puis la langue de notre document (fr).

$facture = new \Spipu\Html2Pdf\Html2Pdf('P', 'A4', 'fr');
 

Ensuite c’est toujours aussi simple, on ajoute du contenu HTML à notre facture puis on la transforme en PDF.

$facture->writeHTML('du HTML');
$facture->output();
 

Le HTML de notre Facture

Ca y est, on rentre dans la partie marrante. Rien de bien compliqué, il suffit juste de suivre les règles et de comprendre comment fonctionne la librairie. Elle a beau s’appeler HTML2PDF, elle ne transforme pas miraculeusement tout code HTML en un magnifique PDF. Pour faire simple, HTML2PDF va interpréter les différentes balises de notre code pour générer le PDF, comme un traducteur. Si vous devez traduire une langue que vous connaissez, ça va. Si vous devez traduire une langue que vous ne connaissez absolument pas, ça se complique. Pour notre librairie, c’est pareil. Vous devez garder en tête que HTML2PDF ne connait pas toutes les balises HTML, il en interprète un certain nombre. Vous devez donc travailler sur un code qu’il comprendra. On pose donc la structure de base :

<page>
    <page_header>
	...
    </page_header> 
    <page_footer> 
        ...
    </page_footer>
    ...
</page>
 

Plutôt que d’utiliser la balise <html> classique, on se servira ici de la balise <page>. Balise à la suite de laquelle on met les balises <page_header> et <page_footer> pour gérer, spoiler alert, notre Header et notre Footer (ces balises doivent être utilisées avant tout contenu HTML correspondant au contenu d’une page). Ensuite, on y mettra le corps de notre facture. Autant vous prévenir tout de suite, on utilise généralement les tableaux pour gérer le design de la facture.

Il y a quelques obligations en ce qui concerne les factures, notamment un certain nombre de mentions à faire apparaitre. Un petit tour sur le site du gouvernement pour être sûr de ne rien oublier : https://www.service-public.fr/professionnels-entreprises/vosdroits/F23208

On commence par le Header, qui contiendra le logo de notre société, et des infos sur le client :

<page_header>
	<table>
		<tr>
			<td>
				<img src="https://monsite.com/images/logo.png" /><!-- utilisez un lien absolu, c'est beaucoup moins galère et cette ressource ne devrait pas bouger. Dans le cas présent ça se justifie -->
			</td>
			<td>
				<b>Facturé à :</b><br />
				$nomDuClient<br />
				$adresseDuClient
			</td>
			<td>
				<b>Détails :</b><br />
				Date de facturation : $date<br />
				Numéro de facture : $numeroDeFacture
			</td>
		</tr>
	</table>
</page_header>
 

On s’occupe ensuite du Footer, qui regroupera les infos importantes de notre entreprise :

<page_footer> 
	<p>
		Ma Super Boite, SASU au capital de X€<br />
		mon adresse<br />
		Immatriculé au RCS de Tours sous le numéro .......<br />
		TVA intracommunautaire : FR........
	</p>
</page_footer>
 

Passons maintenant au corps de notre facture. Nous avons plusieurs informations à afficher : le nom du produit ou de la prestation, la quantité, le prix unitaire, le prix appliqué en cas de réduction, le total HT, le montant de la TVA, et le total TTC.

<table>
	<thead>
		<tr>
			<th>
				Produit/Prestation
			</th>
			<th>
				Prix unitaire
			</th>
			<th>
				Prix facturé
			</th>
			<th>
				Quantité
			</th>
			<th>
				Total HT
			</th>
		</tr>
	</thead>
	<tbody>
		<!-- ici on boucle sur les lignes de notre facture -->
		<tr>
			<td>
				$nomDeLaPrestation
			</td>
			<td>
				$prixUnitaire</td>
			<td>
				$prixUnitaireFacture</td>
			<td>
				$quantite
			</td>
			<td>
				$prixUnitaireFacture * $quantite</td>
		</tr>
		<!-- fin de la boucle -->
		<tr>
			<td colspan="3"></td>
			<td>
				Total HT
			</td>
			<td>
				$totalHorsTaxes</td>
		</tr>
		<tr>
			<td colspan="3"></td>
			<td>
				TVA (20%)
			</td>
			<td>
				$totalHorsTaxes*0.2</td>
		</tr>
		<tr>
			<td colspan="3"></td>
			<td>
				Total TTC
			</td>
			<td>
				$totalHorsTaxes*1.2</td>
		</tr>
	</tbody>
</table>
 

La mise en forme

Comme je vous le disais plus haut, HTML2PDF ne comprend pas tout le HTML, ni tout le CSS. Oubliez donc Bootstrap, il faut faire simple et propre. Pour créer le design de notre facture, on utilise la balise <style> juste après avoir ouvert la balise <page>. Les possibilités étant limitées, on ne fera rien d’exceptionnel. Nous allons simplement jouer sur la largeur de certains éléments, les marges internes et externes et les bordures, en gros.

<style type="text/css">
	page{
		max-width: 100%;
	}
	table { 
		width: 100%; 
		color: #717375; 
		font-family: helvetica; 
		line-height: 5mm; 
		border-collapse: collapse; 
	}
	img{
		width: 100%;
	}
	h2 { margin: 0; padding: 0; }
	p { margin: 5px; color: #717375; }
	.border th { 
		border: 1px solid #000;  
		color: white; 
		background: #000; 
		padding: 5px; 
		font-weight: normal; 
		font-size: 14px; 
		text-align: center; 
	}
	.border td { 
		border: 1px solid #CFD1D2; 
		padding: 5px 10px; 
		text-align: center; 
	}
	.no-border { 
		border-right: 1px solid #CFD1D2; 
		border-left: none; 
		border-top: none; 
		border-bottom: none;
	}
	.p-10 { width: 10%; } .p-15 { width: 15%; } 
	.p-33 { width: 33%; } .p-45 { width: 45%; }
</style>
 

Le code complet

Et voilà ! On résumé tout cela avec le code complet. Pensez tout de même à l’adapter à vos besoins et à vous assurer que votre facture affiche bien toutes les informations requises par la loi.

<page backtop="50mm">
	<style type="text/css">
		page{
			max-width: 100%;
		}
		table { 
			width: 100%; 
			color: #717375; 
			font-family: helvetica; 
			line-height: 5mm; 
			border-collapse: collapse; 
		}
		img{
			width: 100%;
		}
		h2 { margin: 0; padding: 0; }
		p { margin: 5px; color: #717375; }
		.border th { 
			border: 1px solid #000;  
			color: white; 
			background: #000; 
			padding: 5px; 
			font-weight: normal; 
			font-size: 14px; 
			text-align: center; 
		}
		.border td { 
			border: 1px solid #CFD1D2; 
			padding: 5px 10px; 
			text-align: center; 
		}
		.no-border { 
			border-right: 1px solid #CFD1D2; 
			border-left: none; 
			border-top: none; 
			border-bottom: none;
		}
		.p-10 { width: 10%; } .p-15 { width: 15%; } 
		.p-33 { width: 33%; } .p-45 { width: 45%; }
	</style>
    <page_header>
		<table>
			<tr>
				<td>
					<img src="https://monsite.com/images/logo.png" /><!-- utilisez un lien absolu, c'est beaucoup moins galère et cette ressource ne devrait pas bouger. Dans le cas présent ça se justifie -->
				</td>
				<td>
					<b>Facturé à :</b><br />
					$nomDuClient<br />
					$adresseDuClient
				</td>
				<td>
					<b>Détails :</b><br />
					Date de facturation : $date<br />
					Numéro de facture : $numeroDeFacture
				</td>
			</tr>
		</table>
    </page_header> 
    <page_footer> 
        <p>
			Ma Super Boite, SASU au capital de X€<br />
			mon adresse<br />
			Immatriculé au RCS de Tours sous le numéro .......<br />
			TVA intracommunautaire : FR........
		</p>
    </page_footer>
    <table>
		<thead>
			<tr>
				<th>
					Produit/Prestation
				</th>
				<th>
					Prix unitaire
				</th>
				<th>
					Prix facturé
				</th>
				<th>
					Quantité
				</th>
				<th>
					Total HT
				</th>
			</tr>
		</thead>
		<tbody>
			<!-- ici on boucle sur les lignes de notre facture -->
			<tr>
				<td>
					$nomDeLaPrestation
				</td>
				<td>
					$prixUnitaire €
				</td>
				<td>
					$prixUnitaireFacture €
				</td>
				<td>
					$quantite
				</td>
				<td>
					$prixUnitaireFacture * $quantite €
				</td>
			</tr>
			<!-- fin de la boucle -->
			<tr>
				<td colspan="3"></td>
				<td>
					Total HT
				</td>
				<td>
					$totalHorsTaxes €
				</td>
			</tr>
			<tr>
				<td colspan="3"></td>
				<td>
					TVA (20%)
				</td>
				<td>
					$totalHorsTaxes*0.2 €
				</td>
			</tr>
			<tr>
				<td colspan="3"></td>
				<td>
					Total TTC
				</td>
				<td>
					$totalHorsTaxes*1.2 €
				</td>
			</tr>
		</tbody>
	</table>
</page>