From 008163628ab1ed78afd5dab12d4f5da593e5eef5 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 26 Jun 2018 08:03:25 +0200 Subject: [PATCH 01/69] New pdf documents using new column system --- .../core/class/commondocgenerator.class.php | 225 ++ .../commande/doc/pdf_eratosthene.modules.php | 1675 ++++++++++++++ .../facture/doc/pdf_sponge.modules.php | 2030 +++++++++++++++++ .../modules/propale/doc/pdf_cyan.modules.php | 1891 +++++++++++++++ htdocs/langs/en_US/bills.lang | 3 +- htdocs/langs/en_US/orders.lang | 3 +- htdocs/langs/en_US/propal.lang | 3 +- 7 files changed, 5827 insertions(+), 3 deletions(-) create mode 100644 htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php create mode 100644 htdocs/core/modules/facture/doc/pdf_sponge.modules.php create mode 100644 htdocs/core/modules/propale/doc/pdf_cyan.modules.php diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index d3d77640540..ef0283a85d5 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -749,5 +749,230 @@ abstract class CommonDocGenerator if (empty($hidebottom)) $pdf->line($x+$l, $y+$h, $x, $y+$h); $pdf->line($x, $y+$h, $x, $y); } + + + /** + * uasort callback function to Sort colums fields + * + * @param array $a PDF lines array fields configs + * @param array $b PDF lines array fields configs + * @return int Return compare result + */ + function columnSort($a, $b) { + + if(empty($a['rank'])){ $a['rank'] = 0; } + if(empty($b['rank'])){ $b['rank'] = 0; } + if ($a['rank'] == $b['rank']) { + return 0; + } + return ($a['rank'] > $b['rank']) ? -1 : 1; + + } + + /** + * Prepare Array Column Field + * + * @param object $object common object + * @param outputlangs $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + function prepareArrayColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0){ + + global $conf; + + $this->defineColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref); + + + // Sorting + uasort ( $this->cols, array( $this, 'columnSort' ) ); + + // Positionning + $curX = $this->page_largeur-$this->marge_droite; // start from right + + // Array witdh + $arrayWidth = $this->page_largeur-$this->marge_droite-$this->marge_gauche; + + // Count flexible column + $totalDefinedColWidth = 0; + $countFlexCol = 0; + foreach ($this->cols as $colKey =>& $colDef) + { + if(!$this->getColumnStatus($colKey)) continue; // continue if desable + + if(!empty($colDef['scale'])){ + // In case of column widht is defined by percentage + $colDef['width'] = abs($arrayWidth * $colDef['scale'] / 100 ); + } + + if(empty($colDef['width'])){ + $countFlexCol++; + } + else{ + $totalDefinedColWidth += $colDef['width']; + } + } + + foreach ($this->cols as $colKey =>& $colDef) + { + // setting empty conf with default + if(!empty($colDef['title'])){ + $colDef['title'] = array_replace($this->defaultTitlesFieldsStyle, $colDef['title']); + } + else{ + $colDef['title'] = $this->defaultTitlesFieldsStyle; + } + + // setting empty conf with default + if(!empty($colDef['content'])){ + $colDef['content'] = array_replace($this->defaultContentsFieldsStyle, $colDef['content']); + } + else{ + $colDef['content'] = $this->defaultContentsFieldsStyle; + } + + if($this->getColumnStatus($colKey)) + { + // In case of flexible column + if(empty($colDef['width'])){ + $colDef['width'] = abs(($arrayWidth - $totalDefinedColWidth)) / $countFlexCol; + } + + // Set positions + $lastX = $curX; + $curX = $lastX - $colDef['width']; + $colDef['xStartPos'] = $curX; + $colDef['xEndPos'] = $lastX; + } + } + } + + /** + * get column content width from column key + * + * @param string $colKey the column key + * @return float width in mm + */ + function getColumnContentWidth($colKey) + { + $colDef = $this->cols[$colKey]; + return $colDef['width'] - $colDef['content']['padding'][3] - $colDef['content']['padding'][1]; + } + + + /** + * get column content X (abscissa) left position from column key + * + * @param string $colKey the column key + * @return float X position in mm + */ + function getColumnContentXStart($colKey) + { + $colDef = $this->cols[$colKey]; + return $colDef['xStartPos'] + $colDef['content']['padding'][3]; + } + + /** + * get column position rank from column key + * + * @param string $colKey the column key + * @return int rank on success and -1 on error + */ + function getColumnRank($colKey) + { + if(!isset($this->cols[$colKey]['rank'])) return -1; + return $this->cols[$colKey]['rank']; + } + + /** + * get column position rank from column key + * + * @param string $newColKey the new column key + * @param array $defArray a single column definition array + * @param string $targetCol target column used to place the new column beside + * @param bool $insertAfterTarget insert before or after target column ? + * @return int new rank on success and -1 on error + */ + function insertNewColumnDef($newColKey, $defArray, $targetCol = false, $insertAfterTarget = false) + { + // prepare wanted rank + $rank = -1; + + // try to get rank from target column + if(!empty($targetCol)){ + $rank = $this->getColumnRank($targetCol); + if($rank>=0 && $insertAfterTarget){ $rank++; } + } + + // get rank from new column definition + if($rank<0 && !empty($defArray['rank'])){ + $rank = $defArray['rank']; + } + + // error: no rank + if($rank<0){ return -1; } + + foreach ($this->cols as $colKey =>& $colDef) + { + if( $rank <= $colDef['rank']) + { + $colDef['rank'] = $colDef['rank'] + 1; + } + } + + $defArray['rank'] = $rank; + $this->cols[$newColKey] = $defArray; // array_replace is used to preserve keys + + return $rank; + } + + + /** + * print standard column content + * + * @param PDF $pdf pdf object + * @param float $curY curent Y position + * @param string $colKey the column key + * @param string $columnText column text + * @return int new rank on success and -1 on error + */ + function printStdColumnContent($pdf, &$curY, $colKey, $columnText = '') + { + global $hookmanager; + + $parameters=array( + 'object' => $object, + 'curY' =>& $curY, + 'columnText' => $columnText, + 'colKey' => $colKey + ); + $reshook=$hookmanager->executeHooks('printStdColumnContent',$parameters,$this); // Note that $action and $object may have been modified by hook + if ($reshook < 0) setEventMessages($hookmanager->error,$hookmanager->errors,'errors'); + if (!$reshook) + { + if(empty($columnText)) return; + $pdf->SetXY($this->getColumnContentXStart($colKey),$curY); // Set curent position + $colDef = $this->cols[$colKey]; + $pdf->MultiCell( $this->getColumnContentWidth($colKey),2, $columnText,'',$colDef['content']['align']); + } + + } + + + /** + * get column status from column key + * + * @param string $colKey the column key + * @return float width in mm + */ + function getColumnStatus($colKey) + { + if( !empty($this->cols[$colKey]['status'])){ + return true; + } + else return false; + } } diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php new file mode 100644 index 00000000000..58129bea6e2 --- /dev/null +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php @@ -0,0 +1,1675 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand + * Copyright (C) 2010-2013 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2015 Marcos García + * Copyright (C) 2017 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php + * \ingroup commande + * \brief Fichier de la classe permettant de generer les commandes au modele Eratosthène + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/commande/modules_commande.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Classe to generate PDF orders with template Eratosthene + */ +class pdf_eratosthene extends ModelePDFCommandes +{ + /** + * @var DoliDb Database handler + */ + public $db; + + /** + * @var string model name + */ + public $name; + + /** + * @var string model description (short text) + */ + public $description; + + /** + * @var int Save the name of generated file as the main doc when generating a doc with this template + */ + public $update_main_doc_field; + + /** + * @var string document type + */ + public $type; + + /** + * @var array() Minimum version of PHP required by module. + * e.g.: PHP ≥ 5.3 = array(5, 3) + */ + public $phpmin = array(5, 2); + + /** + * Dolibarr version of the loaded document + * @public string + */ + public $version = 'dolibarr'; + + public $page_largeur; + public $page_hauteur; + public $format; + public $marge_gauche; + public $marge_droite; + public $marge_haute; + public $marge_basse; + + public $emetteur; // Objet societe qui emet + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + global $conf,$langs,$mysoc; + + // Translations + $langs->loadLangs(array("main", "bills", "products")); + + $this->db = $db; + $this->name = "eratosthene"; + $this->description = $langs->trans('PDFEratostheneDescription'); + $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template + + // Dimension page + $this->type = 'pdf'; + $formatarray=pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10; + $this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10; + $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; + $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION + $this->option_modereg = 1; // Affiche mode reglement + $this->option_condreg = 1; // Affiche conditions reglement + $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_multilang = 1; // Dispo en plusieurs langues + $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_credit_note = 0; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 1; // Support add of a watermark on drafts + + $this->franchise=!$mysoc->tva_assuj; + + // Get source company + $this->emetteur=$mysoc; + if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default, if was not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; + + + $this->tva=array(); + $this->localtax1=array(); + $this->localtax2=array(); + $this->atleastoneratenotnull=0; + $this->atleastonediscount=0; + } + + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + function write_file($object, $outputlangs, $srctemplatepath='', $hidedetails=0, $hidedesc=0, $hideref=0) + { + global $user, $langs, $conf, $mysoc, $db, $hookmanager, $nblignes; + + if (! is_object($outputlangs)) $outputlangs=$langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1'; + + // Translations + $outputlangs->loadLangs(array("main", "dict", "companies", "bills", "products", "orders", "deliveries")); + + $nblignes = count($object->lines); + + if ($conf->commande->dir_output) + { + $object->fetch_thirdparty(); + + $deja_regle = 0; + + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->commande->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->commande->dir_output . "/" . $objectref; + $file = $dir . "/" . $objectref . ".pdf"; + } + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + + // Create pdf instance + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $pdf->SetAutoPageBreak(1,0); + + $heightforinfotot = 40; // Height reserved to output the info and total part + $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22); // Height reserved to output the footer (value include bottom margin) + + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + // Set path to the background PDF File + if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb=0; + $pdf->SetDrawColor(128,128,128); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("PdfOrderTitle")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfOrderTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + /// Does we have at least one line with discount $this->atleastonediscount + foreach ($object->lines as $line) { + if ($line->remise_percent){ + $this->atleastonediscount = true; + break; + } + } + + if (empty($this->atleastonediscount) && empty($conf->global->PRODUCT_USE_UNITS)) + { + $this->posxpicture+=($this->postotalht - $this->posxdiscount); + $this->posxtva+=($this->postotalht - $this->posxdiscount); + $this->posxup+=($this->postotalht - $this->posxdiscount); + $this->posxqty+=($this->postotalht - $this->posxdiscount); + $this->posxdiscount+=($this->postotalht - $this->posxdiscount); + //$this->postotalht; + } + + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0,0,0); + + + $tab_top = 90+$top_shift; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10); + + // Incoterm + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top -= 2; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = $pdf->GetY(); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + } + } + + // Affiche notes + $notetoshow=empty($object->note_public)?'':$object->note_public; + if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) + { + // Get first sale rep + if (is_object($object->thirdparty)) + { + $salereparray=$object->thirdparty->getSalesRepresentatives($user); + $salerepobj=new User($this->db); + $salerepobj->fetch($salereparray[0]['id']); + if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature); + } + } + + $pagenb = $pdf->getPage(); + if ($notetoshow) + { + $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite; + $pageposbeforenote = $pagenb; + + $substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); + + $tab_top -= 2; + + $pdf->startTransaction(); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + // Description + $pageposafternote=$pdf->getPage(); + $posyafter = $pdf->GetY(); + + if($pageposafternote>$pageposbeforenote ) + { + $pdf->rollbackTransaction(true); + + // prepar pages to receive notes + while ($pagenb < $pageposafternote) { + $pdf->AddPage(); + $pagenb++; + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + // $this->_pagefoot($pdf,$object,$outputlangs,1); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + } + + // back to start + $pdf->setPage($pageposbeforenote); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $pageposafternote=$pdf->getPage(); + + $posyafter = $pdf->GetY(); + + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20))) // There is no space left for total+free text + { + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + //$posyafter = $tab_top_newpage; + } + + + // apply note frame to previus pages + $i = $pageposbeforenote; + while ($i < $pageposafternote) { + $pdf->setPage($i); + + + $pdf->SetDrawColor(128,128,128); + // Draw note frame + if($i>$pageposbeforenote){ + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1); + } + else{ + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1); + } + + // Add footer + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $this->_pagefoot($pdf,$object,$outputlangs,1); + + $i++; + } + + // apply note frame to last page + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $height_note=$posyafter-$tab_top_newpage; + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1); + + } + else // No pagebreak + { + $pdf->commitTransaction(); + $posyafter = $pdf->GetY(); + $height_note=$posyafter-$tab_top; + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1); + + + if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) ) + { + // not enough space, need to add page + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + + $posyafter = $tab_top_newpage; + } + + } + + $tab_height = $tab_height - $height_note; + $tab_top = $posyafter +6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 7; + $curY = $tab_top + 7; + $nexY = $tab_top + 7; + + // Use new auto collum system + $this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref); + + // Loop on each lines + $pageposbeforeprintlines=$pdf->getPage(); + $pagenb = $pageposbeforeprintlines; + for ($i = 0 ; $i < $nblignes ; $i++) + { + $curY = $nexY; + $pdf->SetFont('','', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0,0,0); + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore=$pdf->getPage(); + + // Description of product line + $curX = $this->posxdesc-1; + + $showpricebeforepagebreak=1; + + if($this->getColumnStatus('desc')) + { + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + $pageposafter=$pdf->getPage(); + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pageposafter=$pageposbefore; + //print $pageposafter.'-'.$pageposbefore;exit; + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + $pageposafter=$pdf->getPage(); + $posyafter=$pdf->GetY(); + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblignes-1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + //if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposafter+1); + } + } + else + { + // We found a page break + $showpricebeforepagebreak=0; + } + } + else // No pagebreak + { + $pdf->commitTransaction(); + } + $posYAfterDescription=$pdf->GetY(); + } + + $nexY = $pdf->GetY(); + $pageposafter=$pdf->getPage(); + + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description is moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + // VAT Rate + if ($this->getColumnStatus('vat')) + { + $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate); + $nexY = max($pdf->GetY(),$nexY); + } + + // Unit price before discount + if ($this->getColumnStatus('subprice')) + { + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + // Quantity + // Enough for 6 chars + if ($this->getColumnStatus('qty')) + { + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'qty', $qty); + $nexY = max($pdf->GetY(),$nexY); + } + + + // Unit + if ($this->getColumnStatus('unit')) + { + $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager); + $this->printStdColumnContent($pdf, $curY, 'unit', $unit); + $nexY = max($pdf->GetY(),$nexY); + } + + // Discount on line + if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent) + { + $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent); + $nexY = max($pdf->GetY(),$nexY); + } + + // Total HT line + if ($this->getColumnStatus('totalexcltax')) + { + $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + + $parameters=array( + 'object' => $object, + 'i' => $i, + 'pdf' =>& $pdf, + 'curY' =>& $curY, + 'nexY' =>& $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this); // Note that $object may have been modified by hook + + + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva; + else $tvaligne=$object->lines[$i]->total_tva; + + $localtax1ligne=$object->lines[$i]->total_localtax1; + $localtax2ligne=$object->lines[$i]->total_localtax2; + $localtax1_rate=$object->lines[$i]->localtax1_tx; + $localtax2_rate=$object->lines[$i]->localtax2_tx; + $localtax1_type=$object->lines[$i]->localtax1_type; + $localtax2_type=$object->lines[$i]->localtax2_type; + + if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100; + + $vatrate=(string) $object->lines[$i]->tva_tx; + + // Retrieve type from database for backward compatibility with old records + if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined + && (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax + { + $localtaxtmp_array=getLocalTaxesFromRate($vatrate,0,$object->thirdparty,$mysoc); + $localtax1_type = $localtaxtmp_array[0]; + $localtax2_type = $localtaxtmp_array[2]; + } + + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) + $this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne; + if ($localtax2_type && $localtax2ligne != 0) + $this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne; + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; + if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=0; + $this->tva[$vatrate] += $tvaligne; + + // Add line + if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) + { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1); + $pdf->SetLineStyle(array('dash'=>0)); + } + + $nexY+=2; // Passe espace entre les lignes + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) + { + $pdf->setPage($pagenb); + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak) + { + if ($pagenb == $pageposafter) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } + + // Show square + if ($pagenb == $pageposbeforeprintlines) + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code); + else + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + + // Affiche zone infos + $posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs); + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); + + // Affiche zone versements + /* + if ($deja_regle) + { + $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs); + } + */ + + // Pied de page + $this->_pagefoot($pdf, $object, $outputlangs); + if (method_exists($pdf, 'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->Close(); + + $pdf->Output($file, 'F'); + + // Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file, 'object'=>$object, 'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('afterPDFCreation', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $this->result = array('fullpath'=>$file); + + return 1; // Pas d'erreur + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->transnoentities("ErrorConstantNotDefined","COMMANDE_OUTPUTDIR"); + return 0; + } + } + + /** + * Show payments table + * + * @param TCPDF $pdf Object PDF + * @param Object $object Object order + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @return int <0 if KO, >0 if OK + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + + } + + + /** + * Show miscellaneous information (payment mode, payment term, ...) + * + * @param TCPDF $pdf Object PDF + * @param Object $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @return void + */ + function _tableau_info(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $pdf->SetFont('','', $default_font_size - 1); + + // If France, show VAT mention if not applicable + if ($this->emetteur->country_code == 'FR' && $this->franchise == 1) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + + $posy=$pdf->GetY()+4; + } + + $posxval=52; + + // Show payments conditions + if ($object->cond_reglement_code || $object->cond_reglement) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(43, 4, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc); + $lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement); + $pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + + // Check a payment mode is defined + /* Not used with orders + if (empty($object->mode_reglement_code) + && ! $conf->global->FACTURE_CHQ_NUMBER + && ! $conf->global->FACTURE_RIB_NUMBER) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->MultiCell(80, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0); + $pdf->SetTextColor(0,0,0); + + $posy=$pdf->GetY()+1; + } + */ + /* TODO + else if (! empty($object->availability_code)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->MultiCell(80, 3, $outputlangs->transnoentities("AvailabilityPeriod").': '.,0,'L',0); + $pdf->SetTextColor(0,0,0); + + $posy=$pdf->GetY()+1; + }*/ + + // Show planed date of delivery + if (! empty($object->date_livraison)) + { + $outputlangs->load("sendings"); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true); + $pdf->MultiCell(80, 4, $dlp, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + elseif ($object->availability_code || $object->availability) // Show availability conditions + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("AvailabilityPeriod").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_availability=$outputlangs->transnoentities("AvailabilityType".$object->availability_code)!=('AvailabilityType'.$object->availability_code)?$outputlangs->transnoentities("AvailabilityType".$object->availability_code):$outputlangs->convToOutputCharset(isset($object->availability)?$object->availability:''); + $lib_availability=str_replace('\n',"\n",$lib_availability); + $pdf->MultiCell(80, 4, $lib_availability, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + + // Show payment mode + if ($object->mode_reglement_code + && $object->mode_reglement_code != 'CHQ' + && $object->mode_reglement_code != 'VIR') + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentMode").':'; + $pdf->MultiCell(80, 5, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement); + $pdf->MultiCell(80, 5, $lib_mode_reg,0,'L'); + + $posy=$pdf->GetY()+2; + } + + // Show payment mode CHQ + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') + { + // Si mode reglement non force ou si force a CHQ + if (! empty($conf->global->FACTURE_CHQ_NUMBER)) + { + if ($conf->global->FACTURE_CHQ_NUMBER > 0) + { + $account = new Account($this->db); + $account->fetch($conf->global->FACTURE_CHQ_NUMBER); + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - 3); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - 3); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + if ($conf->global->FACTURE_CHQ_NUMBER == -1) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - 3); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - 3); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + } + } + + // If payment mode not forced or forced to VIR, show payment with BAN + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') + { + if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER)) + { + $bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account); + if (! empty($object->fk_bank)) $bankid=$object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $account = new Account($this->db); + $account->fetch($bankid); + + $curx=$this->marge_gauche; + $cury=$posy; + + $posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size); + + $posy+=2; + } + } + + return $posy; + } + + + /** + * Show total to pay + * + * @param TCPDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Montant deja regle + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + global $conf,$mysoc; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','', $default_font_size - 1); + + // Tableau total + $col1x = 120; $col2x = 170; + if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + } + $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); + + $useborder=0; + $index = 0; + + // Total HT + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); + + $total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht); + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (! empty($object->remise)?$object->remise:0), 0, $outputlangs), 0, 'R', 1); + + // Show VAT by rates and total + $pdf->SetFillColor(248,248,248); + + $total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; + + $this->atleastoneratenotnull=0; + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false); + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) + { + // Nothing to do + } + else + { + //Local tax 1 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + + } + } + } + //} + // VAT + foreach($this->tva as $tvakey => $tvaval) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + $this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' '; + $totalvat.=vatrate($tvakey,1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + + //Local tax 1 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + + // Total TTC + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1); + } + } + + $pdf->SetTextColor(0,0,0); + + $creditnoteamount=0; + $depositsamount=0; + //$creditnoteamount=$object->getSumCreditNotesUsed(); + //$depositsamount=$object->getSumDepositsUsed(); + //print "x".$creditnoteamount."-".$depositsamount;exit; + $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT'); + if (! empty($object->paye)) $resteapayer=0; + + if ($deja_regle > 0) + { + // Already paid + Deposits + $index++; + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0); + + $index++; + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetTextColor(0,0,0); + } + + $index++; + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * Show table for lines + * + * @param PDF $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='') + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $currency = !empty($currency) ? $currency : $conf->currency; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + + if (empty($hidetop)) + { + $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency)); + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4); + $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); + + //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230'; + if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); + } + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','', $default_font_size - 1); + + // Output Rect + $this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect prend une longueur en 3eme param et 4eme param + + + foreach ($this->cols as $colKey => $colDef) + { + if(!$this->getColumnStatus($colKey)) continue; + + // get title label + $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']); + + // Add column separator + if(!empty($colDef['border-left'])){ + $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); + } + + if (empty($hidetop)) + { + $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] ); + + $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1]; + $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']); + } + } + + if (empty($hidetop)){ + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); // line prend une position y en 2eme param et 4eme param + } + + + } + + /** + * Show top header of page. + * + * @param TCPDF $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @param string $titlekey Translation key to show as title of document + * @return void + */ + function _pagehead(&$pdf, $object, $showaddress, $outputlangs, $titlekey="PdfOrderTitle") + { + global $conf,$langs,$hookmanager; + + // Translations + $outputlangs->loadLangs(array("main", "bills", "propal", "orders", "companies")); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==0 && (! empty($conf->global->COMMANDE_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->COMMANDE_DRAFT_WATERMARK); + } + + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-100; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $height=pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size -2); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + $pdf->SetFont('','B', $default_font_size + 3); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities($titlekey); + $pdf->MultiCell(100, 3, $title, '', 'R'); + + $pdf->SetFont('','B',$default_font_size); + + $posy+=5; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref), '', 'R'); + + $posy+=1; + $pdf->SetFont('','', $default_font_size - 1); + + if ($object->ref_client) + { + $posy+=5; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + } + + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("OrderDate")." : " . dol_print_date($object->date,"%d %b %Y",false,$outputlangs,true), '', 'R'); + + // Get contact + if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) + { + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $usertmp=new User($this->db); + $usertmp->fetch($arrayidcontact[0]); + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + } + } + + $posy+=2; + + $top_shift = 0; + // Show list of linked objects + $current_y = $pdf->getY(); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + if ($current_y < $pdf->getY()) + { + $top_shift = $pdf->getY() - $current_y; + } + + if ($showaddress) + { + // Sender properties + $carac_emetteur=''; + // Add internal contact of proposal if defined + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $object->fetch_user($arrayidcontact[0]); + $labelbeforecontactname=($outputlangs->transnoentities("FromContactName")!='FromContactName'?$outputlangs->transnoentities("FromContactName"):$outputlangs->transnoentities("Name")); + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n"; + } + + $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object); + + // Show sender + $posy=42+$top_shift; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + $hautcadre=40; + + // Show sender frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy=$pdf->getY(); + + // Show sender information + $pdf->SetXY($posx+2,$posy); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L'); + + + + // If CUSTOMER contact defined on order, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','CUSTOMER'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target', $object); + + // Show recipient + $widthrecbox=100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=42+$top_shift; + $posx=$this->page_largeur-$this->marge_droite-$widthrecbox; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche; + + // Show recipient frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx+2,$posy-5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":",0,'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0,0,0); + return $top_shift; + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param TCPDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'ORDER_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + + + + /** + * Define Array Column Field + * + * @param object $object common object + * @param outputlangs $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0){ + + global $conf, $hookmanager; + + // Default field style for content + $this->defaultContentsFieldsStyle = array( + 'align' => 'R', // R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + // Default field style for content + $this->defaultTitlesFieldsStyle = array( + 'align' => 'C', // R,C,L + 'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + /* + * For exemple + $this->cols['theColKey'] = array( + 'rank' => $rank, // int : use for ordering columns + 'width' => 20, // the column width in mm + 'title' => array( + 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + 'label' => ' ', // the final label : used fore final generated text + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); + */ + + $rank=0; // do not use negative rank + $this->cols['desc'] = array( + 'rank' => $rank, + 'width' => false, // only for desc + 'status' => true, + 'title' => array( + 'textkey' => 'Designation', // use lang key is usefull in somme case with module + 'align' => 'L', + // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + // 'label' => ' ', // the final label + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', + ), + ); + + $rank = $rank + 10; + $this->cols['photo'] = array( + 'rank' => $rank, + 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Photo', + 'label' => ' ' + ), + 'content' => array( + 'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'border-left' => false, // remove left line separator + ); + + if (! empty($conf->global->MAIN_GENERATE_ORDERS_WITH_PICTURE)) + { + $this->cols['photo']['status'] = true; + } + + + $rank = $rank + 10; + $this->cols['vat'] = array( + 'rank' => $rank, + 'status' => false, + 'width' => 16, // in mm + 'title' => array( + 'textkey' => 'VAT' + ), + 'border-left' => true, // add left line separator + ); + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) + { + $this->cols['vat']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['subprice'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'PriceUHT' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['qty'] = array( + 'rank' => $rank, + 'width' => 16, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'Qty' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['progress'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Progress' + ), + 'border-left' => false, // add left line separator + ); + + if($this->situationinvoice) + { + $this->cols['progress']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['unit'] = array( + 'rank' => $rank, + 'width' => 11, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Unit' + ), + 'border-left' => true, // add left line separator + ); + if($conf->global->PRODUCT_USE_UNITS){ + $this->cols['unit']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['discount'] = array( + 'rank' => $rank, + 'width' => 13, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'ReductionShort' + ), + 'border-left' => true, // add left line separator + ); + if ($this->atleastonediscount){ + $this->cols['discount']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['totalexcltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'TotalHT' + ), + 'border-left' => true, // add left line separator + ); + + + $parameters=array( + 'object' => $object, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails, + 'hidedesc' => $hidedesc, + 'hideref' => $hideref + ); + + $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this); // Note that $object may have been modified by hook + if ($reshook < 0) + { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + elseif (empty($reshook)) + { + $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys + } + else + { + $this->cols = $hookmanager->resArray; + } + + } + +} diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php new file mode 100644 index 00000000000..72c2a5aaca6 --- /dev/null +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -0,0 +1,2030 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand + * Copyright (C) 2010-2014 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2012 Cédric Salvador + * Copyright (C) 2012-2014 Raphaël Doursenaud + * Copyright (C) 2015 Marcos García + * Copyright (C) 2017 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/facture/doc/pdf_sponge.modules.php + * \ingroup facture + * \brief File of class to generate customers invoices from sponge model + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/facture/modules_facture.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Class to manage PDF invoice template sponge + */ +class pdf_sponge extends ModelePDFFactures +{ + /** + * @var DoliDb Database handler + */ + public $db; + + /** + * @var string model name + */ + public $name; + + /** + * @var string model description (short text) + */ + public $description; + + /** + * @var int Save the name of generated file as the main doc when generating a doc with this template + */ + public $update_main_doc_field; + + /** + * @var string document type + */ + public $type; + + /** + * @var array() Minimum version of PHP required by module. + * e.g.: PHP ≥ 5.3 = array(5, 3) + */ + public $phpmin = array(5, 2); + + /** + * Dolibarr version of the loaded document + * @public string + */ + public $version = 'dolibarr'; + + public $page_largeur; + public $page_hauteur; + public $format; + public $marge_gauche; + public $marge_droite; + public $marge_haute; + public $marge_basse; + + public $emetteur; // Objet societe qui emet + + /** + * @var bool Situation invoice type + */ + public $situationinvoice; + + /** + * @var float X position for the situation progress column + */ + public $posxprogress; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + // Translations + $langs->loadLangs(array("main", "bills")); + + $this->db = $db; + $this->name = "sponge"; + $this->description = $langs->trans('PDFSpongeDescription'); + $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template + + // Dimensiont page + $this->type = 'pdf'; + $formatarray=pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10; + $this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10; + $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; + $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION + $this->option_modereg = 1; // Affiche mode reglement + $this->option_condreg = 1; // Affiche conditions reglement + $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_multilang = 1; // Dispo en plusieurs langues + $this->option_escompte = 1; // Affiche si il y a eu escompte + $this->option_credit_note = 1; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 1; // Support add of a watermark on drafts + + $this->franchise=!$mysoc->tva_assuj; + + // Get source company + $this->emetteur=$mysoc; + if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default, if was not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; // used for notes ans other stuff + + // Use new system for position of columns, view $this->defineColumnField() + + $this->tva=array(); + $this->localtax1=array(); + $this->localtax2=array(); + $this->atleastoneratenotnull=0; + $this->atleastonediscount=0; + $this->situationinvoice=false; + } + + + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$db,$hookmanager,$nblignes; + + if (! is_object($outputlangs)) $outputlangs=$langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1'; + + // Translations + $outputlangs->loadLangs(array("main", "bills", "products", "dict", "companies")); + + $nblignes = count($object->lines); + + // Loop on each lines to detect if there is at least one image to show + $realpatharray=array(); + $this->atleastonephoto = false; + if (! empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE)) + { + $objphoto = new Product($this->db); + + for ($i = 0 ; $i < $nblignes ; $i++) + { + if (empty($object->lines[$i]->fk_product)) continue; + + $objphoto->fetch($object->lines[$i]->fk_product); + //var_dump($objphoto->ref);exit; + if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) + { + $pdir[0] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/"; + $pdir[1] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/'; + } + else + { + $pdir[0] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/'; // default + $pdir[1] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/"; // alternative + } + + $arephoto = false; + foreach ($pdir as $midir) + { + if (! $arephoto) + { + $dir = $conf->product->dir_output.'/'.$midir; + + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo + { + if ($obj['photo_vignette']) + { + $filename= $obj['photo_vignette']; + } + else + { + $filename=$obj['photo']; + } + } + else + { + $filename=$obj['photo']; + } + + $realpath = $dir.$filename; + $arephoto = true; + $this->atleastonephoto = true; + } + } + } + + if ($realpath && $arephoto) $realpatharray[$i]=$realpath; + } + } + + //if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + + if ($conf->facture->dir_output) + { + $object->fetch_thirdparty(); + + $deja_regle = $object->getSommePaiement(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); + $amount_credit_notes_included = $object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); + $amount_deposits_included = $object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); + + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->facture->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->facture->dir_output . "/" . $objectref; + $file = $dir . "/" . $objectref . ".pdf"; + } + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + + // Set nblignes with the new facture lines content after hook + $nblignes = count($object->lines); + $nbpayments = count($object->getListOfPayments()); + + // Create pdf instance + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $pdf->SetAutoPageBreak(1,0); + + $heightforinfotot = 50+(4*$nbpayments); // Height reserved to output the info and total part and payment part + $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22); // Height reserved to output the footer (value include bottom margin) + + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + + // Set path to the background PDF File + if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb=0; + $pdf->SetDrawColor(128,128,128); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("PdfInvoiceTitle")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfInvoiceTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + // Does we have at least one line with discount $this->atleastonediscount + foreach ($object->lines as $line) { + if ($line->remise_percent){ + $this->atleastonediscount = true; + break; + } + } + + + // Situation invoice handling + if ($object->situation_cycle_ref) + { + $this->situationinvoice = true; + } + + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0,0,0); + + $tab_top = 90+$top_shift; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10); + $tab_height = 130-$top_shift; + $tab_height_newpage = 150; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $tab_height_newpage -= $top_shift; + + // Incoterm + $height_incoterms = 0; + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top -= 2; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = max($pdf->GetY(),$nexY); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + $height_incoterms += 4; + } + } + + // Affiche notes + $notetoshow=empty($object->note_public)?'':$object->note_public; + if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) + { + // Get first sale rep + if (is_object($object->thirdparty)) + { + $salereparray=$object->thirdparty->getSalesRepresentatives($user); + $salerepobj=new User($this->db); + $salerepobj->fetch($salereparray[0]['id']); + if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature); + } + } + + $pagenb = $pdf->getPage(); + if ($notetoshow) + { + $tab_top -= 2; + + $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite; + $pageposbeforenote = $pagenb; + + $substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); + + + $pdf->startTransaction(); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + // Description + $pageposafternote=$pdf->getPage(); + $posyafter = $pdf->GetY(); + + if($pageposafternote>$pageposbeforenote ) + { + $pdf->rollbackTransaction(true); + + // prepar pages to receive notes + while ($pagenb < $pageposafternote) { + $pdf->AddPage(); + $pagenb++; + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + // $this->_pagefoot($pdf,$object,$outputlangs,1); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + } + + // back to start + $pdf->setPage($pageposbeforenote); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $pageposafternote=$pdf->getPage(); + + $posyafter = $pdf->GetY(); + + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20))) // There is no space left for total+free text + { + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + //$posyafter = $tab_top_newpage; + } + + + // apply note frame to previus pages + $i = $pageposbeforenote; + while ($i < $pageposafternote) { + $pdf->setPage($i); + + + $pdf->SetDrawColor(128,128,128); + // Draw note frame + if($i>$pageposbeforenote){ + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1); + } + else{ + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1); + } + + // Add footer + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $this->_pagefoot($pdf,$object,$outputlangs,1); + + $i++; + } + + // apply note frame to last page + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $height_note=$posyafter-$tab_top_newpage; + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1); + + } + else // No pagebreak + { + $pdf->commitTransaction(); + $posyafter = $pdf->GetY(); + $height_note=$posyafter-$tab_top; + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1); + + + if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) ) + { + // not enough space, need to add page + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + + $posyafter = $tab_top_newpage; + } + + } + + $tab_height = $tab_height - $height_note; + $tab_top = $posyafter +6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 7; + $curY = $tab_top + 7; + $nexY = $tab_top + 7; + + // Use new auto collum system + $this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref); + + // Loop on each lines + $pageposbeforeprintlines=$pdf->getPage(); + $pagenb = $pageposbeforeprintlines; + for ($i = 0; $i < $nblignes; $i++) + { + + $curY = $nexY; + $pdf->SetFont('','', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0,0,0); + + // Define size of image if we need it + $imglinesize=array(); + if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]); + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore=$pdf->getPage(); + + $showpricebeforepagebreak=1; + $posYAfterImage=0; + $posYAfterDescription=0; + + if($this->getColumnStatus('photo')) + { + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot))) // If photo too high, we moved completely on new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pdf->setPage($pageposbefore+1); + + $curY = $tab_top_newpage; + $showpricebeforepagebreak=0; + } + + if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage=$curY+$imglinesize['height']; + } + } + + // Description of product line + if ($this->getColumnStatus('desc')) + { + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + $pageposafter=$pdf->getPage(); + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pageposafter=$pageposbefore; + //print $pageposafter.'-'.$pageposbefore;exit; + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + $pageposafter=$pdf->getPage(); + $posyafter=$pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblignes-1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pdf->setPage($pageposafter+1); + } + } + else + { + // We found a page break + $showpricebeforepagebreak=0; + } + } + else // No pagebreak + { + $pdf->commitTransaction(); + } + $posYAfterDescription=$pdf->GetY(); + } + + $nexY = $pdf->GetY(); + $pageposafter=$pdf->getPage(); + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + // VAT Rate + if ($this->getColumnStatus('vat')) + { + $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate); + $nexY = max($pdf->GetY(),$nexY); + } + + // Unit price before discount + if ($this->getColumnStatus('subprice')) + { + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + // Quantity + // Enough for 6 chars + if ($this->getColumnStatus('qty')) + { + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'qty', $qty); + $nexY = max($pdf->GetY(),$nexY); + } + + // Situation progress + if ($this->getColumnStatus('progress')) + { + $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'progress', $progress); + $nexY = max($pdf->GetY(),$nexY); + } + + // Unit + if ($this->getColumnStatus('unit')) + { + $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager); + $this->printStdColumnContent($pdf, $curY, 'unit', $unit); + $nexY = max($pdf->GetY(),$nexY); + } + + // Discount on line + if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent) + { + $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent); + $nexY = max($pdf->GetY(),$nexY); + } + + // Total HT line + if ($this->getColumnStatus('totalexcltax')) + { + $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + + $parameters=array( + 'object' => $object, + 'i' => $i, + 'pdf' =>& $pdf, + 'curY' =>& $curY, + 'nexY' =>& $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this); // Note that $object may have been modified by hook + + + + $sign=1; + if (isset($object->type) && $object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1; + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + $prev_progress = $object->lines[$i]->get_prev_progress($object->id); + if ($prev_progress > 0 && !empty($object->lines[$i]->situation_percent)) // Compute progress from previous situation + { + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne = $sign * $object->lines[$i]->multicurrency_total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + else $tvaligne = $sign * $object->lines[$i]->total_tva * ($object->lines[$i]->situation_percent - $prev_progress) / $object->lines[$i]->situation_percent; + } else { + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne= $sign * $object->lines[$i]->multicurrency_total_tva; + else $tvaligne= $sign * $object->lines[$i]->total_tva; + } + + $localtax1ligne=$object->lines[$i]->total_localtax1; + $localtax2ligne=$object->lines[$i]->total_localtax2; + $localtax1_rate=$object->lines[$i]->localtax1_tx; + $localtax2_rate=$object->lines[$i]->localtax2_tx; + $localtax1_type=$object->lines[$i]->localtax1_type; + $localtax2_type=$object->lines[$i]->localtax2_type; + + if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100; + + $vatrate=(string) $object->lines[$i]->tva_tx; + + // Retrieve type from database for backward compatibility with old records + if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined + && (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax + { + $localtaxtmp_array=getLocalTaxesFromRate($vatrate,0, $object->thirdparty, $mysoc); + $localtax1_type = $localtaxtmp_array[0]; + $localtax2_type = $localtaxtmp_array[2]; + } + + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) + $this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne; + if ($localtax2_type && $localtax2ligne != 0) + $this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne; + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; + if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=0; + $this->tva[$vatrate] += $tvaligne; + + $nexY = max($nexY,$posYAfterImage); + + // Add line + if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) + { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1); + $pdf->SetLineStyle(array('dash'=>0)); + } + + $nexY+=2; // Passe espace entre les lignes + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) + { + $pdf->setPage($pagenb); + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + + if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak) + { + if ($pagenb == $pageposafter) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + + } + + // Show square + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforfooter + 1; + } + + // Affiche zone infos + $posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs); + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, $deja_regle, $bottomlasttab, $outputlangs); + + // Affiche zone versements + if (($deja_regle || $amount_credit_notes_included || $amount_deposits_included) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) + { + $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs); + } + + // Pied de page + $this->_pagefoot($pdf,$object,$outputlangs); + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + $pdf->Close(); + + $pdf->Output($file,'F'); + + // Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $this->result = array('fullpath'=>$file); + + return 1; // No error + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->transnoentities("ErrorConstantNotDefined","FAC_OUTPUTDIR"); + return 0; + } + } + + + /** + * Show payments table + * + * @param PDF $pdf Object PDF + * @param Object $object Object invoice + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @return int <0 if KO, >0 if OK + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + + $sign=1; + if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1; + + $tab3_posx = 120; + $tab3_top = $posy + 8; + $tab3_width = 80; + $tab3_height = 4; + if ($this->page_largeur < 210) // To work with US executive format + { + $tab3_posx -= 20; + } + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $title=$outputlangs->transnoentities("PaymentsAlreadyDone"); + if ($object->type == 2) $title=$outputlangs->transnoentities("PaymentsBackAlreadyDone"); + + $pdf->SetFont('','', $default_font_size - 3); + $pdf->SetXY($tab3_posx, $tab3_top - 4); + $pdf->MultiCell(60, 3, $title, 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top, $tab3_posx+$tab3_width, $tab3_top); + + $pdf->SetFont('','', $default_font_size - 4); + $pdf->SetXY($tab3_posx, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Payment"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+21, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Amount"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+40, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Type"), 0, 'L', 0); + $pdf->SetXY($tab3_posx+58, $tab3_top); + $pdf->MultiCell(20, 3, $outputlangs->transnoentities("Num"), 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top-1+$tab3_height, $tab3_posx+$tab3_width, $tab3_top-1+$tab3_height); + + $y=0; + + $pdf->SetFont('','', $default_font_size - 4); + + + // Loop on each deposits and credit notes included + $sql = "SELECT re.rowid, re.amount_ht, re.multicurrency_amount_ht, re.amount_tva, re.multicurrency_amount_tva, re.amount_ttc, re.multicurrency_amount_ttc,"; + $sql.= " re.description, re.fk_facture_source,"; + $sql.= " f.type, f.datef"; + $sql.= " FROM ".MAIN_DB_PREFIX ."societe_remise_except as re, ".MAIN_DB_PREFIX ."facture as f"; + $sql.= " WHERE re.fk_facture_source = f.rowid AND re.fk_facture = ".$object->id; + $resql=$this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + $invoice=new Facture($this->db); + while ($i < $num) + { + $y+=3; + $obj = $this->db->fetch_object($resql); + + if ($obj->type == 2) $text=$outputlangs->trans("CreditNote"); + elseif ($obj->type == 3) $text=$outputlangs->trans("Deposit"); + else $text=$outputlangs->trans("UnknownType"); + + $invoice->fetch($obj->fk_facture_source); + + $pdf->SetXY($tab3_posx, $tab3_top+$y); + $pdf->MultiCell(20, 3, dol_print_date($obj->datef,'day',false,$outputlangs,true), 0, 'L', 0); + $pdf->SetXY($tab3_posx+21, $tab3_top+$y); + $pdf->MultiCell(20, 3, price(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $obj->multicurrency_amount_ttc : $obj->amount_ttc, 0, $outputlangs), 0, 'L', 0); + $pdf->SetXY($tab3_posx+40, $tab3_top+$y); + $pdf->MultiCell(20, 3, $text, 0, 'L', 0); + $pdf->SetXY($tab3_posx+58, $tab3_top+$y); + $pdf->MultiCell(20, 3, $invoice->ref, 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top+$y+3, $tab3_posx+$tab3_width, $tab3_top+$y+3); + + $i++; + } + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + + // Loop on each payment + // TODO Call getListOfPaymentsgetListOfPayments instead of hard coded sql + $sql = "SELECT p.datep as date, p.fk_paiement, p.num_paiement as num, pf.amount as amount, pf.multicurrency_amount,"; + $sql.= " cp.code"; + $sql.= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."paiement as p"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as cp ON p.fk_paiement = cp.id"; + $sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = ".$object->id; + //$sql.= " WHERE pf.fk_paiement = p.rowid AND pf.fk_facture = 1"; + $sql.= " ORDER BY p.datep"; + + $resql=$this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i=0; + while ($i < $num) { + $y+=3; + $row = $this->db->fetch_object($resql); + + $pdf->SetXY($tab3_posx, $tab3_top+$y); + $pdf->MultiCell(20, 3, dol_print_date($this->db->jdate($row->date),'day',false,$outputlangs,true), 0, 'L', 0); + $pdf->SetXY($tab3_posx+21, $tab3_top+$y); + $pdf->MultiCell(20, 3, price($sign * (($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $row->multicurrency_amount : $row->amount), 0, $outputlangs), 0, 'L', 0); + $pdf->SetXY($tab3_posx+40, $tab3_top+$y); + $oper = $outputlangs->transnoentitiesnoconv("PaymentTypeShort" . $row->code); + + $pdf->MultiCell(20, 3, $oper, 0, 'L', 0); + $pdf->SetXY($tab3_posx+58, $tab3_top+$y); + $pdf->MultiCell(30, 3, $row->num, 0, 'L', 0); + + $pdf->line($tab3_posx, $tab3_top+$y+3, $tab3_posx+$tab3_width, $tab3_top+$y+3); + + $i++; + } + } + else + { + $this->error=$this->db->lasterror(); + return -1; + } + + } + + + /** + * Show miscellaneous information (payment mode, payment term, ...) + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @return void + */ + function _tableau_info(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $pdf->SetFont('','', $default_font_size - 1); + + // If France, show VAT mention if not applicable + if ($this->emetteur->country_code == 'FR' && $this->franchise == 1) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + + $posy=$pdf->GetY()+4; + } + + $posxval=52; + + // Show payments conditions + if ($object->type != 2 && ($object->cond_reglement_code || $object->cond_reglement)) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(43, 4, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc); + $lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement); + $pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + + if ($object->type != 2) + { + // Check a payment mode is defined + if (empty($object->mode_reglement_code) + && empty($conf->global->FACTURE_CHQ_NUMBER) + && empty($conf->global->FACTURE_RIB_NUMBER)) + { + $this->error = $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"); + } + // Avoid having any valid PDF with setup that is not complete + elseif (($object->mode_reglement_code == 'CHQ' && empty($conf->global->FACTURE_CHQ_NUMBER) && empty($object->fk_account) && empty($object->fk_bank)) + || ($object->mode_reglement_code == 'VIR' && empty($conf->global->FACTURE_RIB_NUMBER) && empty($object->fk_account) && empty($object->fk_bank))) + { + $outputlangs->load("errors"); + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size - 2); + $this->error = $outputlangs->transnoentities("ErrorPaymentModeDefinedToWithoutSetup",$object->mode_reglement_code); + $pdf->MultiCell(80, 3, $this->error,0,'L',0); + $pdf->SetTextColor(0,0,0); + + $posy=$pdf->GetY()+1; + } + + // Show payment mode + if ($object->mode_reglement_code + && $object->mode_reglement_code != 'CHQ' + && $object->mode_reglement_code != 'VIR') + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentMode").':'; + $pdf->MultiCell(80, 5, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement); + $pdf->MultiCell(80, 5, $lib_mode_reg,0,'L'); + + $posy=$pdf->GetY()+2; + } + + // Show payment mode CHQ + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') + { + // Si mode reglement non force ou si force a CHQ + if (! empty($conf->global->FACTURE_CHQ_NUMBER)) + { + $diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE); + + if ($conf->global->FACTURE_CHQ_NUMBER > 0) + { + $account = new Account($this->db); + $account->fetch($conf->global->FACTURE_CHQ_NUMBER); + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + if ($conf->global->FACTURE_CHQ_NUMBER == -1) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + } + } + + // If payment mode not forced or forced to VIR, show payment with BAN + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') + { + if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER)) + { + $bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account); + if (! empty($object->fk_bank)) $bankid=$object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $account = new Account($this->db); + $account->fetch($bankid); + + $curx=$this->marge_gauche; + $cury=$posy; + + $posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size); + + $posy+=2; + } + } + } + + return $posy; + } + + + /** + * Show total to pay + * + * @param PDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Montant deja regle + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + global $conf,$mysoc; + + $sign=1; + if ($object->type == 2 && ! empty($conf->global->INVOICE_POSITIVE_CREDIT_NOTE)) $sign=-1; + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','', $default_font_size - 1); + + // Tableau total + $col1x = 120; $col2x = 170; + if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + } + $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); + + $useborder=0; + $index = 0; + + // Total HT + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); + + $total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht); + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($sign * ($total_ht + (! empty($object->remise)?$object->remise:0)), 0, $outputlangs), 0, 'R', 1); + + // Show VAT by rates and total + $pdf->SetFillColor(248,248,248); + + $total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; + + $this->atleastoneratenotnull=0; + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false); + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) + { + // Nothing to do + } + else + { + // FIXME amount of vat not supported with multicurrency + + //Local tax 1 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + + } + } + } + + //} + + // VAT + // Situations totals migth be wrong on huge amounts + if ($object->situation_cycle_ref && $object->situation_counter > 1) { + + $sum_pdf_tva = 0; + foreach($this->tva as $tvakey => $tvaval){ + $sum_pdf_tva+=$tvaval; // sum VAT amounts to compare to object + } + + if($sum_pdf_tva!=$object->total_tva) { // apply coef to recover the VAT object amount (the good one) + $coef_fix_tva = $object->total_tva / $sum_pdf_tva; + + foreach($this->tva as $tvakey => $tvaval) { + $this->tva[$tvakey]=$tvaval * $coef_fix_tva; + } + } + + } + + foreach($this->tva as $tvakey => $tvaval) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + $this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' '; + $totalvat.=vatrate($tvakey,1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + + //Local tax 1 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + // retrieve global local tax + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + //} + } + + // Revenue stamp + if (price2num($object->revenuestamp) != 0) + { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RevenueStamp"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $object->revenuestamp), $useborder, 'R', 1); + } + + // Total TTC + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($sign * $total_ttc, 0, $outputlangs), $useborder, 'R', 1); + } + } + + $pdf->SetTextColor(0,0,0); + + $creditnoteamount=$object->getSumCreditNotesUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); + $depositsamount=$object->getSumDepositsUsed(($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? 1 : 0); + //print "x".$creditnoteamount."-".$depositsamount;exit; + $resteapayer = price2num($total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 'MT'); + if ($object->paye) $resteapayer=0; + + if (($deja_regle > 0 || $creditnoteamount > 0 || $depositsamount > 0) && empty($conf->global->INVOICE_NO_PAYMENT_DETAILS)) + { + // Already paid + Deposits + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("Paid"), 0, 'L', 0); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle + $depositsamount, 0, $outputlangs), 0, 'R', 0); + + // Credit note + if ($creditnoteamount) + { + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("CreditNotes"), 0, 'L', 0); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($creditnoteamount, 0, $outputlangs), 0, 'R', 0); + } + + // Escompte + if ($object->close_code == Facture::CLOSECODE_DISCOUNTVAT) + { + $index++; + $pdf->SetFillColor(255,255,255); + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle - $creditnoteamount - $depositsamount, 0, $outputlangs), $useborder, 'R', 1); + + $resteapayer=0; + } + + $index++; + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetTextColor(0,0,0); + } + + $index++; + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * Show table for lines + * + * @param PDF $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='') + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $currency = !empty($currency) ? $currency : $conf->currency; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + + if (empty($hidetop)) + { + $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency)); + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4); + $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); + + //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230'; + if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); + } + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','', $default_font_size - 1); + + // Output Rect + $this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect prend une longueur en 3eme param et 4eme param + + + foreach ($this->cols as $colKey => $colDef) + { + if(!$this->getColumnStatus($colKey)) continue; + + // get title label + $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']); + + // Add column separator + if(!empty($colDef['border-left'])){ + $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); + } + + if (empty($hidetop)) + { + $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] ); + + $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1]; + $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']); + } + } + + if (empty($hidetop)){ + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); // line prend une position y en 2eme param et 4eme param + } + + + } + + /** + * Show top header of page. + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @return void + */ + function _pagehead(&$pdf, $object, $showaddress, $outputlangs) + { + global $conf, $langs; + + // Translations + $outputlangs->loadLangs(array("main", "bills", "propal", "companies")); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==Facture::STATUS_DRAFT && (! empty($conf->global->FACTURE_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->FACTURE_DRAFT_WATERMARK); + } + + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $w = 110; + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-$w; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $height=pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B',$default_font_size - 2); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell($w, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + $pdf->SetFont('','B', $default_font_size + 3); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("PdfInvoiceTitle"); + if ($object->type == 1) $title=$outputlangs->transnoentities("InvoiceReplacement"); + if ($object->type == 2) $title=$outputlangs->transnoentities("InvoiceAvoir"); + if ($object->type == 3) $title=$outputlangs->transnoentities("InvoiceDeposit"); + if ($object->type == 4) $title=$outputlangs->transnoentities("InvoiceProForma"); + if ($this->situationinvoice) $title=$outputlangs->transnoentities("InvoiceSituation"); + $pdf->MultiCell($w, 3, $title, '', 'R'); + + $pdf->SetFont('','B',$default_font_size); + + $posy+=5; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $textref=$outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref); + if ($object->statut == Facture::STATUS_DRAFT) + { + $pdf->SetTextColor(128,0,0); + $textref.=' - '.$outputlangs->transnoentities("NotValidated"); + } + $pdf->MultiCell($w, 4, $textref, '', 'R'); + + $posy+=1; + $pdf->SetFont('','', $default_font_size - 2); + + if ($object->ref_client) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + } + + $objectidnext=$object->getIdReplacingInvoice('validated'); + if ($object->type == 0 && $objectidnext) + { + $objectreplacing=new Facture($this->db); + $objectreplacing->fetch($objectidnext); + + $posy+=3; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementByInvoice").' : '.$outputlangs->convToOutputCharset($objectreplacing->ref), '', 'R'); + } + if ($object->type == 1) + { + $objectreplaced=new Facture($this->db); + $objectreplaced->fetch($object->fk_facture_source); + + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("ReplacementInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); + } + if ($object->type == 2 && !empty($object->fk_facture_source)) + { + $objectreplaced=new Facture($this->db); + $objectreplaced->fetch($object->fk_facture_source); + + $posy+=3; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CorrectionInvoice").' : '.$outputlangs->convToOutputCharset($objectreplaced->ref), '', 'R'); + } + + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateInvoice")." : " . dol_print_date($object->date,"day",false,$outputlangs), '', 'R'); + + if (! empty($conf->global->INVOICE_POINTOFTAX_DATE)) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("DatePointOfTax")." : " . dol_print_date($object->date_pointoftax,"day",false,$outputlangs), '', 'R'); + } + + if ($object->type != 2) + { + $posy+=3; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("DateDue")." : " . dol_print_date($object->date_lim_reglement,"day",false,$outputlangs,true), '', 'R'); + } + + if ($object->thirdparty->code_client) + { + $posy+=3; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + } + + // Get contact + if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) + { + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $usertmp=new User($this->db); + $usertmp->fetch($arrayidcontact[0]); + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell($w, 3, $langs->transnoentities("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + } + } + + $posy+=1; + + $top_shift = 0; + // Show list of linked objects + $current_y = $pdf->getY(); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, $w, 3, 'R', $default_font_size); + if ($current_y < $pdf->getY()) + { + $top_shift = $pdf->getY() - $current_y; + } + + if ($showaddress) + { + // Sender properties + $carac_emetteur = pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object); + + // Show sender + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy+=$top_shift; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + + $hautcadre=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 38 : 40; + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 82; + + + // Show sender frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell($widthrecbox, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox-2, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy=$pdf->getY(); + + // Show sender information + $pdf->SetXY($posx+2,$posy); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell($widthrecbox-2, 4, $carac_emetteur, 0, 'L'); + + // If BILLING contact defined on invoice, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','BILLING'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target',$object); + + // Show recipient + $widthrecbox=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 92 : 100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=!empty($conf->global->MAIN_PDF_USE_ISO_LOCATION) ? 40 : 42; + $posy+=$top_shift; + $posx=$this->page_largeur-$this->marge_droite-$widthrecbox; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche; + + // Show recipient frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx+2,$posy-5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":",0,'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox, 2, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0,0,0); + return $top_shift; + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param PDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'INVOICE_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + + + + + /** + * Define Array Column Field + * + * @param object $object common object + * @param outputlangs $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0){ + + global $conf, $hookmanager; + + // Default field style for content + $this->defaultContentsFieldsStyle = array( + 'align' => 'R', // R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + // Default field style for content + $this->defaultTitlesFieldsStyle = array( + 'align' => 'C', // R,C,L + 'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + /* + * For exemple + $this->cols['theColKey'] = array( + 'rank' => $rank, // int : use for ordering columns + 'width' => 20, // the column width in mm + 'title' => array( + 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + 'label' => ' ', // the final label : used fore final generated text + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); + */ + + $rank=0; // do not use negative rank + $this->cols['desc'] = array( + 'rank' => $rank, + 'width' => false, // only for desc + 'status' => true, + 'title' => array( + 'textkey' => 'Designation', // use lang key is usefull in somme case with module + 'align' => 'L', + // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + // 'label' => ' ', // the final label + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', + ), + ); + + // PHOTO + $rank = $rank + 10; + $this->cols['photo'] = array( + 'rank' => $rank, + 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Photo', + 'label' => ' ' + ), + 'content' => array( + 'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'border-left' => false, // remove left line separator + ); + + if (! empty($conf->global->MAIN_GENERATE_INVOICES_WITH_PICTURE) && !empty($this->atleastonephoto)) + { + $this->cols['photo']['status'] = true; + } + + + $rank = $rank + 10; + $this->cols['vat'] = array( + 'rank' => $rank, + 'status' => false, + 'width' => 16, // in mm + 'title' => array( + 'textkey' => 'VAT' + ), + 'border-left' => true, // add left line separator + ); + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) + { + $this->cols['vat']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['subprice'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'PriceUHT' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['qty'] = array( + 'rank' => $rank, + 'width' => 16, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'Qty' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['progress'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Progress' + ), + 'border-left' => true, // add left line separator + ); + + if($this->situationinvoice) + { + $this->cols['progress']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['unit'] = array( + 'rank' => $rank, + 'width' => 11, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Unit' + ), + 'border-left' => true, // add left line separator + ); + if($conf->global->PRODUCT_USE_UNITS){ + $this->cols['unit']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['discount'] = array( + 'rank' => $rank, + 'width' => 13, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'ReductionShort' + ), + 'border-left' => true, // add left line separator + ); + if ($this->atleastonediscount){ + $this->cols['discount']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['totalexcltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'TotalHT' + ), + 'border-left' => true, // add left line separator + ); + + + $parameters=array( + 'object' => $object, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails, + 'hidedesc' => $hidedesc, + 'hideref' => $hideref + ); + + $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this); // Note that $object may have been modified by hook + if ($reshook < 0) + { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + elseif (empty($reshook)) + { + $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys + } + else + { + $this->cols = $hookmanager->resArray; + } + + } + + +} diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php new file mode 100644 index 00000000000..383f34acebd --- /dev/null +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -0,0 +1,1891 @@ + + * Copyright (C) 2005-2012 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand + * Copyright (C) 2010-2015 Juanjo Menent + * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2012 Cedric Salvador + * Copyright (C) 2015 Marcos García + * Copyright (C) 2017 Ferran Marcet + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * or see http://www.gnu.org/ + */ + +/** + * \file htdocs/core/modules/propale/doc/pdf_cyan.modules.php + * \ingroup propale + * \brief Fichier de la classe permettant de generer les propales au modele Cyan + */ +require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; +require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + + +/** + * Class to generate PDF proposal Cyan + */ +class pdf_cyan extends ModelePDFPropales +{ + var $db; + var $name; + var $description; + var $update_main_doc_field; // Save the name of generated file as the main doc when generating a doc with this template + var $type; + + var $phpmin = array(4,3,0); // Minimum version of PHP required by module + var $version = 'dolibarr'; + + var $page_largeur; + var $page_hauteur; + var $format; + var $marge_gauche; + var $marge_droite; + var $marge_haute; + var $marge_basse; + + var $emetteur; // Objet societe qui emet + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + // Translations + $langs->loadLangs(array("main", "bills")); + + $this->db = $db; + $this->name = "cyan"; + $this->description = $langs->trans('DocModelCyanDescription'); + $this->update_main_doc_field = 1; // Save the name of generated file as the main doc when generating a doc with this template + + // Dimension page + $this->type = 'pdf'; + $formatarray=pdf_getFormat(); + $this->page_largeur = $formatarray['width']; + $this->page_hauteur = $formatarray['height']; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=isset($conf->global->MAIN_PDF_MARGIN_LEFT)?$conf->global->MAIN_PDF_MARGIN_LEFT:10; + $this->marge_droite=isset($conf->global->MAIN_PDF_MARGIN_RIGHT)?$conf->global->MAIN_PDF_MARGIN_RIGHT:10; + $this->marge_haute =isset($conf->global->MAIN_PDF_MARGIN_TOP)?$conf->global->MAIN_PDF_MARGIN_TOP:10; + $this->marge_basse =isset($conf->global->MAIN_PDF_MARGIN_BOTTOM)?$conf->global->MAIN_PDF_MARGIN_BOTTOM:10; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION + $this->option_modereg = 1; // Affiche mode reglement + $this->option_condreg = 1; // Affiche conditions reglement + $this->option_codeproduitservice = 1; // Affiche code produit-service + $this->option_multilang = 1; // Dispo en plusieurs langues + $this->option_escompte = 0; // Affiche si il y a eu escompte + $this->option_credit_note = 0; // Support credit notes + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 1; //Support add of a watermark on drafts + + $this->franchise=!$mysoc->tva_assuj; + + // Get source company + $this->emetteur=$mysoc; + if (empty($this->emetteur->country_code)) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default, if was not defined + + // Define position of columns + $this->posxdesc=$this->marge_gauche+1; + + + + $this->tva=array(); + $this->localtax1=array(); + $this->localtax2=array(); + $this->atleastoneratenotnull=0; + $this->atleastonediscount=0; + } + + /** + * Function to build pdf onto disk + * + * @param Object $object Object to generate + * @param Translate $outputlangs Lang output object + * @param string $srctemplatepath Full path of source filename for generator using a template file + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return int 1=OK, 0=KO + */ + function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$db,$hookmanager,$nblignes; + + if (! is_object($outputlangs)) $outputlangs=$langs; + // For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO + if (! empty($conf->global->MAIN_USE_FPDF)) $outputlangs->charset_output='ISO-8859-1'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + $outputlangs->load("propal"); + $outputlangs->load("products"); + + $nblignes = count($object->lines); + + // Loop on each lines to detect if there is at least one image to show + $realpatharray=array(); + $this->atleastonephoto = false; + if (! empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE)) + { + $objphoto = new Product($this->db); + + for ($i = 0 ; $i < $nblignes ; $i++) + { + if (empty($object->lines[$i]->fk_product)) continue; + + $objphoto->fetch($object->lines[$i]->fk_product); + //var_dump($objphoto->ref);exit; + if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) + { + $pdir[0] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/"; + $pdir[1] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/'; + } + else + { + $pdir[0] = get_exdir(0,0,0,0,$objphoto,'product') . dol_sanitizeFileName($objphoto->ref).'/'; // default + $pdir[1] = get_exdir($objphoto->id,2,0,0,$objphoto,'product') . $objphoto->id ."/photos/"; // alternative + } + + $arephoto = false; + foreach ($pdir as $midir) + { + if (! $arephoto) + { + $dir = $conf->product->dir_output.'/'.$midir; + + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + if (empty($conf->global->CAT_HIGH_QUALITY_IMAGES)) // If CAT_HIGH_QUALITY_IMAGES not defined, we use thumb if defined and then original photo + { + if ($obj['photo_vignette']) + { + $filename= $obj['photo_vignette']; + } + else + { + $filename=$obj['photo']; + } + } + else + { + $filename=$obj['photo']; + } + + $realpath = $dir.$filename; + $arephoto = true; + $this->atleastonephoto = true; + } + } + } + + if ($realpath && $arephoto) $realpatharray[$i]=$realpath; + } + } + + if (count($realpatharray) == 0) $this->posxpicture=$this->posxtva; + + if ($conf->propal->multidir_output[$conf->entity]) + { + $object->fetch_thirdparty(); + + $deja_regle = 0; + + // Definition of $dir and $file + if ($object->specimen) + { + $dir = $conf->propal->multidir_output[$conf->entity]; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $objectref = dol_sanitizeFileName($object->ref); + $dir = $conf->propal->multidir_output[$object->entity] . "/" . $objectref; + $file = $dir . "/" . $objectref . ".pdf"; + } + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + // Add pdfgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('beforePDFCreation',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + + // Create pdf instance + $pdf=pdf_getInstance($this->format); + $default_font_size = pdf_getPDFFontSize($outputlangs); // Must be after pdf_getInstance + $pdf->SetAutoPageBreak(1,0); + + if (class_exists('TCPDF')) + { + $pdf->setPrintHeader(false); + $pdf->setPrintFooter(false); + } + $pdf->SetFont(pdf_getPDFFont($outputlangs)); + // Set path to the background PDF File + if (! empty($conf->global->MAIN_ADD_PDF_BACKGROUND)) + { + $pagecount = $pdf->setSourceFile($conf->mycompany->dir_output.'/'.$conf->global->MAIN_ADD_PDF_BACKGROUND); + $tplidx = $pdf->importPage(1); + } + + $pdf->Open(); + $pagenb=0; + $pdf->SetDrawColor(128,128,128); + + $pdf->SetTitle($outputlangs->convToOutputCharset($object->ref)); + $pdf->SetSubject($outputlangs->transnoentities("PdfCommercialProposalTitle")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($outputlangs->convToOutputCharset($user->getFullName($outputlangs))); + $pdf->SetKeyWords($outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name)); + if (! empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + + // Does we have at least one line with discount $this->atleastonediscount + foreach ($object->lines as $line) { + if ($line->remise_percent){ + $this->atleastonediscount = true; + break; + } + } + + + + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + + $heightforinfotot = 40; // Height reserved to output the info and total part + $heightforsignature = empty($conf->global->PROPAL_DISABLE_SIGNATURE)?(pdfGetHeightForHtmlContent($pdf, $outputlangs->transnoentities("ProposalCustomerSignature"))+10):0; + $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5); // Height reserved to output the free text on last page + $heightforfooter = $this->marge_basse + (empty($conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS)?12:22); // Height reserved to output the footer (value include bottom margin) + //print $heightforinfotot + $heightforsignature + $heightforfreetext + $heightforfooter;exit; + + $top_shift = $this->_pagehead($pdf, $object, 1, $outputlangs); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(0, 3, ''); // Set interline to 3 + $pdf->SetTextColor(0,0,0); + + + $tab_top = 90+$top_shift; + $tab_top_newpage = (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)?42+$top_shift:10); + + + // Incoterm + $height_incoterms = 0; + if ($conf->incoterm->enabled) + { + $desc_incoterms = $object->getIncotermsForPDF(); + if ($desc_incoterms) + { + $tab_top -= 2; + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top-1, dol_htmlentitiesbr($desc_incoterms), 0, 1); + $nexY = $pdf->GetY(); + $height_incoterms=$nexY-$tab_top; + + // Rect prend une longueur en 3eme param + $pdf->SetDrawColor(192,192,192); + $pdf->Rect($this->marge_gauche, $tab_top-1, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $height_incoterms+1); + + $tab_top = $nexY+6; + } + } + + // Affiche notes + $notetoshow=empty($object->note_public)?'':$object->note_public; + if (! empty($conf->global->MAIN_ADD_SALE_REP_SIGNATURE_IN_NOTE)) + { + // Get first sale rep + if (is_object($object->thirdparty)) + { + $salereparray=$object->thirdparty->getSalesRepresentatives($user); + $salerepobj=new User($this->db); + $salerepobj->fetch($salereparray[0]['id']); + if (! empty($salerepobj->signature)) $notetoshow=dol_concatdesc($notetoshow, $salerepobj->signature); + } + } + if (! empty($conf->global->MAIN_ADD_CREATOR_IN_NOTE) && $object->user_author_id > 0) + { + $tmpuser=new User($this->db); + $tmpuser->fetch($object->user_author_id); + $notetoshow.='Affaire suivi par '.$tmpuser->getFullName($langs); + if ($tmpuser->email) $notetoshow.=', Mail: '.$tmpuser->email; + if ($tmpuser->office_phone) $notetoshow.=', Tel: '.$tmpuser->office_phone; + } + + $pagenb = $pdf->getPage(); + if ($notetoshow) + { + $tab_top -= 2; + + $tab_width = $this->page_largeur-$this->marge_gauche-$this->marge_droite; + $pageposbeforenote = $pagenb; + + $substitutionarray=pdf_getSubstitutionArray($outputlangs, null, $object); + complete_substitutions_array($substitutionarray, $outputlangs, $object); + $notetoshow = make_substitutions($notetoshow, $substitutionarray, $outputlangs); + + + $pdf->startTransaction(); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + // Description + $pageposafternote=$pdf->getPage(); + $posyafter = $pdf->GetY(); + + if($pageposafternote>$pageposbeforenote ) + { + $pdf->rollbackTransaction(true); + + // prepar pages to receive notes + while ($pagenb < $pageposafternote) { + $pdf->AddPage(); + $pagenb++; + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + // $this->_pagefoot($pdf,$object,$outputlangs,1); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + } + + // back to start + $pdf->setPage($pageposbeforenote); + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->writeHTMLCell(190, 3, $this->posxdesc-1, $tab_top, dol_htmlentitiesbr($notetoshow), 0, 1); + $pageposafternote=$pdf->getPage(); + + $posyafter = $pdf->GetY(); + + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20))) // There is no space left for total+free text + { + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + $pdf->setTopMargin($tab_top_newpage); + // The only function to edit the bottom margin of current page to set it. + $pdf->setPageOrientation('', 1, $heightforfooter + $heightforfreetext); + //$posyafter = $tab_top_newpage; + } + + + // apply note frame to previus pages + $i = $pageposbeforenote; + while ($i < $pageposafternote) { + $pdf->setPage($i); + + + $pdf->SetDrawColor(128,128,128); + // Draw note frame + if($i>$pageposbeforenote){ + $height_note = $this->page_hauteur - ($tab_top_newpage + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note + 1); + } + else{ + $height_note = $this->page_hauteur - ($tab_top + $heightforfooter); + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note + 1); + } + + // Add footer + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + $this->_pagefoot($pdf,$object,$outputlangs,1); + + $i++; + } + + // apply note frame to last page + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $height_note=$posyafter-$tab_top_newpage; + $pdf->Rect($this->marge_gauche, $tab_top_newpage-1, $tab_width, $height_note+1); + + } + else // No pagebreak + { + $pdf->commitTransaction(); + $posyafter = $pdf->GetY(); + $height_note=$posyafter-$tab_top; + $pdf->Rect($this->marge_gauche, $tab_top-1, $tab_width, $height_note+1); + + + if($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+20)) ) + { + // not enough space, need to add page + $pdf->AddPage('','',true); + $pagenb++; + $pageposafternote++; + $pdf->setPage($pageposafternote); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + + $posyafter = $tab_top_newpage; + } + + } + + $tab_height = $tab_height - $height_note; + $tab_top = $posyafter +6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 7; + $curY = $tab_top + 7; + $nexY = $tab_top + 7; + + // Use new auto collum system + $this->prepareArrayColumnField($object,$outputlangs,$hidedetails,$hidedesc,$hideref); + + // Loop on each lines + $pageposbeforeprintlines=$pdf->getPage(); + $pagenb = $pageposbeforeprintlines; + for ($i = 0; $i < $nblignes; $i++) + { + $curY = $nexY; + $pdf->SetFont('','', $default_font_size - 1); // Into loop to work with multipage + $pdf->SetTextColor(0,0,0); + + // Define size of image if we need it + $imglinesize=array(); + if (! empty($realpatharray[$i])) $imglinesize=pdf_getSizeForImage($realpatharray[$i]); + + $pdf->setTopMargin($tab_top_newpage); + $pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot); // The only function to edit the bottom margin of current page to set it. + $pageposbefore=$pdf->getPage(); + + $showpricebeforepagebreak=1; + $posYAfterImage=0; + $posYAfterDescription=0; + + if($this->getColumnStatus('photo')) + { + // We start with Photo of product line + if (isset($imglinesize['width']) && isset($imglinesize['height']) && ($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot))) // If photo too high, we moved completely on new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + //if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposbefore+1); + + $curY = $tab_top_newpage; + $showpricebeforepagebreak=0; + } + + + if (!empty($this->cols['photo']) && isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $pdf->Image($realpatharray[$i], $this->getColumnContentXStart('photo'), $curY, $imglinesize['width'], $imglinesize['height'], '', '', '', 2, 300); // Use 300 dpi + // $pdf->Image does not increase value return by getY, so we save it manually + $posYAfterImage=$curY+$imglinesize['height']; + } + } + + // Description of product line + if($this->getColumnStatus('desc')) + { + $pdf->startTransaction(); + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + $pageposafter=$pdf->getPage(); + if ($pageposafter > $pageposbefore) // There is a pagebreak + { + $pdf->rollbackTransaction(true); + $pageposafter=$pageposbefore; + //print $pageposafter.'-'.$pageposbefore;exit; + $pdf->setPageOrientation('', 1, $heightforfooter); // The only function to edit the bottom margin of current page to set it. + pdf_writelinedesc($pdf,$object,$i,$outputlangs,$this->getColumnContentWidth('desc'),3,$this->getColumnContentXStart('desc'),$curY,$hideref,$hidedesc); + + $pageposafter=$pdf->getPage(); + $posyafter=$pdf->GetY(); + //var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit; + if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforsignature+$heightforinfotot))) // There is no space left for total+free text + { + if ($i == ($nblignes-1)) // No more lines, and no space left to show total, so we create a new page + { + $pdf->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + //if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + $pdf->setPage($pageposafter+1); + } + } + else + { + // We found a page break + $showpricebeforepagebreak=0; + } + } + else // No pagebreak + { + $pdf->commitTransaction(); + } + $posYAfterDescription=$pdf->GetY(); + } + + $nexY = $pdf->GetY(); + $pageposafter=$pdf->getPage(); + + $pdf->setPage($pageposbefore); + $pdf->setTopMargin($this->marge_haute); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + + // We suppose that a too long description or photo were moved completely on next page + if ($pageposafter > $pageposbefore && empty($showpricebeforepagebreak)) { + $pdf->setPage($pageposafter); $curY = $tab_top_newpage; + } + + $pdf->SetFont('','', $default_font_size - 1); // On repositionne la police par defaut + + // VAT Rate + if ($this->getColumnStatus('vat')) + { + $vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'vat', $vat_rate); + $nexY = max($pdf->GetY(),$nexY); + } + + // Unit price before discount + if ($this->getColumnStatus('subprice')) + { + $up_excl_tax = pdf_getlineupexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'subprice', $up_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + // Quantity + // Enough for 6 chars + if ($this->getColumnStatus('qty')) + { + $qty = pdf_getlineqty($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'qty', $qty); + $nexY = max($pdf->GetY(),$nexY); + } + + + // Unit + if ($this->getColumnStatus('unit')) + { + $unit = pdf_getlineunit($object, $i, $outputlangs, $hidedetails, $hookmanager); + $this->printStdColumnContent($pdf, $curY, 'unit', $unit); + $nexY = max($pdf->GetY(),$nexY); + } + + // Discount on line + if ($this->getColumnStatus('discount') && $object->lines[$i]->remise_percent) + { + $remise_percent = pdf_getlineremisepercent($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'discount', $remise_percent); + $nexY = max($pdf->GetY(),$nexY); + } + + // Total HT line + if ($this->getColumnStatus('totalexcltax')) + { + $total_excl_tax = pdf_getlinetotalexcltax($object, $i, $outputlangs, $hidedetails); + $this->printStdColumnContent($pdf, $curY, 'totalexcltax', $total_excl_tax); + $nexY = max($pdf->GetY(),$nexY); + } + + + $parameters=array( + 'object' => $object, + 'i' => $i, + 'pdf' =>& $pdf, + 'curY' =>& $curY, + 'nexY' =>& $nexY, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails + ); + $reshook=$hookmanager->executeHooks('printPDFline',$parameters,$this); // Note that $object may have been modified by hook + + + + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + if ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) $tvaligne=$object->lines[$i]->multicurrency_total_tva; + else $tvaligne=$object->lines[$i]->total_tva; + + $localtax1ligne=$object->lines[$i]->total_localtax1; + $localtax2ligne=$object->lines[$i]->total_localtax2; + $localtax1_rate=$object->lines[$i]->localtax1_tx; + $localtax2_rate=$object->lines[$i]->localtax2_tx; + $localtax1_type=$object->lines[$i]->localtax1_type; + $localtax2_type=$object->lines[$i]->localtax2_type; + + if ($object->remise_percent) $tvaligne-=($tvaligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax1ligne-=($localtax1ligne*$object->remise_percent)/100; + if ($object->remise_percent) $localtax2ligne-=($localtax2ligne*$object->remise_percent)/100; + + $vatrate=(string) $object->lines[$i]->tva_tx; + + // Retrieve type from database for backward compatibility with old records + if ((! isset($localtax1_type) || $localtax1_type=='' || ! isset($localtax2_type) || $localtax2_type=='') // if tax type not defined + && (! empty($localtax1_rate) || ! empty($localtax2_rate))) // and there is local tax + { + $localtaxtmp_array=getLocalTaxesFromRate($vatrate,0,$object->thirdparty,$mysoc); + $localtax1_type = $localtaxtmp_array[0]; + $localtax2_type = $localtaxtmp_array[2]; + } + + // retrieve global local tax + if ($localtax1_type && $localtax1ligne != 0) + $this->localtax1[$localtax1_type][$localtax1_rate]+=$localtax1ligne; + if ($localtax2_type && $localtax2ligne != 0) + $this->localtax2[$localtax2_type][$localtax2_rate]+=$localtax2ligne; + + if (($object->lines[$i]->info_bits & 0x01) == 0x01) $vatrate.='*'; + if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=0; + $this->tva[$vatrate] += $tvaligne; + + if ($posYAfterImage > $posYAfterDescription) $nexY=$posYAfterImage; + + // Add line + if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) + { + $pdf->setPage($pageposafter); + $pdf->SetLineStyle(array('dash'=>'1,1','color'=>array(80,80,80))); + //$pdf->SetDrawColor(190,190,200); + $pdf->line($this->marge_gauche, $nexY+1, $this->page_largeur - $this->marge_droite, $nexY+1); + $pdf->SetLineStyle(array('dash'=>0)); + } + + $nexY+=2; // Passe espace entre les lignes + + // Detect if some page were added automatically and output _tableau for past pages + while ($pagenb < $pageposafter) + { + $pdf->setPage($pagenb); + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + $pagenb++; + $pdf->setPage($pagenb); + $pdf->setPageOrientation('', 1, 0); // The only function to edit the bottom margin of current page to set it. + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak) + { + if ($pagenb == $pageposafter) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1, $object->multicurrency_code); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1, $object->multicurrency_code); + } + $this->_pagefoot($pdf,$object,$outputlangs,1); + // New page + $pdf->AddPage(); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + $pagenb++; + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); + } + } + + // Show square + if ($pagenb == $pageposbeforeprintlines) + { + $this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 0, 0, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1; + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter, 0, $outputlangs, 1, 0, $object->multicurrency_code); + $bottomlasttab=$this->page_hauteur - $heightforinfotot - $heightforfreetext - $heightforsignature - $heightforfooter + 1; + } + + // Affiche zone infos + $posy=$this->_tableau_info($pdf, $object, $bottomlasttab, $outputlangs); + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $object, 0, $bottomlasttab, $outputlangs); + + // Affiche zone versements + /* + if ($deja_regle || $amount_credit_notes_included || $amount_deposits_included) + { + $posy=$this->_tableau_versements($pdf, $object, $posy, $outputlangs); + } + */ + + // Customer signature area + if (empty($conf->global->PROPAL_DISABLE_SIGNATURE)) + { + $posy=$this->_signature_area($pdf, $object, $posy, $outputlangs); + } + + // Pied de page + $this->_pagefoot($pdf,$object,$outputlangs); + if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages(); + + //If propal merge product PDF is active + if (!empty($conf->global->PRODUIT_PDF_MERGE_PROPAL)) + { + require_once DOL_DOCUMENT_ROOT.'/product/class/propalmergepdfproduct.class.php'; + + $already_merged = array (); + foreach ( $object->lines as $line ) { + if (! empty($line->fk_product) && ! (in_array($line->fk_product, $already_merged))) { + // Find the desire PDF + $filetomerge = new Propalmergepdfproduct($this->db); + + if ($conf->global->MAIN_MULTILANGS) { + $filetomerge->fetch_by_product($line->fk_product, $outputlangs->defaultlang); + } else { + $filetomerge->fetch_by_product($line->fk_product); + } + + $already_merged[] = $line->fk_product; + + $product = new Product($this->db); + $product->fetch($line->fk_product); + + if ($product->entity!=$conf->entity) { + $entity_product_file=$product->entity; + } else { + $entity_product_file=$conf->entity; + } + + // If PDF is selected and file is not empty + if (count($filetomerge->lines) > 0) { + foreach ( $filetomerge->lines as $linefile ) { + if (! empty($linefile->id) && ! empty($linefile->file_name)) { + + + if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) + { + if (! empty($conf->product->enabled)) { + $filetomerge_dir = $conf->product->multidir_output[$entity_product_file] . '/' . get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos"; + } elseif (! empty($conf->service->enabled)) { + $filetomerge_dir = $conf->service->multidir_output[$entity_product_file] . '/' . get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos"; + } + } + else + { + if (! empty($conf->product->enabled)) { + $filetomerge_dir = $conf->product->multidir_output[$entity_product_file] . '/' . get_exdir(0,0,0,0,$product,'product') . dol_sanitizeFileName($product->ref); + } elseif (! empty($conf->service->enabled)) { + $filetomerge_dir = $conf->service->multidir_output[$entity_product_file] . '/' . get_exdir(0,0,0,0,$product,'product') . dol_sanitizeFileName($product->ref); + } + } + + dol_syslog(get_class($this) . ':: upload_dir=' . $filetomerge_dir, LOG_DEBUG); + + $infile = $filetomerge_dir . '/' . $linefile->file_name; + if (file_exists($infile) && is_readable($infile)) { + $pagecount = $pdf->setSourceFile($infile); + for($i = 1; $i <= $pagecount; $i ++) { + $tplIdx = $pdf->importPage($i); + if ($tplIdx!==false) { + $s = $pdf->getTemplatesize($tplIdx); + $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L'); + $pdf->useTemplate($tplIdx); + } else { + setEventMessages(null, array($infile.' cannot be added, probably protected PDF'),'warnings'); + } + } + } + } + } + } + } + } + } + + $pdf->Close(); + + $pdf->Output($file,'F'); + + //Add pdfgeneration hook + $hookmanager->initHooks(array('pdfgeneration')); + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + global $action; + $reshook=$hookmanager->executeHooks('afterPDFCreation',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $this->result = array('fullpath'=>$file); + + return 1; // Pas d'erreur + } + else + { + $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); + return 0; + } + } + else + { + $this->error=$langs->trans("ErrorConstantNotDefined","PROP_OUTPUTDIR"); + return 0; + } + } + + /** + * Show payments table + * + * @param TCPDF $pdf Object PDF + * @param Object $object Object proposal + * @param int $posy Position y in PDF + * @param Translate $outputlangs Object langs for output + * @return int <0 if KO, >0 if OK + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + + } + + + /** + * Show miscellaneous information (payment mode, payment term, ...) + * + * @param TCPDF $pdf Object PDF + * @param Object $object Object to show + * @param int $posy Y + * @param Translate $outputlangs Langs object + * @return void + */ + function _tableau_info(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $pdf->SetFont('','', $default_font_size - 1); + + // If France, show VAT mention if not applicable + if ($this->emetteur->country_code == 'FR' && $this->franchise == 1) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + + $posy=$pdf->GetY()+4; + } + + $posxval=52; + + // Show shipping date + if (! empty($object->date_livraison)) + { + $outputlangs->load("sendings"); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("DateDeliveryPlanned").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $dlp=dol_print_date($object->date_livraison,"daytext",false,$outputlangs,true); + $pdf->MultiCell(80, 4, $dlp, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + elseif ($object->availability_code || $object->availability) // Show availability conditions + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("AvailabilityPeriod").':'; + $pdf->MultiCell(80, 4, $titre, 0, 'L'); + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_availability=$outputlangs->transnoentities("AvailabilityType".$object->availability_code)!=('AvailabilityType'.$object->availability_code)?$outputlangs->transnoentities("AvailabilityType".$object->availability_code):$outputlangs->convToOutputCharset($object->availability); + $lib_availability=str_replace('\n',"\n",$lib_availability); + $pdf->MultiCell(80, 4, $lib_availability, 0, 'L'); + + $posy=$pdf->GetY()+1; + } + + // Show payments conditions + if (empty($conf->global->PROPALE_PDF_HIDE_PAYMENTTERMCOND) && ($object->cond_reglement_code || $object->cond_reglement)) + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(43, 4, $titre, 0, 'L'); + + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$outputlangs->convToOutputCharset($object->cond_reglement_doc); + $lib_condition_paiement=str_replace('\n',"\n",$lib_condition_paiement); + $pdf->MultiCell(67, 4, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + + if (empty($conf->global->PROPALE_PDF_HIDE_PAYMENTTERMMODE)) + { + // Check a payment mode is defined + /* Not required on a proposal + if (empty($object->mode_reglement_code) + && ! $conf->global->FACTURE_CHQ_NUMBER + && ! $conf->global->FACTURE_RIB_NUMBER) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0); + $pdf->SetTextColor(0,0,0); + + $posy=$pdf->GetY()+1; + } + */ + + // Show payment mode + if ($object->mode_reglement_code + && $object->mode_reglement_code != 'CHQ' + && $object->mode_reglement_code != 'VIR') + { + $pdf->SetFont('','B', $default_font_size - 2); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentMode").':'; + $pdf->MultiCell(80, 5, $titre, 0, 'L'); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posxval, $posy); + $lib_mode_reg=$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code)!=('PaymentType'.$object->mode_reglement_code)?$outputlangs->transnoentities("PaymentType".$object->mode_reglement_code):$outputlangs->convToOutputCharset($object->mode_reglement); + $pdf->MultiCell(80, 5, $lib_mode_reg,0,'L'); + + $posy=$pdf->GetY()+2; + } + + // Show payment mode CHQ + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'CHQ') + { + // Si mode reglement non force ou si force a CHQ + if (! empty($conf->global->FACTURE_CHQ_NUMBER)) + { + $diffsizetitle=(empty($conf->global->PDF_DIFFSIZE_TITLE)?3:$conf->global->PDF_DIFFSIZE_TITLE); + + if ($conf->global->FACTURE_CHQ_NUMBER > 0) + { + $account = new Account($this->db); + $account->fetch($conf->global->FACTURE_CHQ_NUMBER); + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($account->owner_address), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + if ($conf->global->FACTURE_CHQ_NUMBER == -1) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','B', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$this->emetteur->name),0,'L',0); + $posy=$pdf->GetY()+1; + + if (empty($conf->global->MAIN_PDF_HIDE_CHQ_ADDRESS)) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('','', $default_font_size - $diffsizetitle); + $pdf->MultiCell(100, 3, $outputlangs->convToOutputCharset($this->emetteur->getFullAddress()), 0, 'L', 0); + $posy=$pdf->GetY()+2; + } + } + } + } + + // If payment mode not forced or forced to VIR, show payment with BAN + if (empty($object->mode_reglement_code) || $object->mode_reglement_code == 'VIR') + { + if (! empty($object->fk_account) || ! empty($object->fk_bank) || ! empty($conf->global->FACTURE_RIB_NUMBER)) + { + $bankid=(empty($object->fk_account)?$conf->global->FACTURE_RIB_NUMBER:$object->fk_account); + if (! empty($object->fk_bank)) $bankid=$object->fk_bank; // For backward compatibility when object->fk_account is forced with object->fk_bank + $account = new Account($this->db); + $account->fetch($bankid); + + $curx=$this->marge_gauche; + $cury=$posy; + + $posy=pdf_bank($pdf,$outputlangs,$curx,$cury,$account,0,$default_font_size); + + $posy+=2; + } + } + } + + return $posy; + } + + + /** + * Show total to pay + * + * @param PDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $deja_regle Montant deja regle + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + global $conf,$mysoc; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + $tab2_top = $posy; + $tab2_hl = 4; + $pdf->SetFont('','', $default_font_size - 1); + + // Tableau total + $col1x = 120; $col2x = 170; + if ($this->page_largeur < 210) // To work with US executive format + { + $col2x-=20; + } + $largcol2 = ($this->page_largeur - $this->marge_droite - $col2x); + + $useborder=0; + $index = 0; + + // Total HT + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($col1x, $tab2_top + 0); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalHT"), 0, 'L', 1); + + $total_ht = ($conf->multicurrency->enabled && $object->mylticurrency_tx != 1 ? $object->multicurrency_total_ht : $object->total_ht); + $pdf->SetXY($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ht + (! empty($object->remise)?$object->remise:0), 0, $outputlangs), 0, 'R', 1); + + // Show VAT by rates and total + $pdf->SetFillColor(248,248,248); + + $total_ttc = ($conf->multicurrency->enabled && $object->multicurrency_tx != 1) ? $object->multicurrency_total_ttc : $object->total_ttc; + + $this->atleastoneratenotnull=0; + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) + { + $tvaisnull=((! empty($this->tva) && count($this->tva) == 1 && isset($this->tva['0.000']) && is_float($this->tva['0.000'])) ? true : false); + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_IFNULL) && $tvaisnull) + { + // Nothing to do + } + else + { + //Local tax 1 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 before VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('1','3','5'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey!=0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2", $mysoc->country_code).' '; + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + + } + } + } + //} + // VAT + foreach($this->tva as $tvakey => $tvaval) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + $this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat =$outputlangs->transcountrynoentities("TotalVAT",$mysoc->country_code).' '; + $totalvat.=vatrate($tvakey,1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + + //Local tax 1 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX1_OPTION) && $conf->global->FACTURE_LOCAL_TAX1_OPTION=='localtax1on') + //{ + foreach( $this->localtax1 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT1",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + //Local tax 2 after VAT + //if (! empty($conf->global->FACTURE_LOCAL_TAX2_OPTION) && $conf->global->FACTURE_LOCAL_TAX2_OPTION=='localtax2on') + //{ + foreach( $this->localtax2 as $localtax_type => $localtax_rate ) + { + if (in_array((string) $localtax_type, array('2','4','6'))) continue; + + foreach( $localtax_rate as $tvakey => $tvaval ) + { + // retrieve global local tax + if ($tvakey != 0) // On affiche pas taux 0 + { + //$this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (preg_match('/\*/',$tvakey)) + { + $tvakey=str_replace('*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat = $outputlangs->transcountrynoentities("TotalLT2",$mysoc->country_code).' '; + + $totalvat.=vatrate(abs($tvakey),1).$tvacompl; + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $totalvat, 0, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + } + } + } + //} + + // Total TTC + $index++; + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalTTC"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($total_ttc, 0, $outputlangs), $useborder, 'R', 1); + } + } + + $pdf->SetTextColor(0,0,0); + + /* + $resteapayer = $object->total_ttc - $deja_regle; + if (! empty($object->paye)) $resteapayer=0; + */ + + if ($deja_regle > 0) + { + $index++; + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPaid"), 0, 'L', 0); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle, 0, $outputlangs), 0, 'R', 0); + + /* + if ($object->close_code == 'discount_vat') + { + $index++; + $pdf->SetFillColor(255,255,255); + + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("EscompteOfferedShort"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle, 0, $outputlangs), $useborder, 'R', 1); + + $resteapayer=0; + } + */ + + $index++; + $pdf->SetTextColor(0,0,60); + $pdf->SetFillColor(224,224,224); + $pdf->SetXY($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("RemainderToPay"), $useborder, 'L', 1); + + $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($resteapayer, 0, $outputlangs), $useborder, 'R', 1); + + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetTextColor(0,0,0); + } + + $index++; + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * Show table for lines + * + * @param PDF $pdf Object PDF + * @param string $tab_top Top position of table + * @param string $tab_height Height of table (rectangle) + * @param int $nexY Y (not used) + * @param Translate $outputlangs Langs object + * @param int $hidetop 1=Hide top bar of array and title, 0=Hide nothing, -1=Hide only title + * @param int $hidebottom Hide bottom bar of array + * @param string $currency Currency code + * @return void + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs, $hidetop=0, $hidebottom=0, $currency='') + { + global $conf; + + // Force to disable hidetop and hidebottom + $hidebottom=0; + if ($hidetop) $hidetop=-1; + + $currency = !empty($currency) ? $currency : $conf->currency; + $default_font_size = pdf_getPDFFontSize($outputlangs); + + // Amount in (at tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + + if (empty($hidetop)) + { + $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency)); + $pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 3), $tab_top-4); + $pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre); + + //$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR='230,230,230'; + if (! empty($conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)) $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_droite-$this->marge_gauche, 5, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); + } + + $pdf->SetDrawColor(128,128,128); + $pdf->SetFont('','', $default_font_size - 1); + + // Output Rect + $this->printRect($pdf,$this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height, $hidetop, $hidebottom); // Rect prend une longueur en 3eme param et 4eme param + + + foreach ($this->cols as $colKey => $colDef) + { + if(!$this->getColumnStatus($colKey)) continue; + + // get title label + $colDef['title']['label'] = !empty($colDef['title']['label'])?$colDef['title']['label']:$outputlangs->transnoentities($colDef['title']['textkey']); + + // Add column separator + if(!empty($colDef['border-left'])){ + $pdf->line($colDef['xStartPos'], $tab_top, $colDef['xStartPos'], $tab_top + $tab_height); + } + + if (empty($hidetop)) + { + $pdf->SetXY($colDef['xStartPos'] + $colDef['title']['padding'][3], $tab_top + $colDef['title']['padding'][0] ); + + $textWidth = $colDef['width'] - $colDef['title']['padding'][3] -$colDef['title']['padding'][1]; + $pdf->MultiCell($textWidth,2,$colDef['title']['label'],'',$colDef['title']['align']); + } + } + + if (empty($hidetop)){ + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); // line prend une position y en 2eme param et 4eme param + } + + + } + + /** + * Show top header of page. + * + * @param PDF $pdf Object PDF + * @param Object $object Object to show + * @param int $showaddress 0=no, 1=yes + * @param Translate $outputlangs Object lang for output + * @return void + */ + function _pagehead(&$pdf, $object, $showaddress, $outputlangs) + { + global $conf,$langs; + + $outputlangs->load("main"); + $outputlangs->load("bills"); + $outputlangs->load("propal"); + $outputlangs->load("companies"); + + $default_font_size = pdf_getPDFFontSize($outputlangs); + + pdf_pagehead($pdf,$outputlangs,$this->page_hauteur); + + // Show Draft Watermark + if($object->statut==0 && (! empty($conf->global->PROPALE_DRAFT_WATERMARK)) ) + { + pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->PROPALE_DRAFT_WATERMARK); + } + + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('','B', $default_font_size + 3); + + $posy=$this->marge_haute; + $posx=$this->page_largeur-$this->marge_droite-100; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $height=pdf_getHeightForLogo($logo); + $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height); // width=0 (auto) + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('','B',$default_font_size - 2); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else + { + $text=$this->emetteur->name; + $pdf->MultiCell(100, 4, $outputlangs->convToOutputCharset($text), 0, 'L'); + } + + $pdf->SetFont('','B',$default_font_size + 3); + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("PdfCommercialProposalTitle"); + $pdf->MultiCell(100, 4, $title, '', 'R'); + + $pdf->SetFont('','B',$default_font_size); + + $posy+=5; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $outputlangs->convToOutputCharset($object->ref), '', 'R'); + + $posy+=1; + $pdf->SetFont('','', $default_font_size - 2); + + if ($object->ref_client) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("RefCustomer")." : " . $outputlangs->convToOutputCharset($object->ref_client), '', 'R'); + } + + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Date")." : " . dol_print_date($object->date,"day",false,$outputlangs,true), '', 'R'); + + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : " . dol_print_date($object->fin_validite,"day",false,$outputlangs,true), '', 'R'); + + if ($object->thirdparty->code_client) + { + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("CustomerCode")." : " . $outputlangs->transnoentities($object->thirdparty->code_client), '', 'R'); + } + + // Get contact + if (!empty($conf->global->DOC_SHOW_FIRST_SALES_REP)) + { + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $usertmp=new User($this->db); + $usertmp->fetch($arrayidcontact[0]); + $posy+=4; + $pdf->SetXY($posx,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $langs->trans("SalesRepresentative")." : ".$usertmp->getFullName($langs), '', 'R'); + } + } + + $posy+=2; + + $top_shift = 0; + // Show list of linked objects + $current_y = $pdf->getY(); + $posy = pdf_writeLinkedObjects($pdf, $object, $outputlangs, $posx, $posy, 100, 3, 'R', $default_font_size); + if ($current_y < $pdf->getY()) + { + $top_shift = $pdf->getY() - $current_y; + } + + if ($showaddress) + { + // Sender properties + $carac_emetteur=''; + // Add internal contact of proposal if defined + $arrayidcontact=$object->getIdContact('internal','SALESREPFOLL'); + if (count($arrayidcontact) > 0) + { + $object->fetch_user($arrayidcontact[0]); + $labelbeforecontactname=($outputlangs->transnoentities("FromContactName")!='FromContactName'?$outputlangs->transnoentities("FromContactName"):$outputlangs->transnoentities("Name")); + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$labelbeforecontactname." ".$outputlangs->convToOutputCharset($object->user->getFullName($outputlangs))."\n"; + } + + $carac_emetteur .= pdf_build_address($outputlangs, $this->emetteur, $object->thirdparty, '', 0, 'source', $object); + + // Show sender + $posy=42+$top_shift; + $posx=$this->marge_gauche; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->page_largeur-$this->marge_droite-80; + $hautcadre=40; + + // Show sender frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":", 0, 'L'); + $pdf->SetXY($posx,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1); + $pdf->SetTextColor(0,0,60); + + // Show sender name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell(80, 4, $outputlangs->convToOutputCharset($this->emetteur->name), 0, 'L'); + $posy=$pdf->getY(); + + // Show sender information + $pdf->SetXY($posx+2,$posy); + $pdf->SetFont('','', $default_font_size - 1); + $pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L'); + + + // If CUSTOMER contact defined, we use it + $usecontact=false; + $arrayidcontact=$object->getIdContact('external','CUSTOMER'); + if (count($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + + //Recipient name + // On peut utiliser le nom de la societe du contact + if ($usecontact && !empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) { + $thirdparty = $object->contact; + } else { + $thirdparty = $object->thirdparty; + } + + $carac_client_name= pdfBuildThirdpartyName($thirdparty, $outputlangs); + + $carac_client=pdf_build_address($outputlangs,$this->emetteur,$object->thirdparty,($usecontact?$object->contact:''),$usecontact,'target',$object); + + // Show recipient + $widthrecbox=100; + if ($this->page_largeur < 210) $widthrecbox=84; // To work with US executive format + $posy=42+$top_shift; + $posx=$this->page_largeur-$this->marge_droite-$widthrecbox; + if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=$this->marge_gauche; + + // Show recipient frame + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->SetXY($posx+2,$posy-5); + $pdf->MultiCell($widthrecbox, 5, $outputlangs->transnoentities("BillTo").":", 0, 'L'); + $pdf->Rect($posx, $posy, $widthrecbox, $hautcadre); + + // Show recipient name + $pdf->SetXY($posx+2,$posy+3); + $pdf->SetFont('','B', $default_font_size); + $pdf->MultiCell($widthrecbox, 4, $carac_client_name, 0, 'L'); + + $posy = $pdf->getY(); + + // Show recipient information + $pdf->SetFont('','', $default_font_size - 1); + $pdf->SetXY($posx+2,$posy); + $pdf->MultiCell($widthrecbox, 4, $carac_client, 0, 'L'); + } + + $pdf->SetTextColor(0,0,0); + return $top_shift; + } + + /** + * Show footer of page. Need this->emetteur object + * + * @param PDF $pdf PDF + * @param Object $object Object to show + * @param Translate $outputlangs Object lang for output + * @param int $hidefreetext 1=Hide free text + * @return int Return height of bottom margin including footer text + */ + function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0) + { + global $conf; + $showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS; + return pdf_pagefoot($pdf,$outputlangs,'PROPOSAL_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext); + } + + /** + * Show area for the customer to sign + * + * @param PDF $pdf Object PDF + * @param Facture $object Object invoice + * @param int $posy Position depart + * @param Translate $outputlangs Objet langs + * @return int Position pour suite + */ + function _signature_area(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + $default_font_size = pdf_getPDFFontSize($outputlangs); + $tab_top = $posy + 4; + $tab_hl = 4; + + $posx = 120; + $largcol = ($this->page_largeur - $this->marge_droite - $posx); + $useborder=0; + $index = 0; + // Total HT + $pdf->SetFillColor(255,255,255); + $pdf->SetXY($posx, $tab_top + 0); + $pdf->SetFont('','', $default_font_size - 2); + $pdf->MultiCell($largcol, $tab_hl, $outputlangs->transnoentities("ProposalCustomerSignature"), 0, 'L', 1); + + $pdf->SetXY($posx, $tab_top + $tab_hl); + $pdf->MultiCell($largcol, $tab_hl*3, '', 1, 'R'); + if (! empty($conf->global->MAIN_PDF_PROPAL_USE_ELECTRONIC_SIGNING)) { + $pdf->addEmptySignatureAppearance($posx, $tab_top + $tab_hl, $largcol, $tab_hl*3); + } + + return ($tab_hl*7); + } + + + /** + * Define Array Column Field + * + * @param object $object common object + * @param outputlangs $outputlangs langs + * @param int $hidedetails Do not show line details + * @param int $hidedesc Do not show desc + * @param int $hideref Do not show ref + * @return null + */ + function defineColumnField($object,$outputlangs,$hidedetails=0,$hidedesc=0,$hideref=0){ + + global $conf, $hookmanager; + + // Default field style for content + $this->defaultContentsFieldsStyle = array( + 'align' => 'R', // R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + // Default field style for content + $this->defaultTitlesFieldsStyle = array( + 'align' => 'C', // R,C,L + 'padding' => array(0.5,0,0.5,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ); + + /* + * For exemple + $this->cols['theColKey'] = array( + 'rank' => $rank, // int : use for ordering columns + 'width' => 20, // the column width in mm + 'title' => array( + 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + 'label' => ' ', // the final label : used fore final generated text + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', // text alignement : R,C,L + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + ); + */ + + $rank=0; // do not use negative rank + $this->cols['desc'] = array( + 'rank' => $rank, + 'width' => false, // only for desc + 'status' => true, + 'title' => array( + 'textkey' => 'Designation', // use lang key is usefull in somme case with module + 'align' => 'L', + // 'textkey' => 'yourLangKey', // if there is no label, yourLangKey will be translated to replace label + // 'label' => ' ', // the final label + 'padding' => array(0.5,0.5,0.5,0.5), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'content' => array( + 'align' => 'L', + ), + ); + + $rank = $rank + 10; + $this->cols['photo'] = array( + 'rank' => $rank, + 'width' => (empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?20:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH), // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Photo', + 'label' => ' ' + ), + 'content' => array( + 'padding' => array(0,0,0,0), // Like css 0 => top , 1 => right, 2 => bottom, 3 => left + ), + 'border-left' => false, // remove left line separator + ); + + if (! empty($conf->global->MAIN_GENERATE_PROPOSALS_WITH_PICTURE) && !empty($this->atleastonephoto)) + { + $this->cols['photo']['status'] = true; + } + + + $rank = $rank + 10; + $this->cols['vat'] = array( + 'rank' => $rank, + 'status' => false, + 'width' => 16, // in mm + 'title' => array( + 'textkey' => 'VAT' + ), + 'border-left' => true, // add left line separator + ); + + if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT) && empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT_COLUMN)) + { + $this->cols['vat']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['subprice'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'PriceUHT' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['qty'] = array( + 'rank' => $rank, + 'width' => 16, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'Qty' + ), + 'border-left' => true, // add left line separator + ); + + $rank = $rank + 10; + $this->cols['progress'] = array( + 'rank' => $rank, + 'width' => 19, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Progress' + ), + 'border-left' => false, // add left line separator + ); + + if($this->situationinvoice) + { + $this->cols['progress']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['unit'] = array( + 'rank' => $rank, + 'width' => 11, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'Unit' + ), + 'border-left' => true, // add left line separator + ); + if($conf->global->PRODUCT_USE_UNITS){ + $this->cols['unit']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['discount'] = array( + 'rank' => $rank, + 'width' => 13, // in mm + 'status' => false, + 'title' => array( + 'textkey' => 'ReductionShort' + ), + 'border-left' => true, // add left line separator + ); + if ($this->atleastonediscount){ + $this->cols['discount']['status'] = true; + } + + $rank = $rank + 10; + $this->cols['totalexcltax'] = array( + 'rank' => $rank, + 'width' => 26, // in mm + 'status' => true, + 'title' => array( + 'textkey' => 'TotalHT' + ), + 'border-left' => true, // add left line separator + ); + + + $parameters=array( + 'object' => $object, + 'outputlangs' => $outputlangs, + 'hidedetails' => $hidedetails, + 'hidedesc' => $hidedesc, + 'hideref' => $hideref + ); + + $reshook=$hookmanager->executeHooks('defineColumnField',$parameters,$this); // Note that $object may have been modified by hook + if ($reshook < 0) + { + setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); + } + elseif (empty($reshook)) + { + $this->cols = array_replace($this->cols, $hookmanager->resArray); // array_replace is used to preserve keys + } + else + { + $this->cols = $hookmanager->resArray; + } + + } + +} diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index d06b1512cc6..3b60256c3ef 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -486,7 +486,8 @@ RevenueStamp=Revenue stamp YouMustCreateInvoiceFromThird=This option is only available when creating invoice from tab "customer" of third party YouMustCreateInvoiceFromSupplierThird=This option is only available when creating invoice from tab "supplier" of third party YouMustCreateStandardInvoiceFirstDesc=You have to create a standard invoice first and convert it to "template" to create a new template invoice -PDFCrabeDescription=Invoice PDF template Crabe. A complete invoice template (recommended Template) +PDFCrabeDescription=Invoice PDF template Crabe. A complete invoice template (deprecated Template) +PDFSpongeDescription=Invoice PDF template Sponge. A complete invoice template (recommended Template) PDFCrevetteDescription=Invoice PDF template Crevette. A complete invoice template for situation invoices TerreNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0 MarsNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices, %syymm-nnnn for replacement invoices, %syymm-nnnn for down payment invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0 diff --git a/htdocs/langs/en_US/orders.lang b/htdocs/langs/en_US/orders.lang index 06191d9f7b7..30fb0aa1320 100644 --- a/htdocs/langs/en_US/orders.lang +++ b/htdocs/langs/en_US/orders.lang @@ -140,7 +140,8 @@ OrderByEMail=EMail OrderByWWW=Online OrderByPhone=Phone # Documents models -PDFEinsteinDescription=A complete order model (logo...) +PDFEinsteinDescription=A complete order model (logo...)(deprecated Template) +PDFEratostheneDescription=A complete order model (logo...)(recommended Template) PDFEdisonDescription=A simple order model PDFProformaDescription=A complete proforma invoice (logo…) CreateInvoiceForThisCustomer=Bill orders diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 5a7169ac925..55fb6372d74 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -77,7 +77,8 @@ TypeContact_propal_external_BILLING=Customer invoice contact TypeContact_propal_external_CUSTOMER=Customer contact following-up proposal TypeContact_propal_external_SHIPPING=Customer contact for delivery # Document models -DocModelAzurDescription=A complete proposal model (logo...) +DocModelAzurDescription=A complete proposal model (logo...)(deprecated Template) +DocModelCyanDescription=A complete proposal model (logo...)(recommended Template) DefaultModelPropalCreate=Default model creation DefaultModelPropalToBill=Default template when closing a business proposal (to be invoiced) DefaultModelPropalClosed=Default template when closing a business proposal (unbilled) From 477acb2e4c6267971ca11c7a36889b6c5adf0204 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Fri, 14 Sep 2018 09:48:15 +0200 Subject: [PATCH 02/69] change new PDF version --- htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php | 2 +- htdocs/core/modules/propale/doc/pdf_azur.modules.php | 2 +- htdocs/core/modules/propale/doc/pdf_cyan.modules.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php index 58129bea6e2..039f29fa379 100644 --- a/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php +++ b/htdocs/core/modules/commande/doc/pdf_eratosthene.modules.php @@ -76,7 +76,7 @@ class pdf_eratosthene extends ModelePDFCommandes * Dolibarr version of the loaded document * @public string */ - public $version = 'dolibarr'; + public $version = 'development'; public $page_largeur; public $page_hauteur; diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index 6e72e757fb6..e25abd5bc9e 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -47,7 +47,7 @@ class pdf_azur extends ModelePDFPropales var $type; var $phpmin = array(4,3,0); // Minimum version of PHP required by module - var $version = 'dolibarr'; + var $version = 'development'; var $page_largeur; var $page_hauteur; diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 383f34acebd..c9bce8b07a4 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -47,7 +47,7 @@ class pdf_cyan extends ModelePDFPropales var $type; var $phpmin = array(4,3,0); // Minimum version of PHP required by module - var $version = 'dolibarr'; + var $version = 'development'; var $page_largeur; var $page_hauteur; From d1321e5a7b21ad5fa83ed03b494384d72a7487e5 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Fri, 14 Sep 2018 09:54:39 +0200 Subject: [PATCH 03/69] change new PDF version --- htdocs/core/modules/facture/doc/pdf_sponge.modules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php index 72c2a5aaca6..74f4bf34acf 100644 --- a/htdocs/core/modules/facture/doc/pdf_sponge.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_sponge.modules.php @@ -77,7 +77,7 @@ class pdf_sponge extends ModelePDFFactures * Dolibarr version of the loaded document * @public string */ - public $version = 'dolibarr'; + public $version = 'development'; public $page_largeur; public $page_hauteur; From 3fb2d4c159bb3dd62b143ca3ca9584bb25cb2849 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Tue, 18 Sep 2018 15:52:57 +0200 Subject: [PATCH 04/69] remove change on text --- htdocs/langs/en_US/bills.lang | 4 ++-- htdocs/langs/en_US/orders.lang | 4 ++-- htdocs/langs/en_US/propal.lang | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index ab2adf33441..95114c96446 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -488,8 +488,8 @@ RevenueStamp=Revenue stamp YouMustCreateInvoiceFromThird=This option is only available when creating invoice from tab "customer" of third party YouMustCreateInvoiceFromSupplierThird=This option is only available when creating invoice from tab "supplier" of third party YouMustCreateStandardInvoiceFirstDesc=You have to create a standard invoice first and convert it to "template" to create a new template invoice -PDFCrabeDescription=Invoice PDF template Crabe. A complete invoice template (deprecated Template) -PDFSpongeDescription=Invoice PDF template Sponge. A complete invoice template (recommended Template) +PDFCrabeDescription=Invoice PDF template Crabe. A complete invoice template (recommended Template) +PDFSpongeDescription=Invoice PDF template Sponge. A complete invoice template PDFCrevetteDescription=Invoice PDF template Crevette. A complete invoice template for situation invoices TerreNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0 MarsNumRefModelDesc1=Return number with format %syymm-nnnn for standard invoices, %syymm-nnnn for replacement invoices, %syymm-nnnn for down payment invoices and %syymm-nnnn for credit notes where yy is year, mm is month and nnnn is a sequence with no break and no return to 0 diff --git a/htdocs/langs/en_US/orders.lang b/htdocs/langs/en_US/orders.lang index 1d286cc5ebd..77d2eda19a3 100644 --- a/htdocs/langs/en_US/orders.lang +++ b/htdocs/langs/en_US/orders.lang @@ -140,8 +140,8 @@ OrderByEMail=EMail OrderByWWW=Online OrderByPhone=Phone # Documents models -PDFEinsteinDescription=A complete order model (logo...)(deprecated Template) -PDFEratostheneDescription=A complete order model (logo...)(recommended Template) +PDFEinsteinDescription=A complete order model (logo...) +PDFEratostheneDescription=A complete order model (logo...) PDFEdisonDescription=A simple order model PDFProformaDescription=A complete proforma invoice (logo…) CreateInvoiceForThisCustomer=Bill orders diff --git a/htdocs/langs/en_US/propal.lang b/htdocs/langs/en_US/propal.lang index 44157780ce7..f336daa242d 100644 --- a/htdocs/langs/en_US/propal.lang +++ b/htdocs/langs/en_US/propal.lang @@ -77,8 +77,8 @@ TypeContact_propal_external_BILLING=Customer invoice contact TypeContact_propal_external_CUSTOMER=Customer contact following-up proposal TypeContact_propal_external_SHIPPING=Customer contact for delivery # Document models -DocModelAzurDescription=A complete proposal model (logo...)(deprecated Template) -DocModelCyanDescription=A complete proposal model (logo...)(recommended Template) +DocModelAzurDescription=A complete proposal model (logo...) +DocModelCyanDescription=A complete proposal model (logo...) DefaultModelPropalCreate=Default model creation DefaultModelPropalToBill=Default template when closing a business proposal (to be invoiced) DefaultModelPropalClosed=Default template when closing a business proposal (unbilled) From 23e4cd57f33f8575f2a52912569063e091ae9c7e Mon Sep 17 00:00:00 2001 From: atm-ph Date: Fri, 12 Oct 2018 23:27:38 +0200 Subject: [PATCH 05/69] Fix warnings PHP7 --- htdocs/product/reassort.php | 1 + htdocs/product/reassortlot.php | 1 + htdocs/product/stock/productlot_list.php | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index 70dce7470cd..b1b612d1a39 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -54,6 +54,7 @@ $fourn_id = GETPOST("fourn_id",'int'); $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); +if (empty($page) || $page < 0) $page = 0; if (! $sortfield) $sortfield="p.ref"; if (! $sortorder) $sortorder="ASC"; $limit = GETPOST('limit')?GETPOST('limit','int'):$conf->liste_limit; diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php index 490986b155e..e1b6c82c8f3 100644 --- a/htdocs/product/reassortlot.php +++ b/htdocs/product/reassortlot.php @@ -58,6 +58,7 @@ $fourn_id = GETPOST("fourn_id",'int'); $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); +if (empty($page) || $page < 0) $page = 0; if (! $sortfield) $sortfield="p.ref"; if (! $sortorder) $sortorder="ASC"; $limit = GETPOST('limit')?GETPOST('limit','int'):$conf->liste_limit; diff --git a/htdocs/product/stock/productlot_list.php b/htdocs/product/stock/productlot_list.php index 325ddd5f796..8e5e5d925e9 100644 --- a/htdocs/product/stock/productlot_list.php +++ b/htdocs/product/stock/productlot_list.php @@ -47,6 +47,7 @@ $id = GETPOST('id','int'); $action = GETPOST('action','alpha'); $backtopage = GETPOST('backtopage'); $myparam = GETPOST('myparam','alpha'); +$toselect = GETPOST('toselect', 'array'); $search_entity=GETPOST('search_entity','int'); @@ -152,7 +153,7 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', $search_import_key=''; $search_date_creation=''; $search_date_update=''; - $toselect=''; + $toselect=array(); $search_array_options=array(); } From 7b17b453bf38b0864cb7772effd1e1f25ef9026b Mon Sep 17 00:00:00 2001 From: atm-ph Date: Fri, 12 Oct 2018 23:29:35 +0200 Subject: [PATCH 06/69] Fix sort and switch page --- htdocs/product/reassort.php | 35 ++++++++++++++------------- htdocs/product/reassortlot.php | 43 +++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/htdocs/product/reassort.php b/htdocs/product/reassort.php index b1b612d1a39..fe087fd16a3 100644 --- a/htdocs/product/reassort.php +++ b/htdocs/product/reassort.php @@ -92,11 +92,15 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', $sref=""; $snom=""; $sall=""; + $tosell=""; + $tobuy=""; $search_sale=""; $search_categ=""; $type=""; $catid=''; $toolowstock=''; + $fourn_id=''; + $sbarcode=''; } @@ -183,6 +187,20 @@ if ($resql) } $texte.=' ('.$langs->trans("Stocks").')'; + $param=''; + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + if ($sall) $param.="&sall=".$sall; + if ($tosell) $param.="&tosell=".$tosell; + if ($tobuy) $param.="&tobuy=".$tobuy; + if ($type) $param.="&type=".$type; + if ($fourn_id) $param.="&fourn_id=".$fourn_id; + if ($snom) $param.="&snom=".$snom; + if ($sref) $param.="&sref=".$sref; + if ($search_sale) $param.="&search_sale=".$search_sale; + if ($search_categ) $param.="&search_categ=".$search_categ; + if ($toolowstock) $param.="&toolowstock=".$toolowstock; + if ($sbarcode) $param.="&sbarcode=".$sbarcode; + if ($catid) $param.="&catid=".$catid; llxHeader("", $texte, $helpurl); @@ -193,14 +211,7 @@ if ($resql) print ''; print ''; - if ($sref || $snom || $sall || GETPOST('search')) - { - print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&sall=".$sall."&tosell=".$tosell."&tobuy=".$tobuy.(!empty($search_categ) ? '&search_categ='.$search_categ : '').(!empty($toolowstock) ? '&toolowstock='.$toolowstock : ''), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); - } - else - { - print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&type=$type":"").(!empty($search_categ) ? '&search_categ='.$search_categ : '').(!empty($toolowstock) ? '&toolowstock='.$toolowstock : ''), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); - } + print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); if (! empty($catid)) { @@ -236,14 +247,6 @@ if ($resql) print ''; } - $param=''; - if ($tosell) $param.="&tosell=".$tosell; - if ($tobuy) $param.="&tobuy=".$tobuy; - if ($type) $param.="&type=".$type; - if ($fourn_id) $param.="&fourn_id=".$fourn_id; - if ($snom) $param.="&snom=".$snom; - if ($sref) $param.="&sref=".$sref; - $formProduct = new FormProduct($db); $formProduct->loadWarehouses(); $warehouses_list = $formProduct->cache_warehouses; diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php index e1b6c82c8f3..7cedbcd3981 100644 --- a/htdocs/product/reassortlot.php +++ b/htdocs/product/reassortlot.php @@ -89,6 +89,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', $sref=""; $snom=""; $sall=""; + $tosell=""; + $tobuy=""; $search_sale=""; $search_categ=""; $type=""; @@ -96,6 +98,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', $toolowstock=''; $search_batch=''; $search_warehouse=''; + $fourn_id=''; + $sbarcode=''; } @@ -194,6 +198,24 @@ if ($resql) } $texte.=' ('.$langs->trans("StocksByLotSerial").')'; + $param=''; + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + if ($sall) $param.="&sall=".$sall; + if ($tosell) $param.="&tosell=".$tosell; + if ($tobuy) $param.="&tobuy=".$tobuy; + if ($type) $param.="&type=".$type; + if ($fourn_id) $param.="&fourn_id=".$fourn_id; + if ($snom) $param.="&snom=".$snom; + if ($sref) $param.="&sref=".$sref; + if ($search_batch) $param.="&search_batch=".$search_batch; + if ($sbarcode) $param.="&sbarcode=".$sbarcode; + if ($search_warehouse) $param.="&search_warehouse=".$search_warehouse; + if ($catid) $param.="&catid=".$catid; + if ($toolowstock) $param.="&toolowstock=".$toolowstock; + if ($search_sale) $param.="&search_sale=".$search_sale; + if ($search_categ) $param.="&search_categ=".$search_categ; + /*if ($eatby) $param.="&eatby=".$eatby; + if ($sellby) $param.="&sellby=".$sellby;*/ llxHeader("",$title,$helpurl,$texte); @@ -204,14 +226,8 @@ if ($resql) print ''; print ''; - if ($sref || $snom || $sall || GETPOST('search')) - { - print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=".$sref."&snom=".$snom."&sall=".$sall."&tosell=".$tosell."&tobuy=".$tobuy, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); - } - else - { - print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], "&sref=$sref&snom=$snom&fourn_id=$fourn_id".(isset($type)?"&type=$type":""), $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); - } + print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder,'',$num, $nbtotalofrecords, 'title_products', 0, '', '', $limit); + if (! empty($catid)) { @@ -245,17 +261,6 @@ if ($resql) } - $param=''; - if ($tosell) $param.="&tosell=".$tosell; - if ($tobuy) $param.="&tobuy=".$tobuy; - if ($type) $param.="&type=".$type; - if ($fourn_id) $param.="&fourn_id=".$fourn_id; - if ($snom) $param.="&snom=".$snom; - if ($sref) $param.="&sref=".$sref; - if ($search_batch) $param.="&search_batch=".$search_batch; - /*if ($eatby) $param.="&eatby=".$eatby; - if ($sellby) $param.="&sellby=".$sellby;*/ - print '
'; print ''; From 1f1a614b47d7a0e8a37f496920a2f15f2ab8a189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 14 Oct 2018 10:21:06 +0200 Subject: [PATCH 07/69] Update import.lib.php --- htdocs/core/lib/import.lib.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/htdocs/core/lib/import.lib.php b/htdocs/core/lib/import.lib.php index 89847d69c11..ea700c38845 100644 --- a/htdocs/core/lib/import.lib.php +++ b/htdocs/core/lib/import.lib.php @@ -1,8 +1,9 @@ - * Copyright (C) 2007 Rodolphe Quiedeville - * Copyright (C) 2010 Regis Houssin - * Copyright (C) 2010 Juanjo Menent +/* Copyright (C) 2006-2009 Laurent Destailleur + * Copyright (C) 2007 Rodolphe Quiedeville + * Copyright (C) 2010 Regis Houssin + * Copyright (C) 2010 Juanjo Menent + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +21,9 @@ */ /** - * \file htdocs/core/lib/order.lib.php - * \brief Ensemble de fonctions de base pour le module commande - * \ingroup commande - */ + * \file htdocs/core/lib/import.lib.php + * \brief Ensemble de fonctions de base pour le module import + * \ingroup import /** * Function to return list of tabs for import pages From 70a98743e807a819fc8ec01fa92e5085f2d082c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 14 Oct 2018 10:48:06 +0200 Subject: [PATCH 08/69] Update functions.lib.php --- htdocs/core/lib/functions.lib.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9cbd8562949..cff0ef2b8ef 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -13,6 +13,7 @@ * Copyright (C) 2014 Cédric GROSS * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -5975,11 +5976,12 @@ function complete_head_from_modules($conf,$langs,$object,&$head,&$h,$type,$mode= // No need to make a return $head. Var is modified as a reference if (! empty($hookmanager)) { - $parameters=array('object' => $object, 'mode' => $mode, 'head'=>$head); - $reshook=$hookmanager->executeHooks('completeTabsHead',$parameters); + $parameters=array('object' => $object, 'mode' => $mode, 'head' => $head); + $reshook=$hookmanager->executeHooks('completeTabsHead', $parameters); if ($reshook > 0) { $head = $hookmanager->resArray; + $h = count($head); } } } From 787658ac98fcab578d70b69a2a64aff20f4f8015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 14 Oct 2018 10:56:03 +0200 Subject: [PATCH 09/69] reduce complexity of payments.lib.php --- htdocs/core/lib/payments.lib.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/htdocs/core/lib/payments.lib.php b/htdocs/core/lib/payments.lib.php index ffb0aba36ca..bd460f8d53e 100644 --- a/htdocs/core/lib/payments.lib.php +++ b/htdocs/core/lib/payments.lib.php @@ -1,6 +1,7 @@ + * Copyright (C) 2013 Marcos García + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -136,7 +137,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo else $out.='&securekey='.dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); } } - if ($type == 'order') + elseif ($type == 'order') { $out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=order&ref='.($mode?'':''); if ($mode == 1) $out.='order_ref'; @@ -154,7 +155,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo } } } - if ($type == 'invoice') + elseif ($type == 'invoice') { $out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=invoice&ref='.($mode?'':''); if ($mode == 1) $out.='invoice_ref'; @@ -172,7 +173,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo } } } - if ($type == 'contractline') + elseif ($type == 'contractline') { $out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=contractline&ref='.($mode?'':''); if ($mode == 1) $out.='contractline_ref'; @@ -190,7 +191,7 @@ function getOnlinePaymentUrl($mode, $type, $ref='', $amount='9.99', $freetag='yo } } } - if ($type == 'membersubscription') + elseif ($type == 'membersubscription') { $out=DOL_MAIN_URL_ROOT.'/public/payment/newpayment.php?source=membersubscription&ref='.($mode?'':''); if ($mode == 1) $out.='member_ref'; @@ -289,14 +290,14 @@ function htmlPrintOnlinePaymentFooter($fromcompany,$langs,$addformmessage=0,$suf $parammessageform='ONLINE_PAYMENT_MESSAGE_FORM_'.$suffix; if (! empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); - else if (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); + elseif (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORM)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORM); // Add other message if VAT exists if ($object->total_vat != 0 || $object->total_tva != 0) { $parammessageform='ONLINE_PAYMENT_MESSAGE_FORMIFVAT_'.$suffix; if (! empty($conf->global->$parammessageform)) print $langs->transnoentities($conf->global->$parammessageform); - else if (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); + elseif (! empty($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT)) print $langs->transnoentities($conf->global->ONLINE_PAYMENT_MESSAGE_FORMIFVAT); } } From af813f82145befb310c35973efac5ab97ff213ea Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sun, 14 Oct 2018 19:55:25 +0200 Subject: [PATCH 10/69] Fix missing status_batch var on product lists #9606 --- htdocs/product/index.php | 3 ++- htdocs/product/list.php | 1 + htdocs/product/reassortlot.php | 1 + htdocs/product/stock/productlot_list.php | 4 +++- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/htdocs/product/index.php b/htdocs/product/index.php index 6eebc4d85e2..b998bdc3148 100644 --- a/htdocs/product/index.php +++ b/htdocs/product/index.php @@ -273,7 +273,7 @@ print '
'; */ $max=15; $sql = "SELECT p.rowid, p.label, p.price, p.ref, p.fk_product_type, p.tosell, p.tobuy, p.fk_price_expression,"; -$sql.= " p.entity,"; +$sql.= " p.entity, p.tobatch,"; $sql.= " p.tms as datem"; $sql.= " FROM ".MAIN_DB_PREFIX."product as p"; $sql.= " WHERE p.entity IN (".getEntity($product_static->element, 1).")"; @@ -337,6 +337,7 @@ if ($result) $product_static->label = $objp->label; $product_static->type=$objp->fk_product_type; $product_static->entity = $objp->entity; + $product_static->status_batch = $objp->tobatch; print $product_static->getNomUrl(1,'',16); print "\n"; print '
'; diff --git a/htdocs/product/list.php b/htdocs/product/list.php index 178432addbc..071080edc58 100644 --- a/htdocs/product/list.php +++ b/htdocs/product/list.php @@ -700,6 +700,7 @@ else $product_static->status = $obj->tosell; $product_static->entity = $obj->entity; $product_static->pmp = $obj->pmp; + $product_static->status_batch = $obj->tobatch; if ((! empty($conf->stock->enabled) && $user->rights->stock->lire && $search_type != 1) || ! empty($conf->global->STOCK_DISABLE_OPTIM_LOAD)) // To optimize call of load_stock { diff --git a/htdocs/product/reassortlot.php b/htdocs/product/reassortlot.php index fc2632fe5e2..d737ecf8bb3 100644 --- a/htdocs/product/reassortlot.php +++ b/htdocs/product/reassortlot.php @@ -337,6 +337,7 @@ if ($resql) $product_static->label = $objp->label; $product_static->type=$objp->fk_product_type; $product_static->entity=$objp->entity; + $product_static->status_batch=$objp->tobatch; $product_lot_static->batch=$objp->batch; $product_lot_static->product_id=$objp->rowid; diff --git a/htdocs/product/stock/productlot_list.php b/htdocs/product/stock/productlot_list.php index 5934e8dff55..02260c8bf8b 100644 --- a/htdocs/product/stock/productlot_list.php +++ b/htdocs/product/stock/productlot_list.php @@ -216,7 +216,8 @@ $sql.= " t.fk_user_modif,"; $sql.= " t.import_key,"; $sql.= " p.fk_product_type as product_type,"; $sql.= " p.ref as product_ref,"; -$sql.= " p.label as product_label"; +$sql.= " p.label as product_label,"; +$sql.= " p.tobatch"; // Add fields for extrafields foreach ($extrafields->attribute_list as $key => $val) $sql.=",ef.".$key.' as options_'.$key; // Add fields from hooks @@ -430,6 +431,7 @@ if ($resql) $productstatic->type=$obj->product_type; $productstatic->ref=$obj->product_ref; $productstatic->label=$obj->product_label; + $productstatic->status_batch = $obj->tobatch; print ''; if (! $i) $totalarray['nbfield']++; } From 4d6d3afbea46a3873f37fd0972888c2a7c0f7cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 15 Oct 2018 08:39:46 +0200 Subject: [PATCH 11/69] code comment --- htdocs/accountancy/class/accountancycategory.class.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/accountancy/class/accountancycategory.class.php b/htdocs/accountancy/class/accountancycategory.class.php index a7bab16b30d..db148cbac67 100644 --- a/htdocs/accountancy/class/accountancycategory.class.php +++ b/htdocs/accountancy/class/accountancycategory.class.php @@ -1,6 +1,7 @@ * Copyright (C) 2016-2017 Alexandre Spangaro + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -539,9 +540,9 @@ class AccountancyCategory /** * get cpts of category * - * @param int $cat_id Id accounting account category + * @param int $cat_id Id accounting account category * - * @return array Result in table + * @return array|int Result in table or -1 if error */ public function getCptsCat($cat_id) { global $mysoc; From 06477b40a093f57a3e41d180f97604a7e4bb1b9e Mon Sep 17 00:00:00 2001 From: atm-greg Date: Mon, 15 Oct 2018 12:34:14 +0200 Subject: [PATCH 12/69] modify parenting before task deletion --- htdocs/core/actions_massactions.inc.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index 32d80bef672..b7bbc402b09 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -598,6 +598,17 @@ if (! $error && $massaction == 'delete' && $permtodelete) $result=$objecttmp->fetch($toselectid); if ($result > 0) { + if ($objectclass == "Task" && $objecttmp->hasChildren() > 0) { + $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET fk_task_parent = 0 WHERE fk_task_parent = ".$objecttmp->id; + $res = $db->query($sql); + + if (!$res) + { + setEventMessage('ErrorRecordParentingNotModified', 'errors'); + $error++; + } + } + if (in_array($objecttmp->element, array('societe','member'))) $result = $objecttmp->delete($objecttmp->id, $user, 1); else $result = $objecttmp->delete($user); if ($result <= 0) From dfe239bf8df84e079d938dd823890a02442133cd Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 15 Oct 2018 16:58:53 +0200 Subject: [PATCH 13/69] Fix refused proposals were counted in totals in project overview --- htdocs/projet/element.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 713e5ec74f1..130a0ad711e 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -609,6 +609,10 @@ foreach ($listofreferent as $key => $value) { if (! empty($element->close_code) && $element->close_code == 'replaced') $qualifiedfortotal=false; // Replacement invoice, do not include into total } + if ($key == 'propal') + { + if ($element->statut == Propal::STATUS_NOTSIGNED) $qualifiedfortotal=false; // Refused proposal must not be included in total + } if ($qualifiedfortotal) $total_ht = $total_ht + $total_ht_by_line; From 72dd182b1fed79a2fc8ad126c976e00b745a6a9c Mon Sep 17 00:00:00 2001 From: atm-ph Date: Tue, 16 Oct 2018 18:22:43 +0200 Subject: [PATCH 14/69] Fix list from 'Contacts/Addresses' on company may show duplicate value for extrafields --- htdocs/core/class/commonobject.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index b99c2f8ccd8..32a528c27dc 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4459,6 +4459,7 @@ abstract class CommonObject $resql=$this->db->query($sql); if ($resql) { + $this->array_options = array(); $numrows=$this->db->num_rows($resql); if ($numrows) { From 4e14c2817c5c8522aa11e1c742c3f485fe5d46dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 22:09:11 +0200 Subject: [PATCH 15/69] add errors def to form class --- htdocs/core/class/html.form.class.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index edcb68ca3a7..1cc02f0939a 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -58,6 +58,11 @@ class Form */ public $error=''; + /** + * @var string[] Array of error strings + */ + public $errors = array(); + public $num; // Cache arrays From 2d542d028f88e157ab909c26b59506e80920edc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 22:22:57 +0200 Subject: [PATCH 16/69] Update html.formmail.class.php --- htdocs/core/class/html.formmail.class.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index c80358315c6..f9e5c111878 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -44,6 +44,14 @@ class FormMail extends Form public $fromname; public $frommail; + /** + * @var string user, company, robot + */ + public $fromtype; + /** + * @var int ID + */ + public $fromid; public $replytoname; public $replytomail; public $toname; @@ -91,11 +99,6 @@ class FormMail extends Form public $withtouser=array(); public $withtoccuser=array(); - /** - * @var string Error code (or message) - */ - public $error=''; - public $lines_model; From cf1819ea0e05c7151953d6bdac87709f325f5be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 22:27:34 +0200 Subject: [PATCH 17/69] Update html.formmail.class.php --- htdocs/core/class/html.formmail.class.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index f9e5c111878..68da2dce777 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -4,6 +4,7 @@ * Copyright (C) 2010-2011 Juanjo Menent * Copyright (C) 2015-2017 Marcos García * Copyright (C) 2015-2017 Nicolas ZABOURI + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,15 +45,28 @@ class FormMail extends Form public $fromname; public $frommail; + /** * @var string user, company, robot */ public $fromtype; + /** * @var int ID */ public $fromid; - public $replytoname; + + /** + * @var string thirdparty etc + */ + public $totype; + + /** + * @var int ID + */ + public $toid; + + public $replytoname; public $replytomail; public $toname; public $tomail; From 2e77b9fed9ef745a24d133d346478bfcc86aacd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 22:42:18 +0200 Subject: [PATCH 18/69] fix phpunit --- htdocs/compta/paiement/class/paiement.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index cc60c2cba8e..50f7bc2c4e6 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -76,8 +76,8 @@ class Paiement extends CommonObject //paiement de llx_c_paiement public $num_paiement; // Numero du CHQ, VIR, etc... public $num_payment; // Numero du CHQ, VIR, etc... - public $payment_id; // Id of external modepayment - public $payment_site; // name of external modepayment + public $payment_id; // Id of external modepayment + public $payment_site; // name of external modepayment public $bank_account; // Id compte bancaire du paiement public $bank_line; // Id de la ligne d'ecriture bancaire // fk_paiement dans llx_paiement est l'id du type de paiement (7 pour CHQ, ...) @@ -233,11 +233,11 @@ class Paiement extends CommonObject $mtotal = $totalamount; } $note = ($this->note_public?$this->note_public:$this->note); - $payment_id = $this->payment_id ? $this->payment_id : null; - $payment_site = $this->payment_site ? $this->payment_site : null; + $payment_id = $this->payment_id ? $this->payment_id : null; + $payment_site = $this->payment_site ? $this->payment_site : null; $sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, ext_payment_id, ext_payment_site, fk_user_creat)"; - $sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', '".$this->payment_id."', '".$this->payment_site."', ".$user->id.")"; + $sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', '".$this->db->escape($payment_id)."', '".$this->db->escape($payment_site)."', ".$user->id.")"; dol_syslog(get_class($this)."::Create insert paiement", LOG_DEBUG); $resql = $this->db->query($sql); From fa78ab7c66336ce6283d3274685d68a3ddb61978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 23:20:13 +0200 Subject: [PATCH 19/69] do not trim int --- htdocs/contrat/class/contrat.class.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/htdocs/contrat/class/contrat.class.php b/htdocs/contrat/class/contrat.class.php index 398da806c2d..7e0c2d13ca5 100644 --- a/htdocs/contrat/class/contrat.class.php +++ b/htdocs/contrat/class/contrat.class.php @@ -10,6 +10,7 @@ * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2015-2017 Ferran Marcet * Copyright (C) 2018 Nicolas ZABOURI + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -2887,9 +2888,9 @@ class ContratLigne extends CommonObjectLine $error=0; // Clean parameters - $this->fk_contrat=trim($this->fk_contrat); - $this->fk_product=trim($this->fk_product); - $this->statut=(int) $this->statut; + $this->fk_contrat = (int) $this->fk_contrat; + $this->fk_product = (int) $this->fk_product; + $this->statut = (int) $this->statut; $this->label=trim($this->label); $this->description=trim($this->description); $this->vat_src_code=trim($this->vat_src_code); @@ -2899,7 +2900,7 @@ class ContratLigne extends CommonObjectLine $this->qty=trim($this->qty); $this->remise_percent=trim($this->remise_percent); $this->remise=trim($this->remise); - $this->fk_remise_except=trim($this->fk_remise_except); + $this->fk_remise_except = (int) $this->fk_remise_except; $this->subprice=price2num($this->subprice); $this->price_ht=price2num($this->price_ht); $this->total_ht=trim($this->total_ht); @@ -2908,9 +2909,9 @@ class ContratLigne extends CommonObjectLine $this->total_localtax2=trim($this->total_localtax2); $this->total_ttc=trim($this->total_ttc); $this->info_bits=trim($this->info_bits); - $this->fk_user_author=trim($this->fk_user_author); - $this->fk_user_ouverture=trim($this->fk_user_ouverture); - $this->fk_user_cloture=trim($this->fk_user_cloture); + $this->fk_user_author = (int) $this->fk_user_author; + $this->fk_user_ouverture = (int) $this->fk_user_ouverture; + $this->fk_user_cloture = (int) $this->fk_user_cloture; $this->commentaire=trim($this->commentaire); //if (empty($this->subprice)) $this->subprice = 0; if (empty($this->price_ht)) $this->price_ht = 0; From 27b7cf8beaa34985efc3c193504a9d9c0a16a3d0 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Tue, 16 Oct 2018 23:31:19 +0200 Subject: [PATCH 20/69] Fix uniformization dates of order in API --- htdocs/commande/class/commande.class.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index c588830d83d..7f2a8c98dbe 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -155,7 +155,10 @@ class Commande extends CommonOrder public $demand_reason_id; // Source reason. Why we receive order (after a phone campaign, ...) public $demand_reason_code; public $date; // Date commande - + public $date_creation; // Date commande + public $date_validation; // Date commande + public $date_modification; // Date commande + /** * @deprecated * @see date @@ -1620,7 +1623,7 @@ class Commande extends CommonOrder $sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut'; $sql.= ', c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason'; $sql.= ', c.fk_account'; - $sql.= ', c.date_commande'; + $sql.= ', c.date_commande, c.date_valid, c.tms'; $sql.= ', c.date_livraison'; $sql.= ', c.fk_shipping_method'; $sql.= ', c.fk_warehouse'; @@ -1673,6 +1676,9 @@ class Commande extends CommonOrder $this->total_ttc = $obj->total_ttc; $this->date = $this->db->jdate($obj->date_commande); $this->date_commande = $this->db->jdate($obj->date_commande); + $this->date_creation = $this->db->jdate($obj->date_creation); + $this->date_validation = $this->db->jdate($obj->date_valid); + $this->date_modification = $this->db->jdate($obj->tms); $this->remise = $obj->remise; $this->remise_percent = $obj->remise_percent; $this->remise_absolue = $obj->remise_absolue; From 70b6c502dab209a0db427df3e0132e7d1f975a3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Tue, 16 Oct 2018 23:36:00 +0200 Subject: [PATCH 21/69] Update menubase.class.php --- htdocs/core/class/menubase.class.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/htdocs/core/class/menubase.class.php b/htdocs/core/class/menubase.class.php index 0daf4fe56da..17ada096fd1 100644 --- a/htdocs/core/class/menubase.class.php +++ b/htdocs/core/class/menubase.class.php @@ -1,6 +1,7 @@ * Copyright (C) 2009-2012 Regis Houssin + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,15 +60,18 @@ class Menubase public $fk_menu; /** - * @var int ID + * @var string fk_mainmenu */ public $fk_mainmenu; /** - * @var int ID + * @var string fk_leftmenu */ public $fk_leftmenu; + /** + * @var int position + */ public $position; public $url; public $target; @@ -111,10 +115,10 @@ class Menubase $this->type=trim($this->type); $this->mainmenu=trim($this->mainmenu); $this->leftmenu=trim($this->leftmenu); - $this->fk_menu=trim($this->fk_menu); // If -1, fk_mainmenu and fk_leftmenu must be defined + $this->fk_menu = (int) $this->fk_menu; // If -1, fk_mainmenu and fk_leftmenu must be defined $this->fk_mainmenu=trim($this->fk_mainmenu); $this->fk_leftmenu=trim($this->fk_leftmenu); - $this->position=trim($this->position); + $this->position = (int) $this->position; $this->url=trim($this->url); $this->target=trim($this->target); $this->titre=trim($this->titre); @@ -155,7 +159,7 @@ class Menubase $sql = "SELECT count(*)"; $sql.= " FROM ".MAIN_DB_PREFIX."menu"; $sql.= " WHERE menu_handler = '".$this->db->escape($this->menu_handler)."'"; - $sql.= " AND fk_menu = ".((int) $this->db->escape($this->fk_menu)); + $sql.= " AND fk_menu = ".((int) $this->fk_menu); $sql.= " AND position = ".((int) $this->position); $sql.= " AND url = '".$this->db->escape($this->url)."'"; $sql.= " AND entity = ".$conf->entity; @@ -252,10 +256,10 @@ class Menubase $this->type=trim($this->type); $this->mainmenu=trim($this->mainmenu); $this->leftmenu=trim($this->leftmenu); - $this->fk_menu=trim($this->fk_menu); + $this->fk_menu = (int) $this->fk_menu; $this->fk_mainmenu=trim($this->fk_mainmenu); $this->fk_leftmenu=trim($this->fk_leftmenu); - $this->position=trim($this->position); + $this->position = (int) $this->position; $this->url=trim($this->url); $this->target=trim($this->target); $this->titre=trim($this->titre); @@ -274,7 +278,7 @@ class Menubase $sql.= " type='".$this->db->escape($this->type)."',"; $sql.= " mainmenu='".$this->db->escape($this->mainmenu)."',"; $sql.= " leftmenu='".$this->db->escape($this->leftmenu)."',"; - $sql.= " fk_menu='".$this->db->escape($this->fk_menu)."',"; + $sql.= " fk_menu=".$this->fk_menu.","; $sql.= " fk_mainmenu=".($this->fk_mainmenu?"'".$this->db->escape($this->fk_mainmenu)."'":"null").","; $sql.= " fk_leftmenu=".($this->fk_leftmenu?"'".$this->db->escape($this->fk_leftmenu)."'":"null").","; $sql.= " position=".($this->position > 0 ? $this->position : 0).","; From 3fdf3c95b449c8ef89454709089fc07dd387affb Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Wed, 17 Oct 2018 00:04:44 +0200 Subject: [PATCH 22/69] FIX harmony in date name with API --- htdocs/compta/facture/class/facture.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index e225d1468c4..d614447b189 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -112,6 +112,7 @@ class Facture extends CommonInvoice public $date; // Date invoice public $date_creation; // Creation date public $date_validation; // Validation date + public $date_modification; // Validation date public $datem; public $ref_client; public $ref_int; @@ -1361,6 +1362,7 @@ class Facture extends CommonInvoice $this->date_pointoftax = $this->db->jdate($obj->date_pointoftax); $this->date_creation = $this->db->jdate($obj->datec); $this->date_validation = $this->db->jdate($obj->datev); + $this->date_modification = $this->db->jdate($obj->datem); $this->datem = $this->db->jdate($obj->datem); $this->remise_percent = $obj->remise_percent; $this->remise_absolue = $obj->remise_absolue; From 7c35eae2026ac0eb96e1ed6f11acf71cf2981936 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Wed, 17 Oct 2018 00:06:24 +0200 Subject: [PATCH 23/69] Update commande.class.php --- htdocs/commande/class/commande.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/commande/class/commande.class.php b/htdocs/commande/class/commande.class.php index 7f2a8c98dbe..4f5051f3411 100644 --- a/htdocs/commande/class/commande.class.php +++ b/htdocs/commande/class/commande.class.php @@ -155,9 +155,9 @@ class Commande extends CommonOrder public $demand_reason_id; // Source reason. Why we receive order (after a phone campaign, ...) public $demand_reason_code; public $date; // Date commande - public $date_creation; // Date commande - public $date_validation; // Date commande - public $date_modification; // Date commande + public $date_creation; // Date commande + public $date_validation; // Date commande + public $date_modification; // Date commande /** * @deprecated @@ -1676,9 +1676,9 @@ class Commande extends CommonOrder $this->total_ttc = $obj->total_ttc; $this->date = $this->db->jdate($obj->date_commande); $this->date_commande = $this->db->jdate($obj->date_commande); - $this->date_creation = $this->db->jdate($obj->date_creation); - $this->date_validation = $this->db->jdate($obj->date_valid); - $this->date_modification = $this->db->jdate($obj->tms); + $this->date_creation = $this->db->jdate($obj->date_creation); + $this->date_validation = $this->db->jdate($obj->date_valid); + $this->date_modification = $this->db->jdate($obj->tms); $this->remise = $obj->remise; $this->remise_percent = $obj->remise_percent; $this->remise_absolue = $obj->remise_absolue; From a77458cb36703ef4c7bb21993981a324c4dba6d7 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Wed, 17 Oct 2018 00:07:21 +0200 Subject: [PATCH 24/69] Update facture.class.php --- htdocs/compta/facture/class/facture.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index d614447b189..3f36cb72830 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -112,7 +112,7 @@ class Facture extends CommonInvoice public $date; // Date invoice public $date_creation; // Creation date public $date_validation; // Validation date - public $date_modification; // Validation date + public $date_modification; // Validation date public $datem; public $ref_client; public $ref_int; @@ -1362,7 +1362,7 @@ class Facture extends CommonInvoice $this->date_pointoftax = $this->db->jdate($obj->date_pointoftax); $this->date_creation = $this->db->jdate($obj->datec); $this->date_validation = $this->db->jdate($obj->datev); - $this->date_modification = $this->db->jdate($obj->datem); + $this->date_modification = $this->db->jdate($obj->datem); $this->datem = $this->db->jdate($obj->datem); $this->remise_percent = $obj->remise_percent; $this->remise_absolue = $obj->remise_absolue; From f2d0004a3e542afb3f520dccc9b0bf7eb9515821 Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Wed, 17 Oct 2018 00:36:40 +0200 Subject: [PATCH 25/69] ADD civility list in API --- htdocs/api/class/api_setup.class.php | 60 ++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 3ec618dc92a..304abf46432 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -380,6 +380,66 @@ class Setup extends DolibarrApi return $list; } + /** + * Get the list of civility. + * + * @param string $sortfield Sort field + * @param string $sortorder Sort order + * @param int $limit Number of items per page + * @param int $page Page number (starting from zero) + * @param string $module To filter on module events + * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)" + * @return List of events types + * + * @url GET dictionary/civility + * + * @throws RestException + */ + function getListOfCivility($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $sqlfilters = '') + { + $list = array(); + + $sql = "SELECT rowid, code, label, module"; + $sql.= " FROM ".MAIN_DB_PREFIX."c_civility as t"; + $sql.= " WHERE t.active = 1"; + if ($module) $sql.=" AND t.module LIKE '%" . $this->db->escape($module) . "%'"; + // Add sql filters + if ($sqlfilters) + { + if (! DolibarrApi::_checkFilters($sqlfilters)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + } + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; + } + + + $sql.= $this->db->order($sortfield, $sortorder); + + if ($limit) { + if ($page < 0) { + $page = 0; + } + $offset = $limit * $page; + + $sql .= $this->db->plimit($limit, $offset); + } + + $result = $this->db->query($sql); + + if ($result) { + $num = $this->db->num_rows($result); + $min = min($num, ($limit <= 0 ? $num : $limit)); + for ($i = 0; $i < $min; $i++) { + $list[] = $this->db->fetch_object($result); + } + } else { + throw new RestException(503, 'Error when retrieving list of civility : '.$this->db->lasterror()); + } + + return $list; + } /** * Get the list of extra fields. From a466104b810db2caae6055dc034701bbbafcb66f Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 17 Oct 2018 07:20:04 +0200 Subject: [PATCH 26/69] Fix FEC on transaction card Fix for FEC compliance - Remove useless column label_compte - label_compte is generated with label of accounting account number - Insert also the label of the journal --- htdocs/accountancy/bookkeeping/card.php | 61 ++++++++++++++----------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index a8ff1e13338..09a3b7ef8f5 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -1,8 +1,8 @@ - * Copyright (C) 2013-2017 Florian Henry - * Copyright (C) 2013-2018 Alexandre Spangaro - * Copyright (C) 2017 Laurent Destailleur +/* Copyright (C) 2013-2017 Olivier Geffroy + * Copyright (C) 2013-2017 Florian Henry + * Copyright (C) 2013-2018 Alexandre Spangaro + * Copyright (C) 2017 Laurent Destailleur * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify @@ -32,6 +32,7 @@ require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php'; require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php'; +require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingaccount.class.php'; // Load translation files required by the page $langs->loadLangs(array("accountancy", "bills", "compta")); @@ -49,12 +50,21 @@ if ($user->societe_id > 0) { $mesg = ''; -$account_number = GETPOST('account_number','alphanohtml'); +$accountingaccount = new AccountingAccount($db); +$accountingjournal = new AccountingJournal($db); + +$accountingaccount_number = GETPOST('accountingaccount_number','alphanohtml'); +$accountingaccount->fetch(null, $accountingaccount_number, true); +$accountingaccount_label = $accountingaccount->label; + +$journal_code = GETPOST('code_journal','alpha'); +$accountingjournal->fetch(null, $journal_code); +$journal_label = $accountingjournal->label; + $subledger_account = GETPOST('subledger_account','alphanohtml'); if ($subledger_account == - 1) { $subledger_account = null; } -$label_compte = GETPOST('label_compte','alphanohtml'); $label_operation= GETPOST('label_operation','alphanohtml'); $debit = price2num(GETPOST('debit','alpha')); $credit = price2num(GETPOST('credit','alpha')); @@ -80,7 +90,7 @@ if ($action == "confirm_update") { setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors'); $action='update'; } - if (empty($account_number) || $account_number == '-1') + if (empty($accountingaccount_number) || $accountingaccount_number == '-1') { $error++; setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors'); @@ -96,9 +106,9 @@ if ($action == "confirm_update") { $error++; setEventMessages($object->error, $object->errors, 'errors'); } else { - $object->numero_compte = $account_number; + $object->numero_compte = $accountingaccount_number; $object->subledger_account = $subledger_account; - $object->label_compte = $label_compte; + $object->label_compte = $accountingaccount_label; $object->label_operation= $label_operation; $object->debit = $debit; $object->credit = $credit; @@ -139,7 +149,7 @@ else if ($action == "add") { setEventMessages($langs->trans('ErrorDebitCredit'), null, 'errors'); $action=''; } - if (empty($account_number) || $account_number == '-1') + if (empty($accountingaccount_number) || $accountingaccount_number == '-1') { $error++; setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("AccountAccountingShort")), null, 'errors'); @@ -149,9 +159,9 @@ else if ($action == "add") { if (! $error) { $object = new BookKeeping($db); - $object->numero_compte = $account_number; + $object->numero_compte = $accountingaccount_number; $object->subledger_account = $subledger_account; - $object->label_compte = $label_compte; + $object->label_compte = $accountingaccount_label; $object->label_operation= $label_operation; $object->debit = $debit; $object->credit = $credit; @@ -159,7 +169,8 @@ else if ($action == "add") { $object->doc_type = GETPOST('doc_type','alpha'); $object->piece_num = $piece_num; $object->doc_ref = GETPOST('doc_ref','alpha'); - $object->code_journal = GETPOST('code_journal','alpha'); + $object->code_journal = $journal_code; + $object->journal_label = $journal_label; $object->fk_doc = GETPOST('fk_doc','alpha'); $object->fk_docdet = GETPOST('fk_docdet','alpha'); @@ -212,7 +223,7 @@ else if ($action == "confirm_create") { $object = new BookKeeping($db); - if (! GETPOST('code_journal','alpha') || GETPOST('code_journal','alpha') == '-1') { + if (! $journal_code || $journal_code == '-1') { setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentitiesnoconv("Journal")), null, 'errors'); $action='create'; $error++; @@ -232,7 +243,8 @@ else if ($action == "confirm_create") { $object->doc_type = GETPOST('doc_type','alpha'); $object->piece_num = GETPOST('next_num_mvt','alpha'); $object->doc_ref = GETPOST('doc_ref','alpha'); - $object->code_journal = GETPOST('code_journal','alpha'); + $object->code_journal = $journal_code; + $object->journal_label = $journal_label; $object->fk_doc = 0; $object->fk_docdet = 0; $object->montant = 0; @@ -267,8 +279,8 @@ if ($action == 'setdate') { } if ($action == 'setjournal') { - $journaldoc = trim(GETPOST('code_journal','alpha')); - $result = $object->updateByMvt($piece_num, 'code_journal', $journaldoc, $mode); + $result = $object->updateByMvt($piece_num, 'code_journal', $journal_code, $mode); + $result = $object->updateByMvt($piece_num, 'journal_label', $journal_label, $mode); if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } else { @@ -312,7 +324,6 @@ if ($action == 'valid') { $html = new Form($db); $formaccounting = new FormAccounting($db); -$accountjournal = new AccountingJournal($db); llxHeader('', $langs->trans("CreateMvts")); @@ -357,7 +368,7 @@ if ($action == 'create') print ''; print ''; - print ''; + print ''; print ''; print ''; @@ -460,7 +471,7 @@ if ($action == 'create') print ''; print ''; } else { - print $object->code_journal ; + print $object->code_journal ; } print ''; print ''; @@ -590,7 +601,6 @@ if ($action == 'create') print_liste_field_titre("AccountAccountingShort"); print_liste_field_titre("SubledgerAccount"); - print_liste_field_titre("LabelAccount"); print_liste_field_titre("LabelOperation"); print_liste_field_titre("Debit", "", "", "", "", 'align="right"'); print_liste_field_titre("Credit", "", "", "", "", 'align="right"'); @@ -605,7 +615,7 @@ if ($action == 'create') if ($action == 'update' && $line->id == $id) { print ''; print ''; } else { - print ''; + $accountingaccount->fetch(null, $line->numero_compte, true); + print ''; print ''; - print ''; print ''; print ''; print ''; @@ -663,7 +673,7 @@ if ($action == 'create') if ($action == "" || $action == 'add') { print ''; print ''; print ''; - print ''; print ''; print ''; print ''; From 7d8ff0429251f4860ca70c8aa5226e8266a4e0e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 08:15:12 +0200 Subject: [PATCH 27/69] Update paiement.class.php --- htdocs/compta/paiement/class/paiement.class.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index 50f7bc2c4e6..4fdc4a0ae63 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -138,8 +138,8 @@ class Paiement extends CommonObject $this->type_libelle = $obj->type_libelle; $this->type_code = $obj->type_code; $this->statut = $obj->statut; - $this->payment_id = $obj->ext_payment_id; - $this->payment_site = $obj->ext_payment_site; + $this->payment_id = $obj->ext_payment_id; + $this->payment_site = $obj->ext_payment_site; $this->bank_account = $obj->fk_account; // deprecated $this->fk_account = $obj->fk_account; @@ -233,11 +233,9 @@ class Paiement extends CommonObject $mtotal = $totalamount; } $note = ($this->note_public?$this->note_public:$this->note); - $payment_id = $this->payment_id ? $this->payment_id : null; - $payment_site = $this->payment_site ? $this->payment_site : null; $sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, ext_payment_id, ext_payment_site, fk_user_creat)"; - $sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', '".$this->db->escape($payment_id)."', '".$this->db->escape($payment_site)."', ".$user->id.")"; + $sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', ".($this->payment_id?"'".$this->db->escape($this->payment_id)."'":"null").", ".($this->payment_site?"'".$this->db->escape($this->payment_site)."'":"null").", ".$user->id.")"; dol_syslog(get_class($this)."::Create insert paiement", LOG_DEBUG); $resql = $this->db->query($sql); From b462e7b2170e7de3114a4e12548f1f89ae17c2ca Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Wed, 17 Oct 2018 10:01:02 +0200 Subject: [PATCH 28/69] FIX When delete a product, llx_product_association rows are not deleted --- htdocs/product/class/product.class.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index f33029d368a..56227bc5266 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -12,7 +12,7 @@ * Copyright (C) 2014 Henry Florian * Copyright (C) 2014-2016 Philippe Grand * Copyright (C) 2014 Ion agorria - * Copyright (C) 2016-2017 Ferran Marcet + * Copyright (C) 2016-2018 Ferran Marcet * Copyright (C) 2017 Gustavo Novaro * * This program is free software; you can redistribute it and/or modify @@ -1114,6 +1114,19 @@ class Product extends CommonObject } } + // Delete from product_association + if (!$error){ + $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_association"; + $sql.= " WHERE fk_product_pere = ".$this->rowid." OR fk_product_fils = ".$this->rowid; + dol_syslog(get_class($this).'::delete', LOG_DEBUG); + $result = $this->db->query($sql); + if (! $result) + { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } + // Delete product if (! $error) { From bdae4e1c4dae0369ef3d0051cf5e8c53572bf7c3 Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Wed, 17 Oct 2018 10:04:42 +0200 Subject: [PATCH 29/69] FIX When delete a product, llx_product_association rows are not deleted --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 56227bc5266..9a52722a3c9 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1117,7 +1117,7 @@ class Product extends CommonObject // Delete from product_association if (!$error){ $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_association"; - $sql.= " WHERE fk_product_pere = ".$this->rowid." OR fk_product_fils = ".$this->rowid; + $sql.= " WHERE fk_product_pere = ".$this->id." OR fk_product_fils = ".$this->id; dol_syslog(get_class($this).'::delete', LOG_DEBUG); $result = $this->db->query($sql); if (! $result) From ffde3534419f28f37f57028405074b7b3a7fb5c2 Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Wed, 17 Oct 2018 10:06:06 +0200 Subject: [PATCH 30/69] FIX When delete a product, llx_product_association rows are not deleted --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 9a52722a3c9..ce3658c9a72 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -1117,7 +1117,7 @@ class Product extends CommonObject // Delete from product_association if (!$error){ $sql = "DELETE FROM ".MAIN_DB_PREFIX."product_association"; - $sql.= " WHERE fk_product_pere = ".$this->id." OR fk_product_fils = ".$this->id; + $sql.= " WHERE fk_product_pere = ".$id." OR fk_product_fils = ".$id; dol_syslog(get_class($this).'::delete', LOG_DEBUG); $result = $this->db->query($sql); if (! $result) From a66256a799468bd5813838ffcb498934070b5020 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 17 Oct 2018 13:22:52 +0200 Subject: [PATCH 31/69] FIX Hover on the filemanager --- htdocs/core/class/html.formfile.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 4a59e28f044..d47b846ba02 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1162,7 +1162,7 @@ class FormFile print ''."\n"; // Do we have entry into database ? print ''."\n"; - print ''; + print ''; // File name print ''; print ''; +// Disable Prospect/Customer thirdparty type +print ''; +print ''; +print ''; +print ''; +print ''; + /*print ''; print ''; print ''; From 456bdb5b8c6020480899165f4cbb34ee8ce40fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 20:04:48 +0200 Subject: [PATCH 34/69] do not trim int --- htdocs/ticket/class/ticketlogs.class.php | 33 ++++++++++++------------ 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/htdocs/ticket/class/ticketlogs.class.php b/htdocs/ticket/class/ticketlogs.class.php index 79a4c95efed..68ce6481b31 100644 --- a/htdocs/ticket/class/ticketlogs.class.php +++ b/htdocs/ticket/class/ticketlogs.class.php @@ -1,5 +1,6 @@ +/* Copyright (C) 2013-2016 Jean-François FERRY + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -63,12 +64,12 @@ class Ticketlogs// extends CommonObject public $id; /** - * @var int ID + * @var string trackid */ public $fk_track_id; /** - * @var int ID + * @var int user create ID */ public $fk_user_create; @@ -104,7 +105,7 @@ class Ticketlogs// extends CommonObject } if (isset($this->fk_user_create)) { - $this->fk_user_create = trim($this->fk_user_create); + $this->fk_user_create = (int) $this->fk_user_create; } if (isset($this->message)) { @@ -143,7 +144,7 @@ class Ticketlogs// extends CommonObject if (!$error) { $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX . "ticket_logs"); - if (!$notrigger) { + //if (!$notrigger) { // Uncomment this and change MYOBJECT to your own tag if you // want this action calls a trigger. @@ -153,7 +154,7 @@ class Ticketlogs// extends CommonObject //$result=$interface->run_triggers('MYOBJECT_CREATE',$this,$user,$langs,$conf); //if ($result < 0) { $error++; $this->errors=$interface->errors; } //// End call triggers - } + //} } // Commit or rollback @@ -232,7 +233,7 @@ class Ticketlogs// extends CommonObject } if (isset($this->fk_user_create)) { - $this->fk_user_create = trim($this->fk_user_create); + $this->fk_user_create = (int) $this->fk_user_create; } if (isset($this->message)) { @@ -261,8 +262,8 @@ class Ticketlogs// extends CommonObject $this->errors[] = "Error " . $this->db->lasterror(); } - if (!$error) { - if (!$notrigger) { + //if (!$error) { + //if (!$notrigger) { // Uncomment this and change MYOBJECT to your own tag if you // want this action calls a trigger. @@ -272,8 +273,8 @@ class Ticketlogs// extends CommonObject //$result=$interface->run_triggers('MYOBJECT_MODIFY',$this,$user,$langs,$conf); //if ($result < 0) { $error++; $this->errors=$interface->errors; } //// End call triggers - } - } + //} + //} // Commit or rollback if ($error) { @@ -303,8 +304,8 @@ class Ticketlogs// extends CommonObject $this->db->begin(); - if (!$error) { - if (!$notrigger) { + //if (!$error) { + //if (!$notrigger) { // Uncomment this and change MYOBJECT to your own tag if you // want this action calls a trigger. @@ -314,8 +315,8 @@ class Ticketlogs// extends CommonObject //$result=$interface->run_triggers('MYOBJECT_DELETE',$this,$user,$langs,$conf); //if ($result < 0) { $error++; $this->errors=$interface->errors; } //// End call triggers - } - } + //} + //} if (!$error) { $sql = "DELETE FROM " . MAIN_DB_PREFIX . "ticket_logs"; @@ -354,7 +355,7 @@ class Ticketlogs// extends CommonObject $this->id = 0; $this->fk_track_id = ''; - $this->fk_user_create = ''; + $this->fk_user_create = 1; $this->datec = ''; $this->message = ''; } From 47048baa36fbf642a23cb5c4c63cbcdf3da657ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 20:14:01 +0200 Subject: [PATCH 35/69] do not trim int --- htdocs/projet/class/task.class.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 84829bf85cb..a4ef7965851 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -2,6 +2,7 @@ /* Copyright (C) 2008-2014 Laurent Destailleur * Copyright (C) 2010-2012 Regis Houssin * Copyright (C) 2014 Marcos García + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -340,7 +341,7 @@ class Task extends CommonObject // Clean parameters if (isset($this->fk_project)) $this->fk_project=trim($this->fk_project); if (isset($this->ref)) $this->ref=trim($this->ref); - if (isset($this->fk_task_parent)) $this->fk_task_parent=trim($this->fk_task_parent); + if (isset($this->fk_task_parent)) $this->fk_task_parent = (int) $this->fk_task_parent; if (isset($this->label)) $this->label=trim($this->label); if (isset($this->description)) $this->description=trim($this->description); if (isset($this->duration_effective)) $this->duration_effective=trim($this->duration_effective); @@ -705,12 +706,12 @@ class Task extends CommonObject $this->fk_projet=''; $this->ref='TK01'; - $this->fk_task_parent=''; + $this->fk_task_parent=null; $this->label='Specimen task TK01'; $this->duration_effective=''; - $this->fk_user_creat=''; + $this->fk_user_creat=null; $this->progress='25'; - $this->fk_statut=''; + $this->fk_statut=null; $this->note='This is a specimen task not'; } @@ -1999,4 +2000,4 @@ class Task extends CommonObject return ($datetouse > 0 && ($datetouse < ($now - $conf->projet->task->warning_delay))); } -} \ No newline at end of file +} From 393303fe31d816cf8c0f4e8d0b79a08fa9d97b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 20:17:43 +0200 Subject: [PATCH 36/69] do not trim int --- .../stock/class/productstockentrepot.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/product/stock/class/productstockentrepot.class.php b/htdocs/product/stock/class/productstockentrepot.class.php index 6b12af88c7a..740afcb5f04 100644 --- a/htdocs/product/stock/class/productstockentrepot.class.php +++ b/htdocs/product/stock/class/productstockentrepot.class.php @@ -93,8 +93,8 @@ class ProductStockEntrepot extends CommonObject // Clean parameters - if (isset($this->fk_product)) $this->fk_product = trim($this->fk_product); - if (isset($this->fk_entrepot)) $this->fk_entrepot = trim($this->fk_entrepot); + if (isset($this->fk_product)) $this->fk_product = (int) $this->fk_product; + if (isset($this->fk_entrepot)) $this->fk_entrepot = (int) $this->fk_entrepot; if (isset($this->seuil_stock_alerte)) $this->seuil_stock_alerte = trim($this->seuil_stock_alerte); if (isset($this->desiredstock)) $this->desiredstock = trim($this->desiredstock); if (isset($this->import_key)) $this->import_key = trim($this->import_key); @@ -317,8 +317,8 @@ class ProductStockEntrepot extends CommonObject // Clean parameters - if (isset($this->fk_product)) $this->fk_product = trim($this->fk_product); - if (isset($this->fk_entrepot)) $this->fk_entrepot = trim($this->fk_entrepot); + if (isset($this->fk_product)) $this->fk_product = (int) $this->fk_product; + if (isset($this->fk_entrepot)) $this->fk_entrepot = (int) $this->fk_entrepot; if (isset($this->seuil_stock_alerte)) $this->seuil_stock_alerte = trim($this->seuil_stock_alerte); if (isset($this->desiredstock)) $this->desiredstock = trim($this->desiredstock); if (isset($this->import_key)) $this->import_key = trim($this->import_key); @@ -575,8 +575,8 @@ class ProductStockEntrepot extends CommonObject $this->id = 0; $this->tms = ''; - $this->fk_product = ''; - $this->fk_entrepot = ''; + $this->fk_product = null; + $this->fk_entrepot = null; $this->seuil_stock_alerte = ''; $this->desiredstock = ''; $this->import_key = ''; From ebc5cb5a96d2e99de95202a6cadb8ed5561e5495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 20:24:43 +0200 Subject: [PATCH 37/69] do not trim int --- .../product/stock/class/productlot.class.php | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/htdocs/product/stock/class/productlot.class.php b/htdocs/product/stock/class/productlot.class.php index 1530e068856..d61630eb88e 100644 --- a/htdocs/product/stock/class/productlot.class.php +++ b/htdocs/product/stock/class/productlot.class.php @@ -3,7 +3,7 @@ * Copyright (C) 2014 Juanjo Menent * Copyright (C) 2015 Florian Henry * Copyright (C) 2015 Raphaël Doursenaud - * Copyright (C) ---Put here your own copyright and developer email--- + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -115,19 +115,19 @@ class Productlot extends CommonObject // Clean parameters if (isset($this->entity)) { - $this->entity = trim($this->entity); + $this->entity = (int) $this->entity; } if (isset($this->fk_product)) { - $this->fk_product = trim($this->fk_product); + $this->fk_product = (int) $this->fk_product; } if (isset($this->batch)) { $this->batch = trim($this->batch); } if (isset($this->fk_user_creat)) { - $this->fk_user_creat = trim($this->fk_user_creat); + $this->fk_user_creat = (int) $this->fk_user_creat; } if (isset($this->fk_user_modif)) { - $this->fk_user_modif = trim($this->fk_user_modif); + $this->fk_user_modif = (int) $this->fk_user_modif; } if (isset($this->import_key)) { $this->import_key = trim($this->import_key); @@ -296,19 +296,19 @@ class Productlot extends CommonObject // Clean parameters if (isset($this->entity)) { - $this->entity = trim($this->entity); + $this->entity = (int) $this->entity; } if (isset($this->fk_product)) { - $this->fk_product = trim($this->fk_product); + $this->fk_product = (int) $this->fk_product; } if (isset($this->batch)) { $this->batch = trim($this->batch); } if (isset($this->fk_user_creat)) { - $this->fk_user_creat = trim($this->fk_user_creat); + $this->fk_user_creat = (int) $this->fk_user_creat; } if (isset($this->fk_user_modif)) { - $this->fk_user_modif = trim($this->fk_user_modif); + $this->fk_user_modif = (int) $this->fk_user_modif; } if (isset($this->import_key)) { $this->import_key = trim($this->import_key); @@ -358,9 +358,6 @@ class Productlot extends CommonObject } if (!$error && !$notrigger) { - // Uncomment this and change MYOBJECT to your own tag if you - // want this action calls a trigger. - // Call triggers $result=$this->call_trigger('PRODUCTLOT_MODIFY',$user); if ($result < 0) { $error++; } @@ -395,8 +392,8 @@ class Productlot extends CommonObject $this->db->begin(); - if (!$error) { - if (!$notrigger) { + //if (!$error) { + //if (!$notrigger) { // Uncomment this and change MYOBJECT to your own tag if you // want this action calls a trigger. @@ -404,8 +401,8 @@ class Productlot extends CommonObject //$result=$this->call_trigger('MYOBJECT_DELETE',$user); //if ($result < 0) { $error++; //Do also what you must do to rollback action if trigger fail} //// End call triggers - } - } + //} + //} if (!$error) { $sql = 'DELETE FROM ' . MAIN_DB_PREFIX . $this->table_element; @@ -587,15 +584,15 @@ class Productlot extends CommonObject { $this->id = 0; - $this->entity = ''; - $this->fk_product = ''; + $this->entity = null; + $this->fk_product = null; $this->batch = ''; $this->eatby = ''; $this->sellby = ''; $this->datec = ''; $this->tms = ''; - $this->fk_user_creat = ''; - $this->fk_user_modif = ''; + $this->fk_user_creat = null; + $this->fk_user_modif = null; $this->import_key = ''; } } From db732ddeddcfd3c6ae4d6ea56f5790eeb690d42e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Wed, 17 Oct 2018 20:36:45 +0200 Subject: [PATCH 38/69] code comment --- htdocs/categories/class/categorie.class.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/categories/class/categorie.class.php b/htdocs/categories/class/categorie.class.php index 15cb254ed7d..a9432234793 100644 --- a/htdocs/categories/class/categorie.class.php +++ b/htdocs/categories/class/categorie.class.php @@ -10,6 +10,7 @@ * Copyright (C) 2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud * Copyright (C) 2016 Charlie Benke + * Copyright (C) 2018 Frédéric France * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -805,7 +806,7 @@ class Categorie extends CommonObject * @param string $sortorder Sort order * @param int $limit Limit for list * @param int $page Page number - * @return array Array of categories + * @return array|int Array of categories, 0 if no cat, -1 on error */ function getListForItem($id, $type='customer', $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) { @@ -974,7 +975,7 @@ class Categorie extends CommonObject * @param string $type Type of categories ('customer', 'supplier', 'contact', 'product', 'member') or (0, 1, 2, ...). * @param int $markafterid Removed all categories including the leaf $markafterid in category tree. * - * @return array Array of categories. this->cats and this->motherof are set. + * @return array|int Array of categories. this->cats and this->motherof are set, -1 on error */ function get_full_arbo($type, $markafterid=0) { @@ -1126,7 +1127,7 @@ class Categorie extends CommonObject * * @param int $type Type of category (0, 1, ...) * @param boolean $parent Just parent categories if true - * @return array Table of Object Category + * @return array|int Table of Object Category, -1 on error */ function get_all_categories($type=null, $parent=false) { @@ -1441,7 +1442,7 @@ class Categorie extends CommonObject * @param string $type Type of category ('member', 'customer', 'supplier', 'product', 'contact'). Old mode (0, 1, 2, ...) is deprecated. * @param boolean $exact Exact string search (true/false) * @param boolean $case Case sensitive (true/false) - * @return array Array of category id + * @return array|int Array of category id, -1 if error */ function rechercher($id, $nom, $type, $exact = false, $case = false) { From 52840478c02599701eb4b8b92ea85a4aaf693510 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 17 Oct 2018 21:11:07 +0200 Subject: [PATCH 39/69] Clean code --- htdocs/core/class/CMailFile.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 7562cd609c2..ef8d07dfb45 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -569,7 +569,8 @@ class CMailFile $keyforstarttls ='MAIN_MAIL_EMAIL_STARTTLS_EMAILING'; } - if(!empty($conf->global->MAIN_MAIL_FORCE_SENDTO)) { + if (!empty($conf->global->MAIN_MAIL_FORCE_SENDTO)) + { $this->addr_to = $conf->global->MAIN_MAIL_FORCE_SENDTO; $this->addr_cc = ''; $this->addr_bcc = ''; From 3f136ee58d57c005de34c9781526f2433d2f10e5 Mon Sep 17 00:00:00 2001 From: Scott Albertson Date: Wed, 17 Oct 2018 12:28:05 -0700 Subject: [PATCH 40/69] Add "Reviewed by Hound" badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 776e2b02432..c38d0ca7dd1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # DOLIBARR ERP & CRM ![Downloads per day](https://img.shields.io/sourceforge/dm/dolibarr.svg) +[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) |6|7|8|develop| |----------|----------|----------|----------| From 63f47047259a10386376d378d54ae8cf9f35aec7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 01:05:10 +0200 Subject: [PATCH 41/69] Fix translation --- htdocs/langs/en_US/admin.lang | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 4630757dbad..1fc67ae2ba6 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -620,7 +620,7 @@ Module50000Name=PayBox Module50000Desc=Offer customers a PayBox online payment page (credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...) Module50100Name=Point of sales Module50100Desc=Point of sales module (POS). -Module50150Name=Point of salesaa +Module50150Name=Point of sales Module50150Desc=Point of sales module (Touch screen POS). Module50200Name=Paypal Module50200Desc=Offer customers a PayPal online payment page (PayPal account or credit/debit cards). This can be used to allow your customers to make free payments or for a payment on a particular Dolibarr object (invoice, order, ...) @@ -925,7 +925,7 @@ BackToModuleList=Back to modules list BackToDictionaryList=Back to list of Dictionaries TypeOfRevenueStamp=Type of tax stamp VATManagement=VAT Management -VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the VAT rate follows the active standard rule:
If the seller is not subject to VAT, then VAT defaults to 0. End of rule.

If the (seller's country = buyer's country), then the VAT by default equals the VAT of the product in the seller's country. End of rule.

If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default VAT is 0. This rule is dependant on the seller's country - please consult with your accountant. The VAT should be paid by the buyer to their customs office in their country and not to the seller. End of rule.

If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community VAT number) then the VAT by defaults to the VAT of the seller's country. End of rule.

If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community VAT number), then the VAT is 0 by default. End of rule.

In any other case the proposed default is VAT=0. End of rule.

+VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the VAT rate follows the active standard rule:
If the seller is not subject to VAT, then VAT defaults to 0. End of rule.
If the (seller's country = buyer's country), then the VAT by default equals the VAT of the product in the seller's country. End of rule.
If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default VAT is 0. This rule is dependant on the seller's country - please consult with your accountant. The VAT should be paid by the buyer to their customs office in their country and not to the seller. End of rule.
If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community VAT number) then the VAT by defaults to the VAT of the seller's country. End of rule.
If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community VAT number), then the VAT is 0 by default. End of rule.
In any other case the proposed default is VAT=0. End of rule.

VATIsNotUsedDesc=By default the proposed VAT is 0 which can be used for cases like associations, individuals or small companies. VATIsUsedExampleFR=In France, it means companies or organizations having a real fiscal system (Simplified real or normal real). A system in which VAT is declared. VATIsNotUsedExampleFR=In France, it means associations that are non VAT declared or companies, organizations or liberal professions that have chosen the micro enterprise fiscal system (VAT in franchise) and paid a franchise VAT without any VAT declaration. This choice will display the reference "Non applicable VAT - art-293B of CGI" on invoices. From b2a7845c8abbfe36daa92a35cf33af3784b803f1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 01:28:14 +0200 Subject: [PATCH 42/69] Fix trans --- htdocs/langs/en_US/admin.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 1fc67ae2ba6..2afe1a77c32 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -925,7 +925,7 @@ BackToModuleList=Back to modules list BackToDictionaryList=Back to list of Dictionaries TypeOfRevenueStamp=Type of tax stamp VATManagement=VAT Management -VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the VAT rate follows the active standard rule:
If the seller is not subject to VAT, then VAT defaults to 0. End of rule.
If the (seller's country = buyer's country), then the VAT by default equals the VAT of the product in the seller's country. End of rule.
If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default VAT is 0. This rule is dependant on the seller's country - please consult with your accountant. The VAT should be paid by the buyer to their customs office in their country and not to the seller. End of rule.
If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community VAT number) then the VAT by defaults to the VAT of the seller's country. End of rule.
If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community VAT number), then the VAT is 0 by default. End of rule.
In any other case the proposed default is VAT=0. End of rule.

+VATIsUsedDesc=By default when creating prospects, invoices, orders etc. the VAT rate follows the active standard rule:
If the seller is not subject to VAT, then VAT defaults to 0. End of rule.
If the (seller's country = buyer's country), then the VAT by default equals the VAT of the product in the seller's country. End of rule.
If the seller and buyer are both in the European Community and goods are transport-related products (haulage, shipping, airline), the default VAT is 0. This rule is dependant on the seller's country - please consult with your accountant. The VAT should be paid by the buyer to their customs office in their country and not to the seller. End of rule.
If the seller and buyer are both in the European Community and the buyer is not a company (with a registered intra-Community VAT number) then the VAT by defaults to the VAT of the seller's country. End of rule.
If the seller and buyer are both in the European Community and the buyer is a company (with a registered intra-Community VAT number), then the VAT is 0 by default. End of rule.
In any other case the proposed default is VAT=0. End of rule. VATIsNotUsedDesc=By default the proposed VAT is 0 which can be used for cases like associations, individuals or small companies. VATIsUsedExampleFR=In France, it means companies or organizations having a real fiscal system (Simplified real or normal real). A system in which VAT is declared. VATIsNotUsedExampleFR=In France, it means associations that are non VAT declared or companies, organizations or liberal professions that have chosen the micro enterprise fiscal system (VAT in franchise) and paid a franchise VAT without any VAT declaration. This choice will display the reference "Non applicable VAT - art-293B of CGI" on invoices. From 548fafc6e9d52e05159cd1bc6383b097c88fa5eb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 01:32:06 +0200 Subject: [PATCH 43/69] Fix trans --- htdocs/langs/en_US/admin.lang | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 2afe1a77c32..b173f7912dd 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -943,16 +943,16 @@ LocalTax2IsNotUsedDesc=Do not use other type of tax (other than VAT) LocalTax2Management=Third type of tax LocalTax2IsUsedExample= LocalTax2IsNotUsedExample= -LocalTax1ManagementES= RE Management -LocalTax1IsUsedDescES= The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:
If the buyer is not subjected to RE, RE by default=0. End of rule.
If the buyer is subjected to RE then the RE by default. End of rule.
-LocalTax1IsNotUsedDescES= By default the proposed RE is 0. End of rule. -LocalTax1IsUsedExampleES= In Spain they are professionals subject to some specific sections of the Spanish IAE. -LocalTax1IsNotUsedExampleES= In Spain they are professional and societies and subject to certain sections of the Spanish IAE. -LocalTax2ManagementES= IRPF Management -LocalTax2IsUsedDescES= The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:
If the seller is not subjected to IRPF, then IRPF by default=0. End of rule.
If the seller is subjected to IRPF then the IRPF by default. End of rule.
-LocalTax2IsNotUsedDescES= By default the proposed IRPF is 0. End of rule. -LocalTax2IsUsedExampleES= In Spain, freelancers and independent professionals who provide services and companies who have chosen the tax system of modules. -LocalTax2IsNotUsedExampleES= In Spain they are businesses not subject to tax system of modules. +LocalTax1ManagementES=RE Management +LocalTax1IsUsedDescES=The RE rate by default when creating prospects, invoices, orders etc. follow the active standard rule:
If the buyer is not subjected to RE, RE by default=0. End of rule.
If the buyer is subjected to RE then the RE by default. End of rule.
+LocalTax1IsNotUsedDescES=By default the proposed RE is 0. End of rule. +LocalTax1IsUsedExampleES=In Spain they are professionals subject to some specific sections of the Spanish IAE. +LocalTax1IsNotUsedExampleES=In Spain they are professional and societies and subject to certain sections of the Spanish IAE. +LocalTax2ManagementES=IRPF Management +LocalTax2IsUsedDescES=The IRPF rate by default when creating prospects, invoices, orders etc. follow the active standard rule:
If the seller is not subjected to IRPF, then IRPF by default=0. End of rule.
If the seller is subjected to IRPF then the IRPF by default. End of rule.
+LocalTax2IsNotUsedDescES=By default the proposed IRPF is 0. End of rule. +LocalTax2IsUsedExampleES=In Spain, freelancers and independent professionals who provide services and companies who have chosen the tax system of modules. +LocalTax2IsNotUsedExampleES=In Spain they are businesses not subject to tax system of modules. CalcLocaltax=Reports on local taxes CalcLocaltax1=Sales - Purchases CalcLocaltax1Desc=Local Taxes reports are calculated with the difference between localtaxes sales and localtaxes purchases @@ -1007,7 +1007,7 @@ MessageLogin=Login page message LoginPage=Login page BackgroundImageLogin=Background image PermanentLeftSearchForm=Permanent search form on left menu -DefaultLanguage=Default language to use (variant) +DefaultLanguage=Default language to use (language code) EnableMultilangInterface=Enable multilingual interface EnableShowLogo=Show logo on left menu CompanyInfo=Company/Organization From fd989230a4b439c90b3e5b88bf8d7cd5fda209f2 Mon Sep 17 00:00:00 2001 From: Juanjo Menent Date: Thu, 18 Oct 2018 09:09:42 +0200 Subject: [PATCH 44/69] New: works with variants: -Child label change if parent changes --- htdocs/variants/class/ProductCombination.class.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php index 8908bfa4d2d..77acc80483c 100644 --- a/htdocs/variants/class/ProductCombination.class.php +++ b/htdocs/variants/class/ProductCombination.class.php @@ -330,6 +330,7 @@ class ProductCombination $child->price_autogen = $parent->price_autogen; $child->weight = $parent->weight + $this->variation_weight; $child->weight_units = $parent->weight_units; + $child->label = $parent->label; if ($child->update($child->id, $user) > 0) { From 6c76f9517f259c14a4dc89121b846aabed2c2dbf Mon Sep 17 00:00:00 2001 From: Juanjo Menent Date: Thu, 18 Oct 2018 10:26:21 +0200 Subject: [PATCH 45/69] New: works with variants: -Child label with combination labels --- .../class/ProductCombination.class.php | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php index 77acc80483c..5385664abd4 100644 --- a/htdocs/variants/class/ProductCombination.class.php +++ b/htdocs/variants/class/ProductCombination.class.php @@ -330,7 +330,8 @@ class ProductCombination $child->price_autogen = $parent->price_autogen; $child->weight = $parent->weight + $this->variation_weight; $child->weight_units = $parent->weight_units; - $child->label = $parent->label; + $varlabel = $this->getLabelOfCombination($this->fk_product_child); + $child->label = $parent->label.$varlabel; if ($child->update($child->id, $user) > 0) { @@ -683,4 +684,39 @@ WHERE c.fk_product_parent = ".(int) $productid." AND p.tosell = 1"; return 1; } + + /** + * Return label for combinations + * @param int $prod_child id of child + * @return string combination label + */ + public function getLabelOfCombination($prod_child) + { + $label = ''; + $sql = 'SELECT pav.value AS label'; + $sql.= ' FROM llx_product_attribute_combination pac'; + $sql.= ' INNER JOIN llx_product_attribute_combination2val pac2v ON pac2v.fk_prod_combination=pac.rowid'; + $sql.= ' INNER JOIN llx_product_attribute_value pav ON pav.rowid=pac2v.fk_prod_attr_val'; + $sql.= ' WHERE pac.fk_product_child='.$prod_child; + + $resql = $this->db->query($sql); + if ($resql) { + $num = $this->db->num_rows($resql); + + $i = 0; + + while ($i < $num) + { + $obj = $this->db->fetch_object($resql); + + if ($obj->label) + { + $label.=' '.$obj->label; + } + $i++; + } + + } + return $label; + } } From c588f5e6c09ee98d586818dcdfe8f4bfae8599a6 Mon Sep 17 00:00:00 2001 From: Juanjo Menent Date: Thu, 18 Oct 2018 10:55:27 +0200 Subject: [PATCH 46/69] New: works with variants: -Child label with combination labels --- htdocs/variants/class/ProductCombination.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/variants/class/ProductCombination.class.php b/htdocs/variants/class/ProductCombination.class.php index 5385664abd4..130b18dafc5 100644 --- a/htdocs/variants/class/ProductCombination.class.php +++ b/htdocs/variants/class/ProductCombination.class.php @@ -694,9 +694,9 @@ WHERE c.fk_product_parent = ".(int) $productid." AND p.tosell = 1"; { $label = ''; $sql = 'SELECT pav.value AS label'; - $sql.= ' FROM llx_product_attribute_combination pac'; - $sql.= ' INNER JOIN llx_product_attribute_combination2val pac2v ON pac2v.fk_prod_combination=pac.rowid'; - $sql.= ' INNER JOIN llx_product_attribute_value pav ON pav.rowid=pac2v.fk_prod_attr_val'; + $sql.= ' FROM '.MAIN_DB_PREFIX.'product_attribute_combination pac'; + $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product_attribute_combination2val pac2v ON pac2v.fk_prod_combination=pac.rowid'; + $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product_attribute_value pav ON pav.rowid=pac2v.fk_prod_attr_val'; $sql.= ' WHERE pac.fk_product_child='.$prod_child; $resql = $this->db->query($sql); From 52ad5c5565a8b3eabb0e253d26fc2deec48a6dce Mon Sep 17 00:00:00 2001 From: Juanjo Menent Date: Thu, 18 Oct 2018 12:21:39 +0200 Subject: [PATCH 47/69] New: works with variants: -To edit child price and weight impacts better to see in tab the father price and weight --- htdocs/variants/combinations.php | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/htdocs/variants/combinations.php b/htdocs/variants/combinations.php index 848e5ee70fe..fb23921be25 100644 --- a/htdocs/variants/combinations.php +++ b/htdocs/variants/combinations.php @@ -318,6 +318,66 @@ if (! empty($id) || ! empty($ref)) dol_banner_tab($object, 'ref', $linkback, ($user->societe_id?0:1), 'ref', '', '', '', 0, '', '', 1); + print '
'; + + print '
'; + print '
'.dol_trunc($objp->label,32).''.$productstatic->getNomUrl(1).'
' . $langs->trans("Codejournal") . '' . $formaccounting->select_journal(GETPOST('code_journal', 'alpha'),'code_journal',0,1,array(),1,1) . '' . $formaccounting->select_journal($journal_code,'code_journal',0,0,1,1) . '
'; - print $formaccounting->select_account($line->numero_compte, 'account_number', 1, array (), 1, 1, ''); + print $formaccounting->select_account($line->numero_compte, 'accountingaccount_number', 1, array (), 1, 1, ''); print ''; // TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because it does not @@ -628,9 +638,9 @@ if ($action == 'create') print ''; print '' . length_accountg($line->numero_compte) . '' . $accountingaccount->getNomUrl(0,1,1,'',0) . '' . length_accounta($line->subledger_account) . '' . $line->label_compte . '' . $line->label_operation. '' . price($line->debit) . '' . price($line->credit) . '
'; - print $formaccounting->select_account($account_number, 'account_number', 1, array (), 1, 1, ''); + print $formaccounting->select_account($accountingaccount_number, 'accountingaccount_number', 1, array (), 1, 1, ''); print ''; // TODO For the moment we keep a fre input text instead of a combo. The select_auxaccount has problem because it does not @@ -677,7 +687,6 @@ if ($action == 'create') print ''; } print '
'; From aea7299970f6bd48b101474074868f8f9c611e45 Mon Sep 17 00:00:00 2001 From: gauthier Date: Wed, 17 Oct 2018 15:49:08 +0200 Subject: [PATCH 32/69] FIX : use discount with multicurrency --- htdocs/compta/facture/card.php | 6 ++++++ htdocs/compta/facture/class/facture.class.php | 6 +++--- htdocs/core/class/discount.class.php | 4 +++- htdocs/societe/class/societe.class.php | 6 +++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 1d22d21d574..c92a182124e 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -693,6 +693,9 @@ if (empty($reshook)) $amount_ht[$line->tva_tx] += $line->total_ht; $amount_tva[$line->tva_tx] += $line->total_tva; $amount_ttc[$line->tva_tx] += $line->total_ttc; + $multicurrency_amount_ht[$line->tva_tx] += $line->multicurrency_total_ht; + $multicurrency_amount_tva[$line->tva_tx] += $line->multicurrency_total_tva; + $multicurrency_amount_ttc[$line->tva_tx] += $line->multicurrency_total_ttc; $i ++; } } @@ -748,6 +751,9 @@ if (empty($reshook)) $discount->amount_ht = abs($amount_ht[$tva_tx]); $discount->amount_tva = abs($amount_tva[$tva_tx]); $discount->amount_ttc = abs($amount_ttc[$tva_tx]); + $discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]); + $discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]); + $discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]); $discount->tva_tx = abs($tva_tx); $result = $discount->create($user); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 9bf6d4b876c..f0601ba37af 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1700,9 +1700,9 @@ class Facture extends CommonInvoice $facligne->total_ttc = -$remise->amount_ttc; $facligne->multicurrency_subprice = -$remise->multicurrency_subprice; - $facligne->multicurrency_total_ht = -$remise->multicurrency_total_ht; - $facligne->multicurrency_total_tva = -$remise->multicurrency_total_tva; - $facligne->multicurrency_total_ttc = -$remise->multicurrency_total_ttc; + $facligne->multicurrency_total_ht = -$remise->multicurrency_amount_ht; + $facligne->multicurrency_total_tva = -$remise->multicurrency_amount_tva; + $facligne->multicurrency_total_ttc = -$remise->multicurrency_amount_ttc; $lineid=$facligne->insert(); if ($lineid > 0) diff --git a/htdocs/core/class/discount.class.php b/htdocs/core/class/discount.class.php index 37dedea8b6b..e1796c38421 100644 --- a/htdocs/core/class/discount.class.php +++ b/htdocs/core/class/discount.class.php @@ -103,7 +103,7 @@ class DiscountAbsolute $this->amount_tva = $obj->amount_tva; $this->amount_ttc = $obj->amount_ttc; - $this->multicurrency_amount_ht = $obj->multicurrency_amount_ht; + $this->multicurrency_amount_ht = $this->multicurrency_subprice = $obj->multicurrency_amount_ht; $this->multicurrency_amount_tva = $obj->multicurrency_amount_tva; $this->multicurrency_amount_ttc = $obj->multicurrency_amount_ttc; @@ -161,10 +161,12 @@ class DiscountAbsolute $sql = "INSERT INTO ".MAIN_DB_PREFIX."societe_remise_except"; $sql.= " (entity, datec, fk_soc, fk_user, description,"; $sql.= " amount_ht, amount_tva, amount_ttc, tva_tx,"; + $sql.= " multicurrency_amount_ht, multicurrency_amount_tva, multicurrency_amount_ttc,"; $sql.= " fk_facture_source"; $sql.= ")"; $sql.= " VALUES (".$conf->entity.", '".$this->db->idate($this->datec!=''?$this->datec:dol_now())."', ".$this->fk_soc.", ".$user->id.", '".$this->db->escape($this->description)."',"; $sql.= " ".$this->amount_ht.", ".$this->amount_tva.", ".$this->amount_ttc.", ".$this->tva_tx.","; + $sql.= " ".$this->multicurrency_amount_ht.", ".$this->multicurrency_amount_tva.", ".$this->multicurrency_amount_ttc.", "; $sql.= " ".($this->fk_facture_source ? "'".$this->db->escape($this->fk_facture_source)."'":"null"); $sql.= ")"; diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 843803abca8..2a488aacf44 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -1680,9 +1680,9 @@ class Societe extends CommonObject $discount = new DiscountAbsolute($this->db); $discount->fk_soc=$this->id; - $discount->amount_ht=price2num($remise,'MT'); - $discount->amount_tva=price2num($remise*$tva_tx/100,'MT'); - $discount->amount_ttc=price2num($discount->amount_ht+$discount->amount_tva,'MT'); + $discount->amount_ht=$discount->multicurrency_amount_ht=price2num($remise,'MT'); + $discount->amount_tva=$discount->multicurrency_amount_tva=price2num($remise*$tva_tx/100,'MT'); + $discount->amount_ttc=$discount->multicurrency_amount_ttc=price2num($discount->amount_ht+$discount->amount_tva,'MT'); $discount->tva_tx=price2num($tva_tx,'MT'); $discount->description=$desc; $result=$discount->create($user); From d86c44e641b336a46a6b673298db44704a019090 Mon Sep 17 00:00:00 2001 From: atm-greg Date: Wed, 17 Oct 2018 15:55:46 +0200 Subject: [PATCH 33/69] Add conf to disable a thirdparty type --- htdocs/langs/en_US/admin.lang | 1 + htdocs/societe/admin/societe.php | 34 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 4630757dbad..4054ca8c254 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1821,3 +1821,4 @@ DisabledResourceLinkUser=Disable feature to link a resource to users DisabledResourceLinkContact=Disable feature to link a resource to contacts ConfirmUnactivation=Confirm module reset OnMobileOnly=On small screen (smartphone) only +DisableProspectCustomerType=Disable the "Prospect/customer" thirdparty type diff --git a/htdocs/societe/admin/societe.php b/htdocs/societe/admin/societe.php index 3a7b26505c7..49a9538e225 100644 --- a/htdocs/societe/admin/societe.php +++ b/htdocs/societe/admin/societe.php @@ -211,6 +211,21 @@ if ($action=="setaskforshippingmet") { } } +//Activate "Disable prospect/customer type" +if ($action=="setdisableprospectcustomer") { + $setdisableprospectcustomer = GETPOST('value','int'); + $res = dolibarr_set_const($db, "SOCIETE_DISABLE_PROSPECTSCUSTOMERS", $setdisableprospectcustomer,'yesno',0,'',$conf->entity); + if (! $res > 0) $error++; + if (! $error) + { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } + else + { + setEventMessages($langs->trans("Error"), null, 'errors'); + } +} + //Activate ProfId unique if ($action == 'setprofid') { @@ -821,6 +836,25 @@ else print '
'.$langs->trans("DisableProspectCustomerType").' '; +if (!empty($conf->global->SOCIETE_DISABLE_PROSPECTSCUSTOMERS)) +{ + print ''; + print img_picto($langs->trans("Activated"),'switch_on'); + +} +else +{ + print ''; + print img_picto($langs->trans("Disabled"),'switch_off'); +} +print '
'.$langs->trans("OnSearchAndListGoOnCustomerOrSupplierCard").' 
'; + + // TVA + print ''; + + // Price + print ''; + + // Price minimum + print ''; + + // Weight + print '\n"; + + + + + print "
' . $langs->trans("DefaultTaxRate") . ''; + + $positiverates=''; + if (price2num($object->tva_tx)) $positiverates.=($positiverates?'/':'').price2num($object->tva_tx); + if (price2num($object->localtax1_type)) $positiverates.=($positiverates?'/':'').price2num($object->localtax1_tx); + if (price2num($object->localtax2_type)) $positiverates.=($positiverates?'/':'').price2num($object->localtax2_tx); + if (empty($positiverates)) $positiverates='0'; + echo vatrate($positiverates.($object->default_vat_code?' ('.$object->default_vat_code.')':''), '%', $object->tva_npr); + /* + if ($object->default_vat_code) + { + print vatrate($object->tva_tx, true) . ' ('.$object->default_vat_code.')'; + } + else print vatrate($object->tva_tx, true, $object->tva_npr, true);*/ + print '
' . $langs->trans("SellingPrice") . ''; + if ($object->price_base_type == 'TTC') { + print price($object->price_ttc) . ' ' . $langs->trans($object->price_base_type); + } else { + print price($object->price) . ' ' . $langs->trans($object->price_base_type); + } + print '
' . $langs->trans("MinPrice") . ''; + if ($object->price_base_type == 'TTC') { + print price($object->price_min_ttc) . ' ' . $langs->trans($object->price_base_type); + } else { + print price($object->price_min) . ' ' . $langs->trans($object->price_base_type); + } + print '
'.$langs->trans("Weight").''; + if ($object->weight != '') + { + print $object->weight." ".measuring_units_string($object->weight_units,"weight"); + } + else + { + print ' '; + } + print "
\n"; + + print '
'; + print '
'; + dol_fiche_end(); From b396aaebc5d54fb95d1d2a1cf7c7394fe5f9e62a Mon Sep 17 00:00:00 2001 From: andreubisquerra Date: Thu, 18 Oct 2018 16:31:37 +0200 Subject: [PATCH 48/69] Fix delete without any selected line --- htdocs/takepos/invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/takepos/invoice.php b/htdocs/takepos/invoice.php index cdfe47a756f..c71f7f861a3 100644 --- a/htdocs/takepos/invoice.php +++ b/htdocs/takepos/invoice.php @@ -115,7 +115,7 @@ if ($action=="deleteline"){ $row = $db->fetch_array ($resql); $deletelineid=$row[0]; $invoice->deleteline($deletelineid); - $invoice->fetch($deletelineid); + $invoice->fetch($placeid); } } From 7cafdc4d9a1610a1a52c831cf8be85e3a1008a9d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 16:56:43 +0200 Subject: [PATCH 49/69] Fix phpcs --- htdocs/compta/paiement/class/paiement.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/compta/paiement/class/paiement.class.php b/htdocs/compta/paiement/class/paiement.class.php index cc60c2cba8e..a7e7c48a370 100644 --- a/htdocs/compta/paiement/class/paiement.class.php +++ b/htdocs/compta/paiement/class/paiement.class.php @@ -233,11 +233,11 @@ class Paiement extends CommonObject $mtotal = $totalamount; } $note = ($this->note_public?$this->note_public:$this->note); - $payment_id = $this->payment_id ? $this->payment_id : null; - $payment_site = $this->payment_site ? $this->payment_site : null; + $payment_id = $this->payment_id ? $this->payment_id : null; + $payment_site = $this->payment_site ? $this->payment_site : null; $sql = "INSERT INTO ".MAIN_DB_PREFIX."paiement (entity, ref, datec, datep, amount, multicurrency_amount, fk_paiement, num_paiement, note, ext_payment_id, ext_payment_site, fk_user_creat)"; - $sql.= " VALUES (".$conf->entity.", '".$this->ref."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', '".$total."', '".$mtotal."', ".$this->paiementid.", '".$this->num_paiement."', '".$this->db->escape($note)."', '".$this->payment_id."', '".$this->payment_site."', ".$user->id.")"; + $sql.= " VALUES (".$conf->entity.", '".$this->db->escape($this->ref)."', '". $this->db->idate($now)."', '".$this->db->idate($this->datepaye)."', ".$total.", ".$mtotal.", ".$this->paiementid.", '".$this->db->escape($this->num_paiement)."', '".$this->db->escape($note)."', '".$this->db->escape($this->payment_id)."', '".$this->db->escape($this->payment_site)."', ".$user->id.")"; dol_syslog(get_class($this)."::Create insert paiement", LOG_DEBUG); $resql = $this->db->query($sql); From 05326e271da8f2f0b2008bdfdc9d90f2ca957f09 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 17:15:26 +0200 Subject: [PATCH 50/69] FIX Filter on invoice type --- htdocs/compta/facture/list.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 78576e4c00d..35338722353 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -422,7 +422,7 @@ if ($filtre) } if ($search_ref) $sql .= natural_search('f.facnumber', $search_ref); if ($search_refcustomer) $sql .= natural_search('f.ref_client', $search_refcustomer); -if ($search_type != '') $sql.=" AND f.type IN (".$db->escape($search_type).")"; +if ($search_type != '' && $search_type != '-1') $sql.=" AND f.type IN (".$db->escape($search_type).")"; if ($search_project) $sql .= natural_search('p.ref', $search_project); if ($search_societe) $sql .= natural_search('s.nom', $search_societe); if ($search_town) $sql.= natural_search('s.town', $search_town); From 66cb06eca9e876111cc27737e12cffc0a2fb93ae Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 17:33:14 +0200 Subject: [PATCH 51/69] NEW Top menu is always on screen with MD theme. --- htdocs/theme/md/style.css.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index 3b67c895e0d..2ec97ec7a9d 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1205,6 +1205,13 @@ td.showDragHandle { .side-nav-vert { margin-left: 228px; } +global->THEME_DISABLE_STICKY_TOPMENU)) { ?> +.side-nav-vert { + position: sticky; + top: 0px; + z-index: 210; +} + /* For smartphone (testmenuhider is on) */ browser->layout, array('phone','tablet')) && ((GETPOST('testmenuhider') || ! empty($conf->global->MAIN_TESTMENUHIDER)) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))) { ?> From d4bc53660bf6daee7593d614a79576bfe0dfb568 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 18 Oct 2018 21:22:30 +0200 Subject: [PATCH 52/69] Code comment and debug filemanager --- htdocs/core/ajax/ajaxdirpreview.php | 24 ++++++- htdocs/core/ajax/ajaxdirtree.php | 82 ++++++++++++++++++----- htdocs/core/tpl/filemanager.tpl.php | 21 ++++-- htdocs/ecm/tpl/enablefiletreeajax.tpl.php | 8 ++- 4 files changed, 106 insertions(+), 29 deletions(-) diff --git a/htdocs/core/ajax/ajaxdirpreview.php b/htdocs/core/ajax/ajaxdirpreview.php index 8d1c5cd712c..82f83595537 100644 --- a/htdocs/core/ajax/ajaxdirpreview.php +++ b/htdocs/core/ajax/ajaxdirpreview.php @@ -82,9 +82,16 @@ else // For no ajax call dol_print_error($db,$ecmdir->error); exit; } + + $relativepath=$ecmdir->getRelativePath(); // Example 'mydir/' } - $relativepath=$ecmdir->getRelativePath(); - $upload_dir = $rootdirfordoc.'/'.$relativepath; + elseif (GETPOST('section_dir')) + { + $relativepath=GETPOST('section_dir'); + } + //var_dump($section.'-'.GETPOST('section_dir').'-'.$relativepath); + + $upload_dir = $rootdirfordoc.'/'.$relativepath; } if (empty($url)) @@ -226,7 +233,18 @@ if ($type == 'directory') { if ($module == 'medias') { - $relativepath=GETPOST('file','alpha'); + /* + $_POST is array like + 'token' => string '062380e11b7dcd009d07318b57b71750' (length=32) + 'action' => string 'file_manager' (length=12) + 'website' => string 'template' (length=8) + 'pageid' => string '124' (length=3) + 'section_dir' => string 'mydir/' (length=3) + 'section_id' => string '0' (length=1) + 'max_file_size' => string '2097152' (length=7) + 'sendit' => string 'Envoyer fichier' (length=15) + */ + $relativepath=GETPOST('file','alpha')?GETPOST('file','alpha'):GETPOST('section_dir','alpha'); if ($relativepath && $relativepath!= '/') $relativepath.='/'; $upload_dir = $dolibarr_main_data_root.'/'.$module.'/'.$relativepath; if (GETPOSTISSET('website') || GETPOSTISSET('file_manager')) diff --git a/htdocs/core/ajax/ajaxdirtree.php b/htdocs/core/ajax/ajaxdirtree.php index 4b588751829..a55df4a1038 100644 --- a/htdocs/core/ajax/ajaxdirtree.php +++ b/htdocs/core/ajax/ajaxdirtree.php @@ -30,6 +30,7 @@ if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); + if (! isset($mode) || $mode != 'noajax') // For ajax call { $res=@include '../../main.inc.php'; @@ -39,16 +40,26 @@ if (! isset($mode) || $mode != 'noajax') // For ajax call include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmdirectory.class.php'; + //if (GETPOST('preopened')) { $_GET['dir'] = $_POST['dir'] = '/bbb/'; } + $openeddir = GETPOST('openeddir'); $modulepart= GETPOST('modulepart'); $selecteddir = jsUnEscape(GETPOST('dir')); // relative path. We must decode using same encoding function used by javascript: escape() + + $preopened = GETPOST('preopened'); + if ($selecteddir != '/') $selecteddir = preg_replace('/\/$/','',$selecteddir); // We removed last '/' except if it is '/' } else // For no ajax call { + //if (GETPOST('preopened')) { $_GET['dir'] = $_POST['dir'] = GETPOST('preopened'); } + $openeddir = GETPOST('openeddir'); $modulepart= GETPOST('modulepart'); $selecteddir = GETPOST('dir'); + + $preopened = GETPOST('preopened'); + if ($selecteddir != '/') $selecteddir = preg_replace('/\/$/','',$selecteddir); // We removed last '/' except if it is '/' if (empty($url)) $url=DOL_URL_ROOT.'/ecm/index.php'; } @@ -58,8 +69,16 @@ $langs->load("ecm"); // Define fullpathselecteddir. $fullpathselecteddir=''; -if ($modulepart == 'ecm') $fullpathselecteddir=$conf->ecm->dir_output.'/'.($selecteddir != '/' ? $selecteddir : ''); -if ($modulepart == 'medias') $fullpathselecteddir=$dolibarr_main_data_root.'/medias/'.($selecteddir != '/' ? $selecteddir : ''); +if ($modulepart == 'ecm') +{ + $fullpathselecteddir=$conf->ecm->dir_output.'/'.($selecteddir != '/' ? $selecteddir : ''); + $fullpathopeneddir=$conf->ecm->dir_output.'/'.($openeddir != '/' ? $openeddir : ''); +} +if ($modulepart == 'medias') +{ + $fullpathselecteddir=$dolibarr_main_data_root.'/medias/'.($selecteddir != '/' ? $selecteddir : ''); + $fullpathopeneddir=$dolibarr_main_data_root.'/medias/'.($openeddir != '/' ? $openeddir : ''); +} // Security: @@ -87,20 +106,20 @@ if ($modulepart == 'medias') * View */ -if (! isset($mode) || $mode != 'noajax') +if (! isset($mode) || $mode != 'noajax') // if ajax mode { top_httphead(); } -//print ''."\n"; +//print ''."\n"; $userstatic=new User($db); $form=new Form($db); $ecmdirstatic = new EcmDirectory($db); -// Load full tree from database. We will use it to define nbofsubdir and nboffilesinsubdir +// Load full tree of ECM module from database. We will use it to define nbofsubdir and nboffilesinsubdir if (empty($sqltree)) $sqltree=$ecmdirstatic->get_full_arbo(0); -// Try to find key into $sqltree +// Try to find selected dir id into $sqltree and save it into $current_ecmdir_id $current_ecmdir_id=-1; foreach($sqltree as $keycursor => $val) { @@ -113,6 +132,25 @@ foreach($sqltree as $keycursor => $val) if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_JS)) { + +/** + * treeOutputForAbsoluteDir + * + * @param array $sqltree Sqltree + * @param string $selecteddir Selected dir + * @param string $fullpathselecteddir Full path of selected dir + * @param string $modulepart Modulepart + * @param string $websitekey Website key + * @param int $pageid Page id + * @return void + */ +function treeOutputForAbsoluteDir($sqltree, $selecteddir, $fullpathselecteddir, $modulepart, $websitekey, $pageid) +{ + global $db, $langs, $form; + + $ecmdirstatic = new EcmDirectory($db); + $userstatic = new User($db); + if (file_exists($fullpathselecteddir)) { $files = @scandir($fullpathselecteddir); @@ -172,7 +210,7 @@ if (! empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE $nboffilesinsubdir=$langs->trans("Unknown"); } - print '\n"; } } - // Enable jquery handlers on new generated HTML objects (same code than into lib_footer.js.php) - // Because the content is reloaded by ajax call, we must also reenable some jquery hooks - print "\n\n"; - print ''; - echo "\n"; - - } - } - else print "PermissionDenied"; - } - // This ajax service is called only when a directory $selecteddir is opened but not when closed. //print '