315 lines
8.7 KiB
PHP
315 lines
8.7 KiB
PHP
<?php
|
|
/**
|
|
* AgileBill - Open Billing Software
|
|
*
|
|
* This body of work is free software; you can redistribute it and/or
|
|
* modify it under the terms of the Open AgileBill License
|
|
* License as published at http://www.agileco.com/agilebill/license1-4.txt
|
|
*
|
|
* Originally authored by Joseph Benden
|
|
* Modifications by Tony Landis, AgileBill LLC
|
|
*
|
|
* Recent modifications by Deon George
|
|
*
|
|
* @author Deon George <deonATleenooksDOTnet>
|
|
* @copyright 2009 Deon George
|
|
* @link http://osb.leenooks.net
|
|
*
|
|
* @link http://www.agileco.com/
|
|
* @copyright 2004-2008 Agileco, LLC.
|
|
* @license http://www.agileco.com/agilebill/license1-4.txt
|
|
* @author Tony Landis <tony@agileco.com>
|
|
* @package AgileBill
|
|
* @subpackage Module:Invoice
|
|
*/
|
|
|
|
define('FPDF_FONTPATH',PATH_INCLUDES.'pdf/font/');
|
|
require_once(PATH_INCLUDES.'pdf/fpdi.php');
|
|
require_once(PATH_INCLUDES.'pdf/fpdf_tpl.php');
|
|
require_once(PATH_INCLUDES.'pdf/fpdf.php');
|
|
|
|
/**
|
|
* PDF Invoice Base
|
|
*
|
|
* @package AgileBill
|
|
* @subpackage Module:Invoice
|
|
*/
|
|
abstract class pdf_invoice_base extends fpdi {
|
|
protected $billToCompany = true;
|
|
protected $itemsSummaryMax = 16;
|
|
protected $itemsPreviousMax = 5;
|
|
protected $news = '';
|
|
protected $pageType = 'blank';
|
|
protected $show_itemized = true;
|
|
protected $show_service_range = false;
|
|
private $invoiceCurrency = '$';
|
|
private $invoiceDecimals = 2;
|
|
|
|
# Store previous invoices due
|
|
private $itemsPrevious = array();
|
|
# Stores the invoice items
|
|
protected $invoice;
|
|
protected $itemsFull;
|
|
protected $account;
|
|
# Iteration of drawing the items on the invoice
|
|
protected $iteration;
|
|
# Store the date range, that the invoice covers
|
|
protected $dateRange;
|
|
|
|
public function __construct($inv) {
|
|
parent::__construct();
|
|
|
|
$this->SetCreator('Open Source Billing');
|
|
$this->SetAuthor($inv->print['site']['NAME']);
|
|
$this->SetTitle(sprintf('%s Invoice',$inv->print['site']['NAME']));
|
|
$this->SetSubject(sprintf('Invoice #%06s',$inv->getInvoiceNum()));
|
|
$this->SetKeywords($inv->getInvoiceID());
|
|
$this->SetAutoPageBreak(TRUE,25);
|
|
$this->SetDisplayMode('fullwidth');
|
|
|
|
return $this;
|
|
}
|
|
|
|
public function load_setup(&$rs) {
|
|
if (! $rs) {
|
|
$db =& DB();
|
|
$rs = $db->Execute(sqlSelect($db,'setup_invoice','*',''));
|
|
}
|
|
|
|
$this->billToCompany = $rs->fields['bill_to_company'];
|
|
$this->invoiceCurrency = $rs->fields['invoice_currency'];
|
|
$this->invoiceDecimals = $rs->fields['invoice_decimals'];
|
|
$this->itemsSummaryMax = $rs->fields['items_summary_max'];
|
|
$this->news = $rs->fields['news'];
|
|
$this->pageType = $rs->fields['page_type'];
|
|
$this->show_itemized = $rs->fields['invoice_show_itemized'];
|
|
$this->show_service_range = $rs->fields['invoice_show_service_dates'];
|
|
}
|
|
|
|
abstract public function drawCompanyLogo();
|
|
abstract public function drawCompanyAddress($inv);
|
|
abstract public function drawInvoiceHeader($inv);
|
|
|
|
/**
|
|
* Enable re-iteration of the invoices items, so that they can be displayed many ways
|
|
*/
|
|
abstract public function drawLineItems_pre($iteration);
|
|
|
|
/**
|
|
* This is called for each line item.
|
|
*/
|
|
abstract public function drawLineItems($db,$line,$invnum);
|
|
|
|
/**
|
|
* Draws the summary on the first page
|
|
*/
|
|
abstract public function drawSummaryLineItems($inv);
|
|
abstract public function drawPaymentMethods($inv);
|
|
|
|
public function drawRemittenceStub() {}
|
|
public function drawCustom() {}
|
|
public function drawInvoiceDueNotice() {}
|
|
public function drawInvoicePaidNotice() {}
|
|
public function setLateFeeNotice() {}
|
|
|
|
/**
|
|
* Get a blank invoice template
|
|
*/
|
|
public function getTemplate() {
|
|
return PATH_THEMES.DEFAULT_THEME.'/invoice/invoice-'.$this->pageType.'.pdf';
|
|
}
|
|
|
|
/**
|
|
* Assigns the invoice fields to this object.
|
|
*/
|
|
public function setInvoiceFields($flds) {
|
|
$this->invoice = $flds;
|
|
}
|
|
|
|
/**
|
|
* Assigns the account fields to this object.
|
|
*/
|
|
public function setAccountFields($flds) {
|
|
$this->account = $flds;
|
|
}
|
|
|
|
public function setItemsFull($items) {
|
|
$this->itemsFull = $items;
|
|
}
|
|
|
|
public function setItemsPrevious($items) {
|
|
$this->itemsPrevious = $items;
|
|
}
|
|
|
|
public function setDateRange($periodStart,$periodEnd) {
|
|
$this->dateRange = sprintf('%s - %s',date(UNIX_DATE_FORMAT,$periodStart),date(UNIX_DATE_FORMAT,$periodEnd));
|
|
}
|
|
|
|
public function setCurrency($currency) {
|
|
$this->invoiceCurrency = $currency;
|
|
}
|
|
|
|
public function setDecimals($decimals) {
|
|
$this->invoiceDecimals = $decimals;
|
|
}
|
|
|
|
/**
|
|
* Render an amount into a currency display
|
|
*/
|
|
protected function _currency($num) {
|
|
global $C_list;
|
|
|
|
if ($this->invoiceDecimals>3)
|
|
return $this->invoiceCurrency.number_format($num,$this->invoiceDecimals);
|
|
else
|
|
return $C_list->format_currency_num($num,$this->invoice['actual_billed_currency_id']);
|
|
}
|
|
|
|
/**
|
|
* Override fpdf functions
|
|
*/
|
|
public function _putpages() {
|
|
$nb = $this->page;
|
|
if (! empty($this->AliasNbPages)) {
|
|
//Replace number of pages
|
|
for ($n=1;$n<=$nb;$n++)
|
|
$this->pages[$n]=($this->compress) ? gzcompress(str_replace($this->AliasNbPages,$nb,gzuncompress($this->pages[$n]))) : str_replace($this->AliasNbPages,$nb,$this->pages[$n]) ;
|
|
}
|
|
|
|
if ($this->DefOrientation=='P') {
|
|
$wPt=$this->fwPt;
|
|
$hPt=$this->fhPt;
|
|
} else {
|
|
$wPt=$this->fhPt;
|
|
$hPt=$this->fwPt;
|
|
}
|
|
|
|
$filter=($this->compress) ? '/Filter /FlateDecode ' : '';
|
|
for($n=1;$n<=$nb;$n++) {
|
|
//Page
|
|
$this->_newobj();
|
|
$this->_out('<</Type /Page');
|
|
$this->_out('/Parent 1 0 R');
|
|
if (isset($this->OrientationChanges[$n]))
|
|
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$hPt,$wPt));
|
|
$this->_out('/Resources 2 0 R');
|
|
if(isset($this->PageLinks[$n])) {
|
|
//Links
|
|
$annots='/Annots [';
|
|
foreach($this->PageLinks[$n] as $pl) {
|
|
$rect=sprintf('%.2f %.2f %.2f %.2f',$pl[0],$pl[1],$pl[0]+$pl[2],$pl[1]-$pl[3]);
|
|
$annots.='<</Type /Annot /Subtype /Link /Rect ['.$rect.'] /Border [0 0 0] ';
|
|
if(is_string($pl[4]))
|
|
$annots.='/A <</S /URI /URI '.$this->_textstring($pl[4]).'>>>>';
|
|
else {
|
|
$l=$this->links[$pl[4]];
|
|
$h=isset($this->OrientationChanges[$l[0]]) ? $wPt : $hPt;
|
|
$annots.=sprintf('/Dest [%d 0 R /XYZ 0 %.2f null]>>',1+2*$l[0],$h-$l[1]*$this->k);
|
|
}
|
|
}
|
|
$this->_out($annots.']');
|
|
}
|
|
$this->_out('/Contents '.($this->n+1).' 0 R>>');
|
|
$this->_out('endobj');
|
|
//Page content
|
|
$this->_newobj();
|
|
$this->_out('<<'.$filter.'/Length '.strlen($this->pages[$n]).'>>');
|
|
$this->_putstream($this->pages[$n]);
|
|
$this->_out('endobj');
|
|
}
|
|
|
|
//Pages root
|
|
$this->offsets[1]=strlen($this->buffer);
|
|
$this->_out('1 0 obj');
|
|
$this->_out('<</Type /Pages');
|
|
$kids='/Kids [';
|
|
for ($i=0;$i<$nb;$i++)
|
|
$kids.=(3+2*$i).' 0 R ';
|
|
$this->_out($kids.']');
|
|
$this->_out('/Count '.$nb);
|
|
$this->_out(sprintf('/MediaBox [0 0 %.2f %.2f]',$wPt,$hPt));
|
|
$this->_out('>>');
|
|
$this->_out('endobj');
|
|
}
|
|
|
|
public function _endpage() {
|
|
//End of page contents
|
|
$this->pages[$this->page] = ($this->compress) ? gzcompress($this->pages[$this->page]) : $this->pages[$this->page];
|
|
$this->state=1;
|
|
}
|
|
|
|
protected function RoundedRect($x,$y,$w,$h,$r,$style='') {
|
|
$k = $this->k;
|
|
$hp = $this->h;
|
|
|
|
if ($style=='F')
|
|
$op = 'f';
|
|
elseif ($style=='FD' || $style=='DF')
|
|
$op = 'B';
|
|
else
|
|
$op = 'S';
|
|
|
|
$MyArc = 4/3*(sqrt(2)-1);
|
|
$this->_out(sprintf('%.2f %.2f m',($x+$r)*$k,($hp-$y)*$k));
|
|
$xc = $x+$w-$r ;
|
|
$yc = $y+$r;
|
|
$this->_out(sprintf('%.2f %.2f l',$xc*$k,($hp-$y)*$k));
|
|
|
|
$this->_Arc($xc+$r*$MyArc,$yc-$r,$xc+$r,$yc-$r*$MyArc,$xc+$r,$yc);
|
|
$xc = $x+$w-$r;
|
|
$yc = $y+$h-$r;
|
|
$this->_out(sprintf('%.2f %.2f l',($x+$w)*$k,($hp-$yc)*$k));
|
|
|
|
$this->_Arc($xc+$r,$yc+$r*$MyArc,$xc+$r*$MyArc,$yc+$r,$xc,$yc+$r);
|
|
$xc = $x+$r;
|
|
$yc = $y+$h-$r;
|
|
$this->_out(sprintf('%.2f %.2f l',$xc*$k,($hp-($y+$h))*$k));
|
|
|
|
$this->_Arc($xc-$r*$MyArc,$yc+$r,$xc-$r,$yc+$r*$MyArc,$xc-$r,$yc);
|
|
$xc = $x+$r;
|
|
$yc = $y+$r;
|
|
$this->_out(sprintf('%.2f %.2f l',($x)*$k,($hp-$yc)*$k));
|
|
|
|
$this->_Arc($xc-$r,$yc-$r*$MyArc,$xc-$r*$MyArc,$yc-$r,$xc,$yc-$r);
|
|
$this->_out($op);
|
|
}
|
|
|
|
private function _Arc($x1,$y1,$x2,$y2,$x3,$y3) {
|
|
$h = $this->h;
|
|
$this->_out(sprintf('%.2f %.2f %.2f %.2f %.2f %.2f c ',
|
|
$x1*$this->k,($h-$y1)*$this->k,$x2*$this->k,($h-$y2)*$this->k,$x3*$this->k,($h-$y3)*$this->k));
|
|
}
|
|
|
|
protected function Rotate($angle,$x=-1,$y=-1) {
|
|
if ($x==-1)
|
|
$x = $this->x;
|
|
if ($y==-1)
|
|
$y = $this->y;
|
|
if ($this->angle!=0)
|
|
$this->_out('Q');
|
|
$this->angle = $angle;
|
|
|
|
if ($angle != 0) {
|
|
$angle *= M_PI/180;
|
|
$c = cos($angle);
|
|
$s = sin($angle);
|
|
$cx = $x*$this->k;
|
|
$cy = ($this->h-$y)*$this->k;
|
|
$this->_out(sprintf('q %.5f %.5f %.5f %.5f %.2f %.2f cm 1 0 0 1 %.2f %.2f cm',$c,$s,-$s,$c,$cx,$cy,-$cx,-$cy));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a watermark to the PDF
|
|
*/
|
|
public function addWaterMark($text) {
|
|
$this->SetFont('arial','B',50);
|
|
$this->SetTextColor(203,203,203);
|
|
$this->Rotate(0);
|
|
$this->Text(10,50,$text);
|
|
$this->Rotate(0);
|
|
$this->SetTextColor(0,0,0);
|
|
}
|
|
}
|
|
?>
|