. */ /** * An extension of FPDF to generate personalized correspondence PDFs */ class Correspondence extends FPDF { /** * @var $contact Holds the contact this correspondence will be sent to * @var $language Holds the language this correspondence should be sent in */ var $contact, $language; /** * If you'd want, you could change these constants to encode an RGB colour for headings in your PDFs */ const HEAD_RED = 0; const HEAD_GREEN = 0; const HEAD_BLUE = 0; /** * Available languages * * @see _() Translation function * @see $translations Translations table */ const LANGUAGES = ['en', 'nl']; /** * Array holding the translations * * @see _() A function to translate */ protected static $translations = [ 'adres' => [ 'en' => 'Address', 'nl' => 'Adres'], 'amount' => [ 'en' => 'Amount', 'nl' => 'Subtotaal'], 'amount-due' => [ 'en' => 'Total amount due', 'nl' => 'Te voldoen'], 'biccode' => [ 'en' => 'The BIC code of our bank is %%.', 'nl' => 'De BIC-code van de bank is %%.'], 'btwnr' => [ 'en' => 'VAT nr', 'nl' => 'BTW nr'], 'description' => [ 'en' => 'Description', 'nl' => 'Omschrijving'], 'due-date' => [ 'en' => 'Due date', 'nl' => 'Vervaldatum'], 'email' => [ 'en' => 'Email', 'nl' => 'Email'], 'iban' => [ 'en' => 'IBAN', 'nl' => 'IBAN'], 'invoice' => [ 'en' => 'Invoice', 'nl' => 'Factuur'], 'invoice-date' => [ 'en' => 'Invoice date', 'nl' => 'Factuurdatum'], 'invoice-nr' => [ 'en' => 'Invoice number', 'nl' => 'Factuurnummer'], 'price-excl' => [ 'en' => 'Price excl.', 'nl' => 'Prijs excl.'], 'price-incl' => [ 'en' => 'Price incl.', 'nl' => 'Prijs incl.'], 'request' => [ 'en' => 'You are kindly requested to transfer the total amount before the due date to the provided IBAN nr.', 'nl' => 'U wordt vriendelijk verzocht het te voldoen bedrag voor de vervaldatum van de factuur over te maken naar opgegeven IBAN-nummer.'], 'tel-nr' => [ 'en' => 'Tel.', 'nl' => 'Tel.'], 'total' => [ 'en' => 'Total', 'nl' => 'Totaal'], 'vat' => [ 'en' => 'VAT', 'nl' => 'BTW'], 'mail-offer-subject' => [ 'en' => 'Your invoice', 'nl' => 'Uw factuur'], 'mail-offer' => [ 'en' => "Dear {{getContact-name}},\r\n\r\nPlease find attached your invoice. You can either pay by bank transfer, as indicated on the invoice, or using a credit card on {{getPaymentUrl}}.\r\n\r\nThank you in advance,\r\n\r\n{{{invoice_name}}}", 'nl' => "Beste {{getContact-name}},\r\n\r\nBijgevoegd vindt u uw factuur. U kunt per bankoverschrijving betalen, zoals aangegeven op de factuur, of met een credit card op {{getPaymentUrl}}.\r\n\r\nAlvast hartelijk dank,\r\n\r\n{{{invoice_name}}}"], 'mail-offer-paid-subject' => [ 'en' => 'Your invoice has been paid', 'nl' => 'Uw factuur is betaald'], 'mail-offer-paid' => [ 'en' => "Dear {{getOffer-getContact-name}},\r\n\r\nYour invoice at {{getOffer-getPaymentUrl}} has been paid.\r\n\r\nThank you,\r\n\r\n{{{invoice_name}}}", 'nl' => "Beste {{getOffer-getContact-name}},\r\n\r\nUw factuur op {{getOffer-getPaymentUrl}} is betaald.\r\n\r\nHartelijk dank,\r\n\r\n{{{invoice_name}}}"], ]; /** @var $page_height The height of a page in millimeters */ protected static $page_height = 297; // A4 /** @var $margin_bottom The bottom margin in millimeters */ protected static $margin_bottom = 30; /** * Translate a string * * @see $translations The array holding the translations * * @param string $key The string to translate * * @return string The translated string */ public function _($key) { if (!array_key_exists($key, self::$translations)) return $key; return self::$translations[$key][$this->language]; } /** * Translate a string, statically * * @param string $key The string to translate * @param string $lang The language to translate to (two-letter code) * * @return string The translated string */ public static function __($key, $lang) { if (!array_key_exists($key, self::$translations)) return $key; if (!array_key_exists($lang, self::$translations[$key])) return $key; return self::$translations[$key][$lang]; } /** * Translate a string, statically, and resolve (@see resolve) it * * @param string $key The string to translate * @param string $lang The language to translate to (two-letter code) * @param mixed $obj The object to resolve * * @return string The resolved translated string */ public static function __r($key, $lang, $obj) { return self::resolve(self::__($key, $lang), $obj); } /** * Resolve a string * * Resolves {{keyA-keyB-keyC}} to e.g. $obj->keyA()->keyB->keyC(), where * first the function (e.g. keyA()) is tried, and then the property (e.g. * keyB). * * Resolves {{{const}}} to Constants::const. * * @param string $string The string to resolve * @param mixed $obj The object to use * * @return string The generated string */ public static function resolve($string, $obj) { $string = preg_replace_callback('/\{\{\{(\w+)\}\}\}/', function ($matches) { $key = $matches[1]; return constant("Constants::$key"); }, $string); $string = preg_replace_callback('/\{\{([\w-]+)\}\}/', function ($matches) use ($obj) { $keys = explode('-', $matches[1]); $temp = $obj; foreach ($keys as $key) { if (method_exists($temp, $key)) { $temp = call_user_func([$temp, $key]); } else { $temp = $temp->$key; } } return $temp; }, $string); return $string; } /** * Create a new PDF * * @param string $orientation See the FPDF class specs * @param string $unit See the FPDF class specs * @param string $size See the FPDF class specs */ function __construct() { $this->FPDF('P','mm','A4'); $this->SetMargins(30,20,20); $this->SetAuthor(Constants::invoice_name); $this->SetCreator('BusinessAdmin Correspondence Generator'); $this->SetDisplayMode('fullpage','continuous'); } /** * Workaround for euro signs * * Euro signs in FPDF should be chr(128). Other signs don't have to be changed. * * @return a valuta symbol that can be used in FPDF */ public static function valuta() { switch (Constants::invoice_valuta) { case '€': return chr(128); default: return Constants::invoice_valuta; } } /** * Set the language of the correspondence (used to translate stuff) * * @param string $lang The language, two letter code ('en', 'nl', ...) */ function SetLangauge($lang) { $supported = array('nl', 'en'); if (!in_array($lang, $supported)) { throw new Exception("Language not supported"); } else { $this->language = $lang; } } /** * Set the contact to whom this correspondence will be sent (used for the address) * * @param contact $contact The contact */ function SetContact($contact) { $this->contact = $contact; $this->language = $contact->language; } /** * Makes a header with your details and the address of the contact */ function CorrespondenceHeader() { if (file_exists(Constants::files_folder . 'logo-correspondence.png')) { $this->Image(Constants::files_folder . 'logo-correspondence.png',30,20,50); } $this->SetFont('Helvetica','',7); $this->Cell(110,20); $this->Cell(12,1,' ','T'); $this->Cell(2,1); $this->Cell(35,1,' ','T'); $this->Ln(); $this->Cell(110,3.5); $this->SetFont('','B'); $this->Cell(12,3.5,$this->_('adres'),'',0,'R'); $this->Cell(2,3.5); $this->SetFont('',''); $this->Cell(35,3.5, Constants::invoice_name); $this->Ln(); $this->Cell(124,3.5); $this->Cell(35,3.5, Constants::invoice_address_1); $this->Ln(); $this->Cell(124,3.5); $this->Cell(35,3.5, Constants::invoice_address_2); $this->Ln(); $this->Cell(124,3.5); $this->Cell(35,3.5, Constants::invoice_address_3); $this->Ln(); $this->Cell(160,1.5); $this->Ln(); $this->Cell(110,3.5); $this->SetFont('','B'); $this->Cell(12,3.5,$this->_('btwnr'),'',0,'R'); $this->Cell(2,3.5); $this->SetFont('',''); $this->Cell(35,3.5, Constants::invoice_tax_nr); $this->Ln(); $this->Cell(160,1.5); $this->Ln(); $this->Cell(110,3.5); $this->SetFont('','B'); $this->Cell(12,3.5, $this->_('iban'),'',0,'R'); $this->Cell(2,3.5); $this->SetFont('',''); $this->Cell(35,3.5, Constants::invoice_iban); $this->Ln(); $this->Cell(160,1.5); $this->Ln(); $this->Cell(110,3.5); $this->SetFont('','B'); $this->Cell(12,3.5, $this->_('tel-nr'),'',0,'R'); $this->Cell(2,3.5); $this->SetFont('','',7); $this->Cell(35,3.5, Constants::invoice_tel_nr); $this->Ln(); $this->Cell(110,3.5); $this->SetFont('','B'); $this->Cell(12,3.5, $this->_('email'),'',0,'R'); $this->Cell(2,3.5); $this->SetFont('',''); $this->Cell(35,3.5, Constants::invoice_email); $this->Ln(); $this->Cell(110,1); $this->Cell(12,1,' ','B'); $this->Cell(2,1); $this->Cell(35,1,' ','B'); $this->Ln(); $this->Cell(160,15); $this->Ln(); $this->SetFont('','',11); $this->SetXY(30,56.5); $this->Cell(90,5.5,utf8_decode($this->contact->name)); $this->Ln(); $this->SetXY(30,61.5); $this->Cell(90,5.5,utf8_decode($this->contact->address)); $this->Ln(); $this->SetXY(30,66.5); $this->Cell(90,5.5,utf8_decode($this->contact->postal_code.' '.$this->contact->city)); $this->Ln(); $this->SetXY(30,71.5); $this->Cell(90,5.5,utf8_decode($this->contact->country)); $this->Ln(); } /** * Put PDF information */ function _putinfo() { $this->_out('/Producer '.$this->_textstring('BusinessAdmin Correspondence Generator')); if(!empty($this->title)) $this->_out('/Title '.$this->_textstring($this->title)); if(!empty($this->subject)) $this->_out('/Subject '.$this->_textstring($this->subject)); if(!empty($this->author)) $this->_out('/Author '.$this->_textstring($this->author)); if(!empty($this->keywords)) $this->_out('/Keywords '.$this->_textstring($this->keywords)); if(!empty($this->creator)) $this->_out('/Creator '.$this->_textstring($this->creator)); $this->_out('/CreationDate '.$this->_textstring('D:'.@date('YmdHis'))); } /** * Have we reached the bottom of the page yet? * * @return bool */ public function endOfPage() { return ($this->GetY() > self::$page_height - self::$margin_bottom); } /** * Start a new page if we're on the end */ public function addPageIfOnEnd() { if ($this->endOfPage()) { $this->Ln(); $this->AddPage(); $this->Cell(100, 5, ''); // blank line $this->Ln(); } } }