Image('images/logo_koriolan.png', 10, 10, 60, 0, 'PNG', 'https://koriolan.tech'); } public function Footer() { $this->SetFont('helvetica', '', 7); $this->SetTextColor(150, 150, 150); // Partie gauche : $this->SetXY(10, -23); $this->Cell(90, 10, 'Koriolan', 0, false, 'L'); $this->SetXY(10, -19); $this->Cell(90, 10, 'SASU au capital social de 50 000€', 0, false, 'L'); $this->SetXY(10, -15); $this->Cell(90, 10, '6 rue Grange Bruyère - 69110 Sainte-Foy-Lès-Lyon - FRANCE', 0, false, 'L'); // Partie droite : $this->SetXY(110, -23); $this->Cell(90, 10, 'RCS Lyon 879 809 341', 0, false, 'R'); $this->SetXY(110, -19); $this->Cell(90, 10, 'SIRET 879 809 341 00016', 0, false, 'R'); $this->SetXY(110, -15); $this->Cell(90, 10, 'TVA Intraco. FR29 879 809 341', 0, false, 'R'); } public function CreateTextBox($textval, $x = 0, $y = 0, $width = 0, $height = 10, $fontsize = 10, $fontstyle = '', $align = 'L', $border = 0) { $this->SetXY($x, $y); $this->SetFont('helvetica', $fontstyle, $fontsize); $this->Cell($width, $height, $textval, 0, false, $align); } } //******************************************************************************************************************************** // Fonction : Génère le document PDF à partir des données reçues en paramètres // Reçoit : une autre concernant la pièce ('Commande', 'Facture') et ses attributs, une variable concernant le client, // et une autre contenant les lignes de la pièce. Le fichier généré est stocké dans 'documents/commandes' ou 'documents/factures'. // Retour : 0 si Ok, -1 si erreur //******************************************************************************************************************************** function document_pdf($piece, $client, $lignes) { switch($piece['type']) { case "commande": { $nom_piece = $_SESSION['textes']['fonctions_pdf']['document']['piece']['type_commande']; $rep = "commandes"; break; } case "facture": { $nom_piece = $_SESSION['textes']['fonctions_pdf']['document']['piece']['type_facture']; $rep = "factures"; break; } default: return(-1); } $pdf = new MYPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); // set document (meta) information : $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor('Koriolan'); $pdf->SetTitle($nom_piece.' '.$piece['no']); $pdf->SetSubject('ShipHeart'); $pdf->SetKeywords('ShipHeart by Koriolan'); $pdf->SetTextColor(0, 69, 99); $pdf->SetFont('helvetica', '', 10); $pdf->AddPage(); // L'abscisse x varie de 10 à 200 (soit une marge de 10 à gauche et 10 à droite) // --------------------------------------------------------- // Adresse du client : $x = 120; // Doit rester < 200 qui est la marge droite ! $y = 30; $pdf->CreateTextBox($client['entreprise'], $x, $y, (200 - $x), 12, 12, 'B', 'L'); $y += 6; $pdf->CreateTextBox($client['nom_complet'], $x, $y, (200 - $x), 10, 10, '', 'L'); $y += 5; $pdf->CreateTextBox($client['rue'], $x, $y, (200 - $x), 10, 10, '', 'L'); $y += 5; $pdf->CreateTextBox($client['ville_complete'], $x, $y, (200 - $x), 10, 10, '', 'L'); $y += 5; $pdf->CreateTextBox($client['libelle_pays'], $x, $y, (200 - $x), 10, 10, '', 'L'); // --------------------------------------------------------- // N° de commande : $x = 10; $y += 10; $pdf->CreateTextBox($nom_piece.' '.$piece['no'], $x, $y, (200 - $x), 20, 20, 'B', 'L'); // --------------------------------------------------------- // Date : $x = 120; $y += 15; $pdf->CreateTextBox('Date : '.date(''.$_SESSION['textes']['all']['all']['date']['format_d_m_y'].''), $x, $y, (200 - $x), 10, 10, '', 'R'); // --------------------------------------------------------- // Tableau $x = 10; $y += 15; $pdf->Line($x, $y, (210 - $x), $y); // Ligne horizontale $x = 10; // $y += 5; $largeur_1 = 90; $largeur_2 = 20; $largeur_3 = 30; $largeur_4 = 20; $largeur_5 = 30; $pdf->CreateTextBox($_SESSION['textes']['fonctions_pdf']['document']['piece']['designation_titre'], $x, $y, $largeur_1, 10, 10, 'B', 'L', 1); // Ligne d'entête $x += $largeur_1; $pdf->CreateTextBox($_SESSION['textes']['fonctions_pdf']['document']['piece']['quantite_titre'], $x, $y, $largeur_2, 10, 10, 'B', 'C', 1); $x += $largeur_2; $pdf->CreateTextBox($_SESSION['textes']['fonctions_pdf']['document']['piece']['pu_ht_titre'], $x, $y, $largeur_3, 10, 10, 'B', 'R', 1); $x += $largeur_3; $pdf->CreateTextBox($_SESSION['textes']['fonctions_pdf']['document']['piece']['taux_tva_titre'], $x, $y, $largeur_4, 10, 10, 'B', 'C', 1); $x += $largeur_4; $pdf->CreateTextBox($_SESSION['textes']['fonctions_pdf']['document']['piece']['pt_ttc_titre'], $x, $y, $largeur_5, 10, 10, 'B', 'R', 1); $x = 10; $y += 10; $pdf->Line($x, $y, (210 - $x), $y); // Ligne horizontale $x = 10; // $y += 5; for ($i = 0; $i < $piece['nb_lignes']; $i ++) { $pdf->CreateTextBox($lignes[$i]['designation'], $x, $y, $largeur_1, 10, 10, '', 'L'); $x += $largeur_1; $pdf->CreateTextBox($lignes[$i]['qte'], $x, $y, $largeur_2, 10, 10, '', 'C'); $x += $largeur_2; $pdf->CreateTextBox(number_format($lignes[$i]['pu_ht'], 2, ".", " ").' €', $x, $y, $largeur_3, 10, 10, '', 'R'); $x += $largeur_3; $pdf->CreateTextBox(number_format($lignes[$i]['taux_tva'], 2, ".", " ").' %', $x, $y, $largeur_4, 10, 10, '', 'C'); $x += $largeur_4; $pdf->CreateTextBox(number_format(($lignes[$i]['qte'] * $lignes[$i]['pu_ht'] * (1 + ($lignes[$i]['taux_tva']/100))), 2, ".", " ").' €', $x, $y, $largeur_5, 10, 10, '', 'R'); $x = 10; $y += 5; if ($y > 260) // Détection d'un saut de page nécessaire { $y = 30; $pdf->AddPage(); } } // Ligne horizontale : $x = 10; $y += 5; $pdf->Line($x, $y, (210 - $x), $y); // --------------------------------------------------------- // Vérification si un saut de page est nécessaire : if ($y > 260) { $y = 30; $pdf->AddPage(); } // --------------------------------------------------------- // Totaux : $x = 10; // $y += 5; $pdf->CreateTextBox('TOTAL', $x, $y, $largeur_1, 10, 11, 'B', 'R'); $x += $largeur_1; $x += $largeur_2; $pdf->CreateTextBox(number_format($piece['total_ht'], 2, ".", " ").' €', $x, $y, $largeur_3, 10, 11, '', 'R'); $x += $largeur_3; $x += $largeur_4; $pdf->CreateTextBox(number_format($piece['total_ttc'], 2, ".", " ").' €', $x, $y, $largeur_5, 10, 11, 'B', 'R'); // --------------------------------------------------------- // Commentaire : if ($piece['commentaire'] != "") { if ($y > 260) // Vérification si un saut de page est nécessaire { $y = 30; $pdf->AddPage(); } $x = 10; $y += 30; $pdf->SetFont('helvetica', '', 10); $pdf->MultiCell((200 - $x), 10, $piece['commentaire'], 'TRBL', 'J', 0, 1, $x, $y, true, 0, true, true); } // --------------------------------------------------------- // Ajout des numéros de page : // NB : les fonctions usuelles ('getAliasNumPage()' et 'getAliasNbPages()') dans le Header ou le Footer fonctionnent bien mais posent des soucis d'alignement... $nb_pages = $pdf->getNumPages(); for($i = 1; $i < ($nb_pages + 1); $i ++) { $pdf->setPage($i); $pdf->SetFont('helvetica', '', 10); $pdf->SetTextColor(0, 69, 99); $pdf->SetXY(150,10); $pdf->Cell(50, 10, 'Page '.$i.'/'.$nb_pages, 0, false, 'R'); } // --------------------------------------------------------- // Fermeture de l'objet PDF et enreigistrement du fichier : ob_clean(); // Semble nécessaire ; sinon erreur du 'output' suivant $pdf_string = $pdf->Output('pseudo.pdf', 'S'); // export du flux dans une chaine (le nom du fichier est ignoré...) // Copie de cette chaine dans le fichier final (cette solution en 2 temps permet d'éviter de devoir utiliser un nom de fichier absolu (semble obligatoire avec Output et l'option 'F') file_put_contents('../../documents/'.$rep.'/'.$piece['no'].'.pdf', $pdf_string); return(0); } class MYPDF2 extends TCPDF { public function Header() { // $this->Image('images/logo_shipheart.png', 10, 10, 60, 0, 'PNG', 'https://shipheart.tech'); } public function CreateTextBox($textval, $x = 0, $y = 0, $width = 0, $height = 10, $fontsize = 10, $fontstyle = '', $align = 'J', $border = 0) { $this->SetXY($x, $y); $this->SetFont('helvetica', $fontstyle, $fontsize); $this->SetFillColor(255,255,255); $this->MultiCell($width, $height, $textval, 0, $align, false); } } //******************************************************************************************************************************** // Fonction : URL d'activation d'un code d'invitation, portée par le QR code ET par le lien cliquable du PDF d'invitation. // Construite à partir de URL_SITE (definitions.php) : plus d'adresse écrite en dur (synthèse §47). // Reçoit : le code d'invitation // Retour : l'URL complète //******************************************************************************************************************************** function Url_activation_code_acces($code) { return 'https://'.URL_SITE.'/shipmembers.php?code_acces='.urlencode($code); } //******************************************************************************************************************************** // Fonction : Image PNG d'un QR code, produite EN MÉMOIRE (aucun fichier temporaire : l'ancienne version écrivait le QR code // et le PDF dans html/temp/, donc dans la partie publique du site - synthèse §47). // Reçoit : le texte à encoder // Retour : le contenu binaire de l'image PNG //******************************************************************************************************************************** function Qr_code_png($texte) { ob_start(); QRcode::png($texte, false, QR_ECLEVEL_M, 8, 2); // false = sortie standard, capturée par le tampon $png = ob_get_clean(); header_remove('Content-Type'); // phpqrcode a posé un en-tête image/png : retiré, le PDF posera le sien return $png; } //******************************************************************************************************************************** // Fonction : Génère et ENVOIE au navigateur le PDF d'une invitation nominative à accéder à un bateau (synthèse §47). // La page appelante doit s'arrêter juste après (exit) : rien ne doit suivre le PDF. // Reçoit : l'invitation (tableau) : Code, Nom_bateau, Email_invite, Prenom_invite, Nom_invite, Type_acces, // Expiration_invitation // Retour : rien (le PDF est envoyé en téléchargement) //******************************************************************************************************************************** function code_acces_pdf($invitation) { $code = $invitation['Code']; $nom_bateau = $invitation['Nom_bateau']; $email = $invitation['Email_invite']; $destinataire = trim(($invitation['Prenom_invite'] ?? '').' '.($invitation['Nom_invite'] ?? '')); $type_acces = $invitation['Type_acces'] ?? ''; $expiration = ($invitation['Expiration_invitation'] != NULL) ? date_format(date_create($invitation['Expiration_invitation']), 'd/m/Y') : ''; $nom_fichier = 'Invitation_'.preg_replace('/[^A-Za-z0-9_-]/', '_', $nom_bateau).'_'.$code.'.pdf'; $pdf = new MYPDF2('LANDSCAPE', 'px', 'A4', true, 'UTF-8', false); // set document (meta) information : $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor('Koriolan'); $pdf->SetTitle('Invitation - '.$nom_bateau); $pdf->SetSubject('ShipHeart'); $pdf->SetKeywords('ShipHeart by Koriolan'); $pdf->SetTextColor(0, 69, 99); $pdf->SetFont('helvetica', '', 10); $pdf->SetAutoPageBreak(false); // Mise en page fixe sur 2 feuilles : pas de saut de page automatique (l'ancienne version // obtenait sa 2e feuille par un saut automatique, déclenché par le texte du bas de la 1re) //--------------------------------------------------------- // Feuille 1 (pliée en deux : à droite la couverture, à gauche le mot d'accueil) : $pdf->AddPage(); $pdf->SetDrawColor(217,217,217); $pdf->Line(421, 0, 421, 595); $pdf->Image('images/logo_shipheart.png', 506, 214, 252, 167, 'PNG', 'https://shipheart.tech'); // Couverture $pdf->Image('images/logo_shipheart.png', 12, 12, 64, 45, 'PNG', 'https://shipheart.tech'); $salutation = ($destinataire != '') ? $destinataire.",\n\n" : ''; $pdf->CreateTextBox($salutation."Nous vous remercions pour votre confiance et sommes ravis de vous offrir un accès aux informations du bateau ".$nom_bateau." via notre plateforme Ship2net.\n\n" ."We thank you for your trust and are delighted to offer you access to the information of the boat ".$nom_bateau." via our Ship2net platform.", 52, 150, 317, 230, 12, '', 'L'); $pdf->CreateTextBox($nom_bateau.(($type_acces != '') ? ' - '.$type_acces : ''), 0, 520, 421, 46, 12, 'B', 'C'); //--------------------------------------------------------- // Feuille 2 (à gauche le mode d'emploi, à droite le QR code et le code) : $pdf->AddPage(); $pdf->SetDrawColor(217,217,217); $pdf->Line(421, 0, 421, 595); $pdf->Image('images/logo_shipheart.png', 12, 12, 64, 45, 'PNG', 'https://shipheart.tech'); $pdf->Image('images/logo_shipheart.png', 766, 12, 64, 45, 'PNG', 'https://shipheart.tech'); $pdf->CreateTextBox("Cette invitation est réservée à l'adresse ".$email.".\n" ."Pour l'activer, scannez le QR code ci-contre, puis connectez-vous à votre compte ShipMember avec cette adresse (ou créez votre compte avec cette adresse).\n" ."Sans appareil photo : rendez-vous sur ".URL_SITE." et connectez-vous avec cette adresse ; l'invitation apparaîtra dans « Mes invitations ».\n" .(($expiration != '') ? "Invitation valable jusqu'au ".$expiration.".\n" : '') ."\n" ."This invitation is reserved for the address ".$email.".\n" ."To activate it, scan the QR code opposite, then log in to your ShipMember account with this address (or create your account with this address).\n" ."Without a camera: go to ".URL_SITE." and log in with this address; the invitation will appear in \"My invitations\".\n" .(($expiration != '') ? "Invitation valid until ".$expiration."." : ''), 52, 110, 317, 400, 11, '', 'L'); $pdf->Image('@'.Qr_code_png(Url_activation_code_acces($code)), 546, 196, 164, 164, 'PNG', Url_activation_code_acces($code)); $pdf->CreateTextBox($code, 506, 372, 244, 30, 18, 'B', 'C'); $pdf->CreateTextBox(URL_SITE, 506, 400, 244, 20, 11, '', 'C'); //--------------------------------------------------------- // Envoi direct au navigateur, sans fichier intermédiaire. Tout ce qui aurait déjà été mis en tampon (espaces, // avertissements...) est jeté : un seul octet parasite avant le PDF le corromprait. while (ob_get_level() > 0) ob_end_clean(); $pdf->Output($nom_fichier, 'D'); }