[Vtigercrm-developers] [PATCH] TeX rendering API and invoice pdf

Enrico Weigelt weigelt at metux.de
Wed Sep 26 05:50:45 PDT 2007


Hi folks,

these patches add an universal rendering API for things like 
invoices and an TeX renderer backend. The old invoice pdf code 
is changed to run via the rendering API. Now it's very easy to 
add new renderers. I also included my own templates as example.

The API patch (renderapi-1) does not change anything but just
adding some new files in the lib/render/ subdir and could be 
applied to 5.1 and 5.1_jens asap.

cu
-- 
----------------------------------------------------------------------
 Enrico Weigelt, metux IT service -- http://www.metux.de/

 cellphone: +49 174 7066481   email: info at metux.de   skype: nekrad666
----------------------------------------------------------------------
 Embedded-Linux / Portierung / Opensource-QM / Verteilte Systeme
----------------------------------------------------------------------
-------------- next part --------------
diff -ruN htdocs.orig/lib/render/README htdocs/lib/render/README
--- htdocs.orig/lib/render/README	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/lib/render/README	2007-05-09 13:53:10.000000000 +0200
@@ -0,0 +1 @@
+This subdirectory contains the TeX rendering stuff.
diff -ruN htdocs.orig/lib/render/RenderFactory.php htdocs/lib/render/RenderFactory.php
--- htdocs.orig/lib/render/RenderFactory.php	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/lib/render/RenderFactory.php	2007-05-09 17:05:57.000000000 +0200
@@ -0,0 +1,64 @@
+<?php
+
+if (!defined('RENDER_LIB_PREFIX'))
+    define('RENDER_LIB_PREFIX', 'lib/render/');
+
+class E_Render_UnknownEngine extends Exception
+{
+    var $engine;
+    
+    function E_Render_Exception($e)
+    {
+	$this->engine = $e;
+    }
+
+    function __toString()
+    {
+	return "Unknown Engine: \"".$this->engine."\"";
+    }
+}
+	
+class E_Render_FormatNotSupportedByEngine extends Exception
+{
+    var $engine;
+    var $format;
+
+    function E_Render_FormatNotSupportedByEngine($format,$engine)
+    {
+	$this->format = $format;
+	$this->engine = $engine;
+    }
+    
+    function __toString()
+    {
+	return "Format \"".$this->format.
+	       "\" not supported by engine \"".
+	       $this->engine.
+	       "\"";
+    }
+}
+
+class RenderFactory
+{
+    /* public static */ function getRenderer_Invoice($param)
+    {
+	if (!($f = $param{'format'}))
+	    throw new Exception("missing output format");
+	if (!($e = $param{'engine'}))
+	    throw new Exception("missing engine");
+	    
+	switch ($e)
+	{
+	    case 'pdflatex':
+	    {
+		if ($f != 'application/pdf')
+		    throw new E_Render_FormatNotSupportedByEngine($f,$e);
+		
+		require_once(RENDER_LIB_PREFIX.'TexRender_Invoice.php');
+		return new TexRender_Invoice($param);
+	    }
+	    default:
+		throw new E_Render_UnknownEngine($e);
+	}
+    }
+}
diff -ruN htdocs.orig/lib/render/TexEncode.php htdocs/lib/render/TexEncode.php
--- htdocs.orig/lib/render/TexEncode.php	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/lib/render/TexEncode.php	2007-05-10 02:51:50.000000000 +0200
@@ -0,0 +1,101 @@
+<?php
+
+// FIXME: support more languages
+
+class TexEncode
+{
+    function Date($date, $lang)
+    {
+	switch($lang)
+	{
+	    case 'en':	return TexEncode::Date_en($date);
+	    case 'de':	return TexEncode::Date_de($date);
+	    default:	throw new Exception("unsupported language $lang");
+	}
+    }
+    
+    function Date_de($date)
+    {
+	if (preg_match('~([0-9]+)-([0-9]+)-([0-9]+)~', $date, $m))
+        {
+	    $text = $m[3].'.';
+	    switch ($m[2])
+	    {
+		case 1:		$text .= ' Jan ';	break;
+		case 2:		$text .= ' Feb. '; 	break;
+	        case 3:		$text .= ' M"arz ';	break;
+	        case 4:		$text .= ' Apr. ';	break;
+	        case 5:		$text .= ' Mai ';	break;
+		case 6:		$text .= ' Jun. ';	break;
+	        case 7:		$text .= ' Jul. ';	break;
+		case 8:		$text .= ' Aug. ';	break;
+		case 9:		$text .= ' Sep. ';	break;
+		case 10:	$text .= ' Okt. ';	break;
+		case 11:	$text .= ' Nov. ';	break;
+		case 12:	$text .= ' Dez. ';	break;
+		default:	$text .= $m[2].'.';	break;
+	    }
+	    $text .= $m[1];
+	}
+	else $text = $date;
+	return $text;
+    }
+
+    function Date_en($date)
+    {
+	if (preg_match('~([0-9]+)-([0-9]+)-([0-9]+)~', $date, $m))
+        {
+	    $text = $m[3].'.';
+	    switch ($m[2])
+	    {
+		case 1:		$text .= ' Jan ';	break;
+		case 2:		$text .= ' Feb. '; 	break;
+	        case 3:		$text .= ' March ';	break;
+	        case 4:		$text .= ' Apr. ';	break;
+	        case 5:		$text .= ' May ';	break;
+		case 6:		$text .= ' June ';	break;
+	        case 7:		$text .= ' July ';	break;
+		case 8:		$text .= ' Aug. ';	break;
+		case 9:		$text .= ' Sep. ';	break;
+		case 10:	$text .= ' Oct. ';	break;
+		case 11:	$text .= ' Nov. ';	break;
+		case 12:	$text .= ' Dec. ';	break;
+		default:	$text .= $m[2].'.';	break;
+	    }
+	    $text .= $m[1];
+	}
+	else $text = $date;
+	return $text;
+    }
+    
+    function text($text)
+    {
+	return str_replace("\n",'\\ \\\\',
+	       str_replace("\r",'\\ \\\\', 
+	       TexEncode::escape($text)));
+    }
+
+    function escape ( $text )
+    {
+	return 
+	str_replace ( '#', '\#',
+        str_replace ( '&', '\&',
+	str_replace ( '$', '\$',
+	str_replace ( '~', '\~',
+	str_replace ( '_', '\_',
+	str_replace ( '&auml;',  '"a',
+	str_replace ( '&Auml;',  '"A',
+	str_replace ( '&Uuml;',  '"U',
+	str_replace ( '&uuml;',  '"u',
+	str_replace ( '&Ouml;',  '"O',
+	str_replace ( '&ouml;',  '"o',
+	str_replace ( '&szlig;', '"s', 
+	str_replace ( '"', '\"',
+	htmlentities ( $text ))))))))))))));
+    }
+
+    function money ( $val )
+    {
+	return sprintf ( '%01.2f', $val );
+    }
+}
diff -ruN htdocs.orig/lib/render/TexRender_Invoice.php htdocs/lib/render/TexRender_Invoice.php
--- htdocs.orig/lib/render/TexRender_Invoice.php	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/lib/render/TexRender_Invoice.php	2007-05-10 16:55:44.000000000 +0200
@@ -0,0 +1,217 @@
+<?php
+
+/* TeX rendering engine for invoices 
+   
+   2007-05-09 Enrico Weigelt <weigelt at metux.de>
+   
+*/
+
+// NOTE: the webserver needs *write* acccess to this directory
+//       we normally take the session storage dir
+define('TEXRENDER_TMP_MASK',     '{SESSION.SAVE_PATH}/texrender-{SESSION.ID}-{NAME}');
+define('TEXRENDER_TEMPLATE_DIR', 'templates/tex/{TEMPLATE-NAME}/');
+
+require_once(RENDER_LIB_PREFIX.'TexEncode.php');
+
+class TexRender_Invoice
+{
+    /* private */ var $tmpmask;
+    /* private */ var $data;
+    /* private */ var $product_items;
+    /* private */ var $fn_tex;
+    /* private */ var $fn_pdf;
+    /* private */ var $fn_template;
+    /* private */ var $key;
+    
+    /* private */ function _tmpname($name)
+    {
+	return str_replace('{SESSION.NAME}',      session_name(),
+	       str_replace('{SESSION.ID}',        session_id(),
+	       str_replace('{SESSION.SAVE_PATH}', realpath(ini_get('session.save_path')),
+	       str_replace('{NAME}',              $name,
+	       $this->tmpmask
+	))));
+    }
+
+    /* private */ function _test_write_access()
+    {
+	$fn = $this->_tmpname('write-test');
+	if (!($fp=fopen($fn,"w")))
+	    throw new Exception("write-test: could not open file for writing: $fn");
+	fputs($fp,"TEST123");
+	fclose($fp);
+	
+	$res = trim(implode('',file($fn)));
+	if ($res != "TEST123")
+	    throw new Exception("write-test: reading test data failed for file: $fn");
+	
+	unlink($fn);
+
+	return true;
+    }
+
+    function TexRender_Invoice($param)
+    {
+	// test write access and otherwise failed
+	$this->tmpmask = TEXRENDER_TMP_MASK;
+	
+	// should be already cought by the factory, but just to be sure
+	if ($param{'format'} != 'application/pdf')
+	    throw new Exception("fomat not supported by this renderer: ".$param{'format'});
+	
+	if (!$param{'template'})
+	    throw new Exception("missing template name");
+
+	$this->template_name = $param{'template'};
+	$this->data = array();
+	$this->_test_write_access();
+	$this->key = md5(serialize(gettimeofday));
+	$this->fn_tex = $this->_tmpname($this->key.'.tex');
+	$this->fn_pdf = $this->_tmpname($this->key.'.pdf');
+	$this->template_dir= realpath(str_replace('{TEMPLATE-NAME}', $this->template_name,TEXRENDER_TEMPLATE_DIR));
+	$this->fn_template_main = $this->template_dir.'/invoice/main.texi';
+	$this->fn_template_item = $this->template_dir.'/invoice/item.texi';
+
+	$inc = $this->template_dir.'/config.php';
+	if (!include($inc))
+	    throw new Exception("could not load config: $inc");
+	    
+	if (!is_array($this->config = $tex_template_config))
+	    throw new Exception("missing template config");
+	
+	if (!$this->config{'lang'})
+	    throw new Exception("language not set in template config");
+    }
+
+    function addData($par)
+    {
+	foreach($par as $walk => $cur)
+	    $this->data{$walk} = $cur;
+    }
+
+    function checkProductItem($item)
+    {
+	if (!$item{'name'})
+	    throw new Exception("missing item name");
+	if (!$item{'amount'})
+	    throw new Exception("missing amount");
+	if (!is_numeric($item{'amount'}))
+	    throw new Exception("amount must be numeric");
+	if (!$item{'price'})
+	    throw new Exception("missing price");
+	if (!is_numeric($item{'price'}))
+	    throw new Exception("price must be numeric");
+	if (($item{'discount'})&&($item{'discount'} != 0))
+	    throw new Exception("discount not supported yet by this renderer");
+	if (!is_numeric($item{'tax_percent'}))
+	    throw new Exception("tax_percent must be numeric");
+    }
+
+    function checkData()
+    {
+	if ((!is_array($this->_product_items)) || 
+	    (!count($this->_product_items)))
+	    throw new Exception("no product items");
+
+	if (!$this->data{'ident'})
+	    throw new Exception("missing ident");
+    }
+    
+    /* public */ function addProductItem($item)
+    {
+	// check for correct items
+	$this->checkProductItem($item);
+
+	// calculate some stuff if necessary
+	if (!$item{'total'}) 
+	    $item{'total'} = $item{'price'} * $item{'amount'};
+	if (!$item{'taxes'})
+	    $item{'taxes'} = $item{'total'} * $item{'tax_percent'};
+	if (!$item{'topay'})
+	    $item{'topay'} = $item{'total'} + $item{'taxes'};
+
+	$this->_product_items[] = $item;
+    }
+
+    /* public String */ function getOutputContentType()
+    {
+	return 'application/pdf';
+    }
+
+    /* private String */ function _generate_tex()
+    {
+	if (!($tmpl_main = implode('',file($this->fn_template_main))))
+	    throw new Exception("could not load main template: ".$this->fn_template_main);
+	if (!($tmpl_item = implode('',file($this->fn_template_item))))
+	    throw new Exception("could not load item template: ".$this->fn_template_item);
+
+	// generate the item list
+	foreach ($this->_product_items as $walk => $cur)
+	{
+	    $items .= 
+	         str_replace('::Item:Name::',        $cur{'name'},
+	         str_replace('::Item:Price::',       TexEncode::money($cur{'price'}),
+		 str_replace('::Item:Amount::',      $cur{'amount'},
+		 str_replace('::Item:Taxrate::',     $cur{'tax_percent'},
+		 str_replace('::Item:Description::', $cur{'description'},
+		 str_replace('::Item:Comment::',     trim($cur{'comment'}),
+		 str_replace('::Item:Discount::',    TexEncode::money($cur{'discount'}),
+		 str_replace('::Item:Total::',       TexEncode::money($cur{'total'}),
+		 str_replace('::Item:Taxes::',       TexEncode::money($cur{'taxes'}),
+		 str_replace('::Item:Topay::',       TexEncode::money($cur{'topay'}),
+		 $tmpl_item))))))))));
+
+	    $all_total += $cur{'total'};
+	    $all_taxes += $cur{'taxes'};
+	    $all_topay += $cur{'topay'};
+	}
+		
+	$content = 
+	    str_replace('::TemplateDir::',           $this->template_dir,
+	    str_replace('::Items::',                 $items,
+	    str_replace('::Bill:Ident::',            $this->data{'ident'},
+            str_replace('::Bill:Total::',            TexEncode::money($all_total),
+	    str_replace('::Bill:Taxes::',            TexEncode::money($all_taxes),
+	    str_replace('::Bill:Topay::',            TexEncode::money($all_topay),
+	    str_replace('::Company:Addr:Street::',   $this->data{'company:addr:street'},
+	    str_replace('::Company:Addr:PCode::',    $this->data{'company:addr:pcode'},
+	    str_replace('::Company:Addr:City::',     $this->data{'company:addr:city'},
+	    str_replace('::Company:Addr:Country::',  $this->data{'company:addr:country'},
+	    str_replace('::Company:Addr:State::',    $this->data{'company:addr:state'},
+	    str_replace('::Company:Phone::',         $this->data{'company:phone'},
+	    str_replace('::Company:Fax::',           $this->data{'company:fax'},
+	    str_replace('::Company:Website::',       $this->data{'company:website'},
+	    str_replace('::Customer:Name::',         $this->data{'customer:name'},
+	    str_replace('::Customer:Addr:Street::',  TexEncode::text($this->data{'billing:addr:street'}),
+	    str_replace('::Customer:Addr:PCode::',   TexEncode::text($this->data{'billing:addr:pcode'}),
+	    str_replace('::Customer:Addr:City::',    TexEncode::text($this->data{'billing:addr:city'}),
+	    str_replace('::Customer:Addr:State::',   TexEncode::text($this->data{'billing:addr:state'}),
+	    str_replace('::Customer:Addr:Country::', TexEncode::text($this->data{'billing:addr:country'}),
+		$tmpl_main))))))))))))))))))));
+
+	return $content;
+    }
+    
+    /* public */ function generate()
+    {
+	$this->checkData();
+	$tex = $this->_generate_tex();
+	@unlink($this->fn_tex);
+	if (!($fp_tex = fopen($this->fn_tex,"w")))
+	    throw new Exception("could not open tex source file: ".$this->fn_tex);
+	
+	fputs($fp_tex,$tex);
+	fclose($fp_tex);
+
+	$cmd = 'cd '.dirname($this->fn_tex).' && pdflatex '.$this->fn_tex;
+	`$cmd` ; `$cmd` ; // call it twice for table calculations
+    }
+    
+    // send appropriate http headers and output file
+    /* public */ function sendHTTPOutput()
+    {
+	$this->generate();
+	Header("Content-Type: ".$this->getOutputContentType());
+	readfile($this->fn_pdf);
+    }
+}
-------------- next part --------------
diff -ruN htdocs.orig/modules/Invoice/CreatePDF.php htdocs/modules/Invoice/CreatePDF.php
--- htdocs.orig/modules/Invoice/CreatePDF.php	2007-05-09 00:56:25.000000000 +0200
+++ htdocs/modules/Invoice/CreatePDF.php	2007-05-10 15:30:08.000000000 +0200
@@ -9,67 +9,36 @@
  *
  ********************************************************************************/
 
-
-require_once('include/fpdf/pdf.php');
-require_once('include/fpdf/pdfconfig.php');
 require_once('modules/Invoice/Invoice.php');
 require_once('modules/Organization/Organization.php');
 require_once('include/database/PearDatabase.php');
 require_once('include/utils/EditViewUtils.php');
+require_once('lib/render/RenderFactory.php');
 
-global $adb,$app_strings,$focus;
-global $log;
-
-// for template checking ...
-$tmpl_dirs = array( "firstpage", "pages", "lastpage");
-$tmpl_files = array( "header.php", "body.php", "footer.php");
+global $adb,$app_strings,$focus,$log;
 
 $sql="select currency_symbol from vtiger_currency_info";
 $result = $adb->query($sql);
 $currency_symbol = $adb->query_result($result,0,'currency_symbol');
 
-// would you like and end page?  1 for yes 0 for no
-$endpage="1";
-
 $id = $_REQUEST['record'];
 
 //retreiving the vtiger_invoice info
 $focus = new Invoice();
 $focus->retrieve_entity_info($_REQUEST['record'],"Invoice");
-$account_name = getAccountName($focus->column_fields[account_id]);
-$invoice_no = $focus->column_fields[invoice_no];
 
 // **************** BEGIN POPULATE DATA ********************
 
-
-// populate data
 if($focus->column_fields["salesorder_id"] != '')
 	$so_name = getSoName($focus->column_fields["salesorder_id"]);
 else
 	$so_name = '';
 $po_name = $focus->column_fields["purchaseorder"];
 
-$valid_till = $focus->column_fields["duedate"];
-$valid_till = getDisplayDate($valid_till);
-$bill_street = $focus->column_fields["bill_street"];
-$bill_city = $focus->column_fields["bill_city"];
-$bill_state = $focus->column_fields["bill_state"];
-$bill_code = $focus->column_fields["bill_code"];
-$bill_country = $focus->column_fields["bill_country"];
-
-$contact_name =getContactName($focus->column_fields["contact_id"]);
-$ship_street = $focus->column_fields["ship_street"];
-$ship_city = $focus->column_fields["ship_city"];
-$ship_state = $focus->column_fields["ship_state"];
-$ship_code = $focus->column_fields["ship_code"];
-$ship_country = $focus->column_fields["ship_country"];
-
-$conditions = from_html($focus->column_fields["terms_conditions"]);
-$description = from_html($focus->column_fields["description"]);
-$status = $focus->column_fields["invoicestatus"];
-
 // Company information
-$crmid = $focus->column_fields["record_id"];
+if (!($crmid = $focus->column_fields["record_id"]))
+    throw new Exception("crmid is null/empty");
+
 $org_query = "select organizationname from vtiger_entity2org where crmid='".$crmid."'";
 $result = $adb->query($org_query);
 $org_rows = $adb->num_rows($result);
@@ -82,7 +51,7 @@
     $org_name = $adb->query_result($result,0,"organizationname");
 } else {
     $log->info( $module. " '".$crmid."' not assigned to any organization");
-    exit();
+    throw new Exception("crmid $crmid not assigned to any organisation (org_name=$org_name)");
 }
 
 // get organization/orgunit details
@@ -92,68 +61,11 @@
 $log->debug( "Here we are: getOrgUnits( $organization, $orgunitid);");
 $orgunittab = getOrgUnits( $organization, $orgunitid);
 
-if( is_array( $orgunittab[$orgunitid])) {
-    $orgdetails = $orgunittab[$orgunitid];
-    $org_name = $orgdetails["name"];
-    $org_address = $orgdetails["address"];
-    $org_city = $orgdetails["city"];
-    $org_state = $orgdetails["state"];
-    $org_country = $orgdetails["country"];
-    $org_code = $orgdetails["code"];
-    $org_phone = $orgdetails["phone"];
-    $org_fax = $orgdetails["fax"];
-    $org_website = $orgdetails["website"];
-    $logo_name = $orgdetails["logoname"];
-    $template = $orgdetails["invoice_template"];
-} else {
-    $log->info( $module. " '".$crmid."' organization/orgunitid mismatch");
-    exit();
-}
-
-// Check the template
-if( $template == "") 
-    $template = "Default";
-
-if( $template != "Default") {
-    foreach( $tmpl_dirs as $dir) {
-	foreach( $tmpl_files as $file) {
-	    if( !file_exists( "modules/".$module."/pdf_templates/".$template."/".$dir."/".$file)) {
-		$log->info( $module. " '".$crmid."' organization/orgunitid template '".$template."' is incomplete");
-		$log->info("Missing file: modules/".$module."/pdf_templates/".$template."/".$dir."/".$file);
-		$log->info("Fallback to the Default template");
-		$template = "Default";
-		break 2;
-	    }
-	}
-    }
-}
-//NOTE : Removed currency symbols and added with Grand Total text. it is enough to show the currency symbol in one place
-
-//we can also get the NetTotal, Final Discount Amount/Percent, Adjustment and GrandTotal from the array $associated_products[1]['final_details']
-
-//getting the Net Total
-$price_subtotal = number_format($focus->column_fields["hdnSubTotal"],2,'.',',');
-
-//Final discount amount/percentage
-$discount_amount = $focus->column_fields["hdnDiscountAmount"];
-$discount_percent = $focus->column_fields["hdnDiscountPercent"];
-
-if($discount_amount != "")
-	$price_discount = number_format($discount_amount,2,'.',',');
-else if($discount_percent != "")
-{
-	//This will be displayed near Discount label - used in include/fpdf/templates/body.php
-	$final_price_discount_percent = "(".number_format($discount_percent,2,'.',',')." %)";
-	$price_discount = number_format((($discount_percent*$focus->column_fields["hdnSubTotal"])/100),2,'.',',');
-}
-else
-	$price_discount = "0.00";
-
-//Adjustment
-$price_adjustment = number_format($focus->column_fields["txtAdjustment"],2,'.',',');
-//Grand Total
-$price_total = number_format($focus->column_fields["hdnGrandTotal"],2,'.',',');
+if(!is_array( $orgunittab[$orgunitid])) 
+    throw new Exception("org/orgunitid mismatch");
 
+$orgdetails  = $orgunittab[$orgunitid];
+$template    = $orgdetails["invoice_template"];
 
 //get the Associated Products for this Invoice
 $focus->id = $focus->column_fields["record_id"];
@@ -166,6 +78,8 @@
 //To calculate the group tax amount
 if($final_details['taxtype'] == 'group')
 {
+	throw new Exception("group tax not supported");
+
 	$group_tax_total = $final_details['tax_totalamount'];
 	$price_salestax = number_format($group_tax_total,2,'.',',');
 
@@ -191,47 +105,37 @@
 $sh_tax_amount = $final_details['shtax_totalamount'];
 $price_shipping_tax = number_format($sh_tax_amount,2,'.',',');
 
+$render = RenderFactory::getRenderer_Invoice(array
+(
+    format	=> 'application/pdf',
+    engine	=> 'pdflatex',
+    template	=> 'default'
+));
 
 //This is to get all prodcut details as row basis
-for($i=1,$j=$i-1;$i<=$num_products;$i++,$j++)
+for($i=1;$i<=$num_products;$i++)
 {
-	$product_name[$i] = $associated_products[$i]['productName'.$i];
-	$prod_description[$i] = $associated_products[$i]['productDescription'.$i];
-	$product_id[$i] = $associated_products[$i]['hdnProductId'.$i];
-	$qty[$i] = $associated_products[$i]['qty'.$i];
-	$unit_price[$i] = number_format($associated_products[$i]['unitPrice'.$i],2,'.',',');
-	$list_price[$i] = number_format($associated_products[$i]['listPrice'.$i],2,'.',',');
-	$list_pricet[$i] = $associated_products[$i]['listPrice'.$i];
-	$discount_total[$i] = $associated_products[$i]['discountTotal'.$i];
-	//aded for 5.0.3 pdf changes
-	$product_code[$i] = $associated_products[$i]['hdnProductcode'.$i];
-	
-	$taxable_total = $qty[$i]*$list_pricet[$i]-$discount_total[$i];
-
-	$producttotal = $taxable_total;
-	$total_taxes = '0.00';
 	if($focus->column_fields["hdnTaxType"] == "individual")
 	{
-		$total_tax_percent = '0.00';
-		//This loop is to get all tax percentage and then calculate the total of all taxes
-		for($tax_count=0;$tax_count<count($associated_products[$i]['taxes']);$tax_count++)
-		{
-			$tax_percent = $associated_products[$i]['taxes'][$tax_count]['percentage'];
-			$total_tax_percent = $total_tax_percent+$tax_percent;
-			$tax_amount = (($taxable_total*$tax_percent)/100);
-			$total_taxes = $total_taxes+$tax_amount;
-		}
-		$producttotal = $taxable_total+$total_taxes;
-		$product_line[$j]["Tax"] = number_format($total_taxes,2,'.',',')."\n ($total_tax_percent %) ";
-	}
-	$prod_total[$i] = number_format($producttotal,2,'.',',');
-
-	$product_line[$j]["Product Code"] = $product_code[$i];
-	$product_line[$j]["Product Name"] = $product_name[$i];
-	$product_line[$j]["Qty"] = $qty[$i];
-	$product_line[$j]["Price"] = $list_price[$i];
-	$product_line[$j]["Discount"] = $discount_total[$i];
-	$product_line[$j]["Total"] = $prod_total[$i];
+	    //This loop is to get all tax percentage and then calculate the total of all taxes
+	    for($tax_count=0;$tax_count<count($associated_products[$i]['taxes']);$tax_count++)
+		$tax_percent = $associated_products[$i]['taxes'][$tax_count]['percentage'];
+	}
+
+	$product_id = $associated_products[$i]['hdnProductId'.$i];
+
+	$render->addProductItem(array
+	(
+	    code	=> $associated_products[$i]['hdnProductcode'.$i],
+	    name	=> $associated_products[$i]['productName'.$i],
+	    amount	=> $associated_products[$i]['qty'.$i],
+	    price	=> $associated_products[$i]['listPrice'.$i],
+	    unit_price  => $associated_products[$i]['unitPrice'.$i],
+	    discount	=> $associated_products[$i]['discountTotal'.$i],
+	    tax_percent => (integer)($tax_percent)/100,
+	    description => $associated_products[$i]['productDescription'.$i],
+	    comment     => $associated_products[$i]['comment'.$i]
+	));
 
 	// Product piecelists
 	$query = "SELECT vtiger_crmentity.crmid,
@@ -245,86 +149,46 @@
 	    INNER JOIN vtiger_crmentity
 		ON vtiger_crmentity.crmid = vtiger_products.productid
 	    WHERE vtiger_crmentity.deleted = 0
-	    AND vtiger_products2products_rel.productid = ".$product_id[$i]."
+	    AND vtiger_products2products_rel.productid = ".$product_id."
 	    AND vtiger_products2products_rel.relation_type = 10";
 	$result = $adb->query($query);
 	$pieces = $adb->num_rows($result);
 	if( $pieces > 0) {
-	    $product_line[++$j]["Product Name"] = "";
-	    $product_line[$j]["Description"] = "consisting of:";
-	    $product_line[$j]["Qty"] = "";
-	    $product_line[$j]["Price"] = "";
-	    $product_line[$j]["Discount"] = "";
-	    $product_line[$j]["Total"] = "";
-	    for( $pl=0; $pl<$pieces; $pl++) {
-	        $product_line[++$j]["Product Name"] = "";
-		$product_line[$j]["Description"] =
-		    $adb->query_result( $result, $pl, "productname");
-		$product_line[$j]["Qty"] =
-		    $adb->query_result( $result, $pl, "quantity");
-		$product_line[$j]["Price"] = "";
-		$product_line[$j]["Discount"] = "";
-		$product_line[$j]["Total"] = "";
-	    }
+	    throw new Exception("multiple pieces not yet supported !");
 	}
 }
 
-//echo '<pre>Product Details ==>';print_r($product_line);echo '</pre>';
-//echo '<pre>';print_r($associated_products);echo '</pre>';
-
 // ************************ END POPULATE DATA ***************************8
 
-$page_num='1';
-$pdf = new PDF( 'P', 'mm', 'A4' );
-$pdf->Open();
-
-$num_pages=ceil(count($product_line)/$products_per_page);
-
-
-$current_product=0;
-for($l=0;$l<$num_pages;$l++)
-{
-	$line=array();
-	if($num_pages == $page_num)
-		$lastpage=1;
-
-	while($current_product != $page_num*$products_per_page)
-	{
-		$line[]=$product_line[$current_product];
-		$current_product++;
-	}
-
-	//if bottom > 145 then we skip the Description and T&C in every
-	//page and display only in lastpage
-	//if you want to display the description and T&C in each page then
-	//set the display_desc_tc='true' and bottom <= 145 in pdfconfig.php
-	$pdf->AddPage();
-	if( $page_num == "1") {
-	    include("pdf_templates/".$template."/firstpage/header.php");
-	    include("pdf_templates/".$template."/firstpage/body.php");
-	    if($display_desc_tc == 'true' && $bottom <= 145)
-		include("pdf_templates/".$template."/firstpage/footer.php");
-	} else {
-	    include("pdf_templates/".$template."/pages/header.php");
-	    include("pdf_templates/".$template."/pages/body.php");
-	    if($display_desc_tc == 'true' && $bottom <= 145)
-		include("pdf_templates/".$template."/pages/footer.php");
-	}
-
-	$page_num++;
-
-	if (($endpage) && ($lastpage))
-	{
-	    $pdf->AddPage();
-	    include("pdf_templates/".$template."/lastpage/header.php");
-	    include("pdf_templates/".$template."/lastpage/body.php");
-	    include("pdf_templates/".$template."/lastpage/footer.php");
-	}
-}
-
-
-$pdf->Output('Invoice-'.$crmid.'.pdf','D'); //added file name to make it work in IE, also forces the download giving the user the option to save
+$render->addData(array
+(
+    'valid_until'		=> $focus->column_fields["duedate"],
+    'description'		=> from_html($focus->column_fields["description"]),
+    'conditions'		=> from_html($focus->column_fields["terms_conditions"]),
+    'tax_type'			=> $focus->column_fields['hdnTaxType'],
+    'ident'			=> $focus->column_fields['invoice_no'],
+    'contact:name'		=> getContactName($focus->column_fields["contact_id"]),
+    'company:name'		=> $orgdetails["name"],
+    'company:addr:city'		=> $orgdetails["city"],
+    'company:addr:pcode'	=> $orgdetails["code"],
+    'company:addr:street'	=> $orgdetails["address"],
+    'company:addr:country'	=> $orgdetails["country"],
+    'company:addr:state'	=> $orgdetails["state"],
+    'company:phone'		=> $orgdetails["phone"],
+    'company:fax'		=> $orgdetails["fax"],
+    'company:website'		=> $orgdetails["website"],
+    'customer:name'		=> getAccountName($focus->column_fields[account_id]),
+    'shipping:addr:city'	=> $focus->column_fields["ship_city"],
+    'shipping:addr:pcode'	=> $focus->column_fields["ship_code"],
+    'shipping:addr:street'	=> $focus->column_fields["ship_street"],
+    'shipping:addr:country'	=> $ship_country = $focus->column_fields["ship_country"],
+    'shipping:addr:state'	=> $focus->column_fields["ship_state"],
+    'billing:addr:city'		=> $focus->column_fields["bill_city"],
+    'billing:addr:pcode'	=> $focus->column_fields["bill_code"],
+    'billing:addr:street'	=> $focus->column_fields["bill_street"],
+    'billing:addr:country'	=> $focus->column_fields["bill_country"],
+    'billing:addr:state'	=> $focus->column_fields["bill_state"]
+));
 
-// Added to fix annoying bug that includes HTML in your PDF
+$render->sendHTTPOutput();
 exit();
-?>
-------------- next part --------------
diff -ruN htdocs.orig/templates/tex/default/config.php htdocs/templates/tex/default/config.php
--- htdocs.orig/templates/tex/default/config.php	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/config.php	2007-05-09 20:00:54.000000000 +0200
@@ -0,0 +1,7 @@
+<?php
+
+$tex_template_config = array 
+(
+    'lang'	=> 'de',
+    'tex2pdf'	=> 'pdflatex'
+);
diff -ruN htdocs.orig/templates/tex/default/invoice/item.texi htdocs/templates/tex/default/invoice/item.texi
--- htdocs.orig/templates/tex/default/invoice/item.texi	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/invoice/item.texi	2007-05-10 14:25:30.000000000 +0200
@@ -0,0 +1,2 @@
+::Item:Name:: \ifempty{::Item:Comment::}{}{(::Item:Comment::)} & ::Item:Price:: \Euro & ::Item:Amount:: & ::Item:Total:: \Euro \\
+\hline
diff -ruN htdocs.orig/templates/tex/default/invoice/main.texi htdocs/templates/tex/default/invoice/main.texi
--- htdocs.orig/templates/tex/default/invoice/main.texi	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/invoice/main.texi	2007-05-10 14:15:53.000000000 +0200
@@ -0,0 +1,53 @@
+\def\ResourcePrefix{::TemplateDir::/resource}
+\input \ResourcePrefix/bill.tex
+
+\def\ifempty#1#2#3{\def\inner{#1}\ifx\inner\empty
+   #2\else #3\fi }
+
+\begin{document}
+    \letterInit
+    \begin{letter}{%
+            ::Customer:Addr:Street:: \ \\
+	    ::Customer:Addr:PCode::\ ::Customer:Addr:City:: \ \\
+           \ \\[\medskipamount]
+	}
+
+	\opening{\Large Ihre Rechnung:\normalsize~~~ ::Bill:Ident::
+%%	~~~~~~~~~~vom:~~::BillDate::
+	}
+
+	\setlength\LTleft{0pt}
+	\setlength\LTright{72pt}
+	\begin{longtable}{|p{300pt}|r|r|r|}
+	    \hline
+	    Leistung         & Preis     & Menge     & Summe 	\\
+	    \hline
+	    \endhead
+	    \hline
+	    \hline
+	    \multicolumn{3}{|l|}{Rechnungsbetrag} & ::Bill:Total:: \Euro \\
+	    \hline
+	    \multicolumn{3}{|l|}{Umsatzsteuer}    & ::Bill:Taxes:: \Euro \\
+	    \hline
+	    \hline
+	    \multicolumn{3}{|l|}{Gesamt}          & ::Bill:Topay:: \Euro \\
+	    \hline
+	    \noalign{
+		\vspace{12pt}
+		\small
+		Soweit nicht anders angegeben entspricht das Lieferdatum
+		dem Rechnungsdatum
+	    }
+	    \noalign{
+		\vspace{12pt}
+		\normalsize
+		Bitte {\"u}berweisen Sie den f{\"a}lligen Betrag binnen 
+		10~Tagen auf eines unserer Konten. \newline
+		Die Ware bleibt bis zur vollst{\"a}ndigen Bezahlung Eigentum 
+		von metux IT service.
+	    }	    
+	    \endlastfoot
+	    ::Items::
+	\end{longtable} 
+    \end{letter}
+\end{document}
diff -ruN htdocs.orig/templates/tex/default/resource/bill.tex htdocs/templates/tex/default/resource/bill.tex
--- htdocs.orig/templates/tex/default/resource/bill.tex	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/resource/bill.tex	2007-05-09 23:55:35.000000000 +0200
@@ -0,0 +1,22 @@
+\input{\ResourcePrefix/metux.tex}
+
+\documentclass[a4paper,bottom=0cm,fromalign=center,fromlogo=true]{scrlttr2}
+\usepackage{epsfig}
+\usepackage{longtable}
+
+\usepackage{ngerman}
+\usepackage[latin1]{inputenc}
+%usepackage{fancyhdr}
+%pagestyle{fancy}
+
+% brief-init
+\newcommand\letterInit{%
+    \captionsgerman
+    \dategerman
+    \firsthead{\metuxHeader}
+    \firstfoot{\metuxFooter}
+    \setkomavar{fromname}{metux IT service}
+    \setkomavar{fromaddress}{Heydaer Stra{\ss}e 23, 99338 Plaue}
+}
+
+\newcommand\Euro{Euro}
diff -ruN htdocs.orig/templates/tex/default/resource/header.eps htdocs/templates/tex/default/resource/header.eps
--- htdocs.orig/templates/tex/default/resource/header.eps	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/resource/header.eps	2002-09-17 01:45:21.000000000 +0200
@@ -0,0 +1,178 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: header.eps
+%%Creator: fig2dev Version 3.2 Patchlevel 3d
+%%CreationDate: Tue Jul 30 18:35:09 2002
+%%For: ems at nibiru.metux.de ()
+%%BoundingBox: 0 0 643 88
+%%Magnification: 1.0000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+newpath 0 88 moveto 0 0 lineto 643 0 lineto 643 88 lineto closepath clip newpath
+-4.5 96.9 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add
+  4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+  bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+  4 -2 roll mul srgb} bind def
+/reencdict 12 dict def /ReEncode { reencdict begin
+/newcodesandnames exch def /newfontname exch def /basefontname exch def
+/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
+basefontdict { exch dup /FID ne { dup /Encoding eq
+{ exch dup length array copy newfont 3 1 roll put }
+{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
+newfont /FontName newfontname put newcodesandnames aload pop
+128 1 255 { newfont /Encoding get exch /.notdef put } for
+newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
+newfontname newfont definefont pop end } def
+/isovec [
+8#055 /minus 8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
+8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
+8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
+8#220 /dotlessi 8#230 /oe 8#231 /OE
+8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
+8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
+8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
+8#255 /hyphen 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
+8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
+8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
+8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
+8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
+8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
+8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
+8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
+8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
+8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
+8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
+8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
+8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
+8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
+8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
+8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
+8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
+8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
+8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
+/Courier-Bold /Courier-Bold-iso isovec ReEncode
+/Times-Bold /Times-Bold-iso isovec ReEncode
+/Times-Roman /Times-Roman-iso isovec ReEncode
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+10 setmiterlimit
+ 0.06000 0.06000 sc
+%
+% Fig objects follow
+%
+/Times-Roman-iso ff 150.00 scf sf
+6600 1200 m
+gs 1 -1 sc (www.metux.de) col8 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+6600 825 m
+gs 1 -1 sc (+49 36207 51833) col8 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+6600 675 m
+gs 1 -1 sc (+49 174 7066481) col8 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+6600 1350 m
+gs 1 -1 sc (contact @ metux.de) col8 sh gr
+/Courier-Bold-iso ff 180.00 scf sf
+1650 750 m
+gs 1 -1 sc (Ihr innovativer IT-Dienstleister) col25 sh gr
+/Times-Bold-iso ff 150.00 scf sf
+5700 1200 m
+gs 1 -1 sc (      Internet) col0 sh gr
+/Times-Bold-iso ff 150.00 scf sf
+5700 675 m
+gs 1 -1 sc (    Telephon) col0 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+1650 1350 m
+gs 1 -1 sc (Advance Bank \(BLZ 702 300 00\), Kto-Nr: 200 72 64 206) col8 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+1650 1575 m
+gs 1 -1 sc (Enrico Weigelt, Steuer-Nr: 154/286/05931) col8 sh gr
+/Times-Bold-iso ff 300.00 scf sf
+75 750 m
+gs 1 -1 sc (metux ITS) col9 sh gr
+/Courier-Bold-iso ff 150.00 scf sf
+150 1350 m
+gs 1 -1 sc (Bankverbindung:) col0 sh gr
+/Courier-Bold-iso ff 150.00 scf sf
+750 1575 m
+gs 1 -1 sc (Inhaber:) col0 sh gr
+/Courier-Bold-iso ff 150.00 scf sf
+225 1125 m
+gs 1 -1 sc (Hausanschrift:) col0 sh gr
+/Times-Roman-iso ff 150.00 scf sf
+1650 1125 m
+gs 1 -1 sc (Heydaer Strasse 23 99338 Plaue) col8 sh gr
+/Times-Roman-iso ff 180.00 scf sf
+10125 300 m
+gs 1 -1 sc (tricktext) col0 sh gr
+$F2psEnd
+rs
diff -ruN htdocs.orig/templates/tex/default/resource/header.fig htdocs/templates/tex/default/resource/header.fig
--- htdocs.orig/templates/tex/default/resource/header.fig	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/resource/header.fig	2002-09-17 01:44:26.000000000 +0200
@@ -0,0 +1,24 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+A4      
+100.00
+Single
+-2
+1200 2
+4 0 0 893 -1 14 10 -0.0000 4 135 1350 150 1350 Bankverbindung:\001
+4 0 0 890 -1 14 10 -0.0000 4 105 1260 225 1125 Hausanschrift:\001
+4 0 9 918 -1 2 20 0.0000 4 150 1005 75 750 metux ITS\001
+4 0 25 969 -1 14 12 -0.0000 4 135 3360 1650 750 Ihr innovativer IT-Dienstleister\001
+4 0 0 942 -1 2 10 0.0000 4 135 750 5700 675     Telephon\001
+4 0 8 991 -1 0 10 0.0000 4 105 1050 6600 675 +49 174 7066481\001
+4 0 8 997 -1 0 10 0.0000 4 105 1050 6600 825 +49 36207 51833\001
+4 0 8 999 -1 0 10 0.0000 4 105 990 6600 1200 www.metux.de\001
+4 0 0 946 -1 2 10 0.0000 4 105 765 5700 1200       Internet\001
+4 0 8 888 -1 0 10 0.0000 4 135 1935 1650 1125 Heydaer Strasse 23 99338 Plaue\001
+4 0 8 987 -1 0 10 0.0000 4 135 1230 6600 1350 contact @ metux.de\001
+4 0 8 933 -1 0 10 0.0000 4 135 3435 1650 1350 Advance Bank (BLZ 702 300 00), Kto-Nr: 200 72 64 206\001
+4 0 0 50 0 0 12 0.0000 4 135 645 10125 300 tricktext\001
+4 0 0 893 -1 14 10 0.0000 4 105 720 750 1575 Inhaber:\001
+4 0 8 933 -1 0 10 0.0000 4 135 2415 1650 1575 Enrico Weigelt, Steuer-Nr: 154/286/05931\001
diff -ruN htdocs.orig/templates/tex/default/resource/metux.tex htdocs/templates/tex/default/resource/metux.tex
--- htdocs.orig/templates/tex/default/resource/metux.tex	1970-01-01 01:00:00.000000000 +0100
+++ htdocs/templates/tex/default/resource/metux.tex	2007-05-09 23:56:59.000000000 +0200
@@ -0,0 +1,76 @@
+% Variablen .... %
+\def\metuxSignature{\epsfig{file=\ResourcePrefix/signature.png}}
+\def\metuxName{metux IT service}
+\def\metuxPhone{+49-36207-519931}
+\def\metuxFax{+49-36207-519932}
+\def\metuxEmail{weigelt at metux.de}
+\def\metuxUrl{www.metux.de}
+\def\metuxAddress{Heydaer Stra{\ss}e 23, 99338 Plaue}
+\def\metuxBankAccount{0972596900}
+\def\metuxBankCompany{Dresdner Bank AG}
+\def\metuxBankCode{82080000}
+\def\metuxBank{Kto: \metuxBankAccount, BLZ: \metuxBankCode, \metuxBankCompany}
+\def\metuxStrnr{154/286/05931}
+\def\metuxOwner{Enrico Weigelt}
+
+\def\nl{\ \\}
+\def\metuxGeomLeft{2cm}
+\def\metuxGeomRight{2cm}
+\def\metuxGeomBottom{1cm}
+\def\metuxGeomHead{1cm}
+\def\metuxGeomTop{0.5cm}
+
+\newcommand\metuxFooter
+{
+    \hrule
+    ~\newline
+    \parbox[l]{180pt}{
+	\small
+	\metuxName		\\
+	Inh. \metuxOwner	\\
+	\metuxAddress		\\
+	StNr: \metuxStrnr
+    }
+    \parbox[l]{180pt}{
+	\small
+	Bankverbindung:		\\
+	Kto: \metuxBankAccount	\\
+	BLZ: \metuxBankCode	\\
+	\metuxBankCompany
+    }
+    \parbox[l]{180pt}{
+	\small
+	Tel:  \metuxPhone	\\
+	Fax:   \metuxFax	\\
+	eMail: \metuxEmail	\\
+	WWW:   \metuxUrl
+    }
+}
+
+\newcommand\metuxHeader{\epsfig{file=\ResourcePrefix/logo.png}}
+%\newcommand\metuxHeader{\epsfig{file=\ResourcePrefix/logo.eps}}
+\newcommand\metuxInit{
+    \renewcommand{\headrulewidth}{0.5pt}
+    \renewcommand{\footrulewidth}{0.5pt}
+    \cfoot{\metuxFooter}
+    \chead{\metuxHeader}
+}
+
+% \newcommand\Euro{Euro}
+
+\def\metuxMFG{%
+    \noindent Mit freundlichem Gru\ss
+
+    \epsfig{\metuxSignature}
+	
+    \noindent Enrico Weigelt 	\\
+    metux IT service
+}
+
+\def\metuxMFGpriv{%
+    \noindent Mit freundlichem Gru\ss
+
+    \metuxSignature
+	
+    \noindent Enrico Weigelt
+}


More information about the vtigercrm-developers mailing list