From 9d931b7b053223ed5e29835c904c6e6e7973d746 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Wed, 10 Jul 2013 15:54:28 +0200 Subject: [PATCH 01/13] Task # 862 : ODT templates on shipment --- htdocs/admin/expedition.php | 179 +++--- .../doc/doc_generic_shipment_odt.modules.php | 569 ++++++++++++++++++ ...erou.modules.php => pdf_merou.modules.php} | 4 +- ...get.modules.php => pdf_rouget.modules.php} | 4 +- htdocs/core/modules/modExpedition.class.php | 32 + .../shipment/template_shipment.odt | Bin 0 -> 25555 bytes 6 files changed, 716 insertions(+), 72 deletions(-) create mode 100644 htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php rename htdocs/core/modules/expedition/doc/{pdf_expedition_merou.modules.php => pdf_merou.modules.php} (99%) rename htdocs/core/modules/expedition/doc/{pdf_expedition_rouget.modules.php => pdf_rouget.modules.php} (99%) create mode 100644 htdocs/install/doctemplates/shipment/template_shipment.odt diff --git a/htdocs/admin/expedition.php b/htdocs/admin/expedition.php index a5451248078..fd11266b74f 100644 --- a/htdocs/admin/expedition.php +++ b/htdocs/admin/expedition.php @@ -105,11 +105,11 @@ else if ($action == 'specimen') $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); foreach($dirmodels as $reldir) { - $file=dol_buildpath($reldir."core/modules/expedition/doc/pdf_expedition_".$modele.".modules.php",0); + $file=dol_buildpath($reldir."core/modules/expedition/doc/pdf_".$modele.".modules.php",0); if (file_exists($file)) { $filefound=1; - $classname = "pdf_expedition_".$modele; + $classname = "pdf_".$modele; break; } } @@ -175,6 +175,14 @@ else if ($action == 'setmodel') { dolibarr_set_const($db, "EXPEDITION_ADDON_NUMBER",$value,'chaine',0,'',$conf->entity); } +else if ($action=='setModuleOptions') { + if (dolibarr_set_const($db, "EXPEDITION_ADDON_PDF_ODT_PATH",GETPOST('value1'),'chaine',0,'',$conf->entity)) + { + // La constante qui a ete lue en avant du nouveau set + // on passe donc par une variable pour avoir un affichage coherent + $conf->global->EXPEDITION_ADDON_PDF_ODT_PATH = GETPOST('value1'); + } +} /* @@ -370,80 +378,115 @@ clearstatcache(); $var=true; foreach ($dirmodels as $reldir) { - $dir = dol_buildpath($reldir."core/modules/expedition/doc/"); + foreach (array('','/doc') as $valdir) + { + $dir = dol_buildpath($reldir."core/modules/expedition".$valdir); - if (is_dir($dir)) - { - $handle=opendir($dir); - if (is_resource($handle)) - { - while (($file = readdir($handle))!==false) - { - if (substr($file, dol_strlen($file) -12) == '.modules.php' && substr($file,0,15) == 'pdf_expedition_') - { - $name = substr($file, 15, dol_strlen($file) - 27); - $classname = substr($file, 0, dol_strlen($file) - 12); + if (is_dir($dir)) + { + $handle=opendir($dir); + if (is_resource($handle)) + { + while (($file = readdir($handle))!==false) + { + $filelist[]=$file; + } + closedir($handle); + arsort($filelist); - $var=!$var; - print ''; - print $name; - print "\n"; - require_once $dir.$file; - $module = new $classname(); + foreach($filelist as $file) + { + if (preg_match('/\.modules\.php$/i',$file) && preg_match('/^(pdf_|doc_)/',$file)) + { - print $module->description; - print ''; + if (file_exists($dir.'/'.$file)) + { + $name = substr($file, 4, dol_strlen($file) -16); + $classname = substr($file, 0, dol_strlen($file) -12); - // Active - if (in_array($name, $def)) - { - print "\n"; - print ''; - print img_picto($langs->trans("Activated"),'switch_on'); - print ''; - print ""; - } - else - { - print "\n"; - print ''.img_picto($langs->trans("Disabled"),'switch_off').''; - print ""; - } + require_once $dir.'/'.$file; + $module = new $classname($db); - // Default - print ""; - if ($conf->global->EXPEDITION_ADDON_PDF == $name) - { - print img_picto($langs->trans("Default"),'on'); - } - else - { - print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; - } - print ''; + $modulequalified=1; + if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified=0; + if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified=0; - // Info - $htmltooltip = ''.$langs->trans("Name").': '.$module->name; - $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); - $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; - $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; - $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); - print ''; - print $form->textwithpicto('',$htmltooltip,-1,0); - print ''; + if ($modulequalified) + { + $var = !$var; + print ''; + print (empty($module->name)?$name:$module->name); + print "\n"; + if (method_exists($module,'info')) print $module->info($langs); + else print $module->description; + print ''; - // Preview - $link='scandir.'&label='.urlencode($module->name).'">'.img_object($langs->trans("Preview"),'sending').''; - print ''; - print $link; - print ''; + // Active + if (in_array($name, $def)) + { + print ''."\n"; + print ''; + print img_picto($langs->trans("Enabled"),'switch_on'); + print ''; + print ''; + } + else + { + print ''."\n"; + print 'scandir.'&label='.urlencode($module->name).'">'.img_picto($langs->trans("Disabled"),'switch_off').''; + print ""; + } - print ''; - } - } - closedir($handle); - } - } + // Defaut + print ''; + if ($conf->global->EXPEDITION_ADDON_PDF == $name) + { + print img_picto($langs->trans("Default"),'on'); + } + else + { + print 'scandir.'&label='.urlencode($module->name).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"),'off').''; + } + print ''; + + // Info + $htmltooltip = ''.$langs->trans("Name").': '.$module->name; + $htmltooltip.='
'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown")); + if ($module->type == 'pdf') + { + $htmltooltip.='
'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur; + } + $htmltooltip.='

'.$langs->trans("FeaturesSupported").':'; + $htmltooltip.='
'.$langs->trans("Logo").': '.yn($module->option_logo,1,1); + $htmltooltip.='
'.$langs->trans("PaymentMode").': '.yn($module->option_modereg,1,1); + $htmltooltip.='
'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg,1,1); + $htmltooltip.='
'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang,1,1); + $htmltooltip.='
'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark,1,1); + + print ''; + print $form->textwithpicto('',$htmltooltip,1,0); + print ''; + + // Preview + print ''; + if ($module->type == 'pdf') + { + print 'scandir.'&label='.urlencode($module->name).'">'.img_object($langs->trans("Preview"),'sending').''; + } + else + { + print img_object($langs->trans("PreviewNotAvailable"),'generic'); + } + print ''; + + print "\n"; + } + } + } + } + } + } + } } print ''; diff --git a/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php new file mode 100644 index 00000000000..e6c917c4895 --- /dev/null +++ b/htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php @@ -0,0 +1,569 @@ + + * Copyright (C) 2012 Juanjo Menent +* +* 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/expedition/doc/doc_generic_shipment_odt.modules.php + * \ingroup expedition + * \brief File of class to build ODT documents for shipment + */ + +require_once DOL_DOCUMENT_ROOT.'/core/modules/expedition/modules_expedition.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/files.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/doc.lib.php'; + + +/** + * Class to build documents using ODF templates generator + */ +class doc_generic_shipment_odt extends ModelePdfExpedition +{ + var $emetteur; // Objet societe qui emet + + var $phpmin = array(5,2,0); // Minimum version of PHP required by module + var $version = 'dolibarr'; + + + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + function __construct($db) + { + global $conf,$langs,$mysoc; + + $langs->load("main"); + $langs->load("companies"); + + $this->db = $db; + $this->name = "ODT templates"; + $this->description = $langs->trans("DocumentModelOdt"); + $this->scandir = 'EXPEDITION_ADDON_PDF_ODT_PATH'; // Name of constant that is used to save list of directories to scan + + // Dimension page pour format A4 + $this->type = 'odt'; + $this->page_largeur = 0; + $this->page_hauteur = 0; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=0; + $this->marge_droite=0; + $this->marge_haute=0; + $this->marge_basse=0; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 0; // Gere option tva EXPEDITION_TVAOPTION + $this->option_modereg = 0; // Affiche mode reglement + $this->option_condreg = 0; // Affiche conditions reglement + $this->option_codeproduitservice = 0; // Affiche code produit-service + $this->option_multilang = 0; // 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 = 0; // Support add of a watermark on drafts + + // Recupere emetteur + $this->emetteur=$mysoc; + if (! $this->emetteur->country_code) $this->emetteur->country_code=substr($langs->defaultlang,-2); // By default if not defined + } + + + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @return array Array of substitution + */ + function get_substitutionarray_object($object,$outputlangs) + { + global $conf; + + $resarray=array( + 'object_id'=>$object->id, + 'object_ref'=>$object->ref, + 'object_ref_ext'=>$object->ref_ext, + 'object_ref_customer'=>$object->ref_client, + 'object_hour'=>dol_print_date($object->date,'hour'), + 'object_date'=>dol_print_date($object->date,'day'), + 'object_date_delivery'=>dol_print_date($object->date_livraison,'dayhour'), + 'object_date_creation'=>dol_print_date($object->date_creation,'day'), + 'object_date_modification'=>(! empty($object->date_modification)?dol_print_date($object->date_modification,'day'):''), + 'object_date_validation'=>(! empty($object->date_validation)?dol_print_date($object->date_validation,'dayhour'):''), + 'object_date_delivery_planed'=>(! empty($object->date_livraison)?dol_print_date($object->date_livraison,'day'):''), + 'object_date_close'=>dol_print_date($object->date_cloture,'dayhour'), + 'object_payment_mode_code'=>$object->mode_reglement_code, + 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), + 'object_payment_term_code'=>$object->cond_reglement_code, + 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), + 'object_total_ht'=>price($object->total_ht,0,$outputlangs), + 'object_total_vat'=>price($object->total_tva,0,$outputlangs), + 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), + 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_vatrate'=>vatrate($object->tva), + 'object_note_private'=>$object->note, + 'object_note'=>$object->note_public, + ); + + // Add vat by rates + foreach ($object->lines as $line) + { + if (empty($resarray['object_total_vat_'.$line->tva_tx])) $resarray['object_total_vat_'.$line->tva_tx]=0; + $resarray['object_total_vat_'.$line->tva_tx]+=$line->total_tva; + } + + return $resarray; + } + + /** + * Define array with couple substitution key => substitution value + * + * @param array $line Array of lines + * @param Translate $outputlangs Lang object to use for output + * @return array Return a substitution array + */ + function get_substitutionarray_lines($line,$outputlangs) + { + global $conf; + + return array( + 'line_fulldesc'=>doc_getlinedesc($line,$outputlangs), + 'line_product_ref'=>$line->product_ref, + 'line_product_label'=>$line->product_label, + 'line_desc'=>$line->desc, + 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits), + 'line_up'=>price($line->subprice, 0, $outputlangs), + 'line_qty'=>$line->qty, + 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), + 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), + 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), + 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), + 'line_date_start'=>$line->date_start, + 'line_date_end'=>$line->date_end + ); + } + + /** + * Return description of a module + * + * @param Translate $langs Lang object to use for output + * @return string Description + */ + function info($langs) + { + global $conf,$langs; + + $langs->load("companies"); + $langs->load("errors"); + + $form = new Form($this->db); + + $texte = $this->description.".
\n"; + $texte.= '
'; + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= ''; + + // List of directories area + $texte.= ''; + + + $texte.= ''; + $texte.= ''; + + /*$texte.= ''; + $texte.= ''; + $texte.= '';*/ + + $texte.= '
'; + $texttitle=$langs->trans("ListOfDirectories"); + $listofdir=explode(',',preg_replace('/[\r\n]+/',',',trim($conf->global->EXPEDITION_ADDON_PDF_ODT_PATH))); + $listoffiles=array(); + foreach($listofdir as $key=>$tmpdir) + { + $tmpdir=trim($tmpdir); + $tmpdir=preg_replace('/DOL_DATA_ROOT/',DOL_DATA_ROOT,$tmpdir); + if (! $tmpdir) { + unset($listofdir[$key]); continue; + } + if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound",$tmpdir),0); + else + { + $tmpfiles=dol_dir_list($tmpdir,'files',0,'\.odt'); + if (count($tmpfiles)) $listoffiles=array_merge($listoffiles,$tmpfiles); + } + } + $texthelp=$langs->trans("ListOfDirectoriesForModelGenODT"); + // Add list of substitution keys + $texthelp.='
'.$langs->trans("FollowingSubstitutionKeysCanBeUsed").'
'; + $texthelp.=$langs->transnoentitiesnoconv("FullListOnOnlineDocumentation"); // This contains an url, we don't modify it + + $texte.= $form->textwithpicto($texttitle,$texthelp,1,'help','',1); + $texte.= ''; + $texte.= ''; + $texte.= ''; + $texte.= '
'; + $texte.= ''; + $texte.= '  '; + $texte.= ''; + $texte.= '
'; + + // Scan directories + if (count($listofdir)) $texte.=$langs->trans("NumberOfModelFilesFound").': '.count($listoffiles).''; + + $texte.= '
'; + $texte.= $langs->trans("ExampleOfDirectoriesForModelGen"); + $texte.= '
'; + $texte.= ''; + $texte.= '
'; + $texte.= '
'; + + return $texte; + } + + /** + * Function to build a document on disk using the generic odt module. + * + * @param Expedition $object Object source to build document + * @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 if OK, <=0 if KO + */ + function write_file($object,$outputlangs,$srctemplatepath,$hidedetails=0,$hidedesc=0,$hideref=0) + { + global $user,$langs,$conf,$mysoc,$hookmanager; + + if (empty($srctemplatepath)) + { + dol_syslog("doc_generic_odt::write_file parameter srctemplatepath empty", LOG_WARNING); + return -1; + } + + // Add odtgeneration hook + if (! is_object($hookmanager)) + { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('odtgeneration')); + global $action; + + if (! is_object($outputlangs)) $outputlangs=$langs; + $sav_charset_output=$outputlangs->charset_output; + $outputlangs->charset_output='UTF-8'; + + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + + if ($conf->expedition->dir_output) + { + // If $object is id instead of object + if (! is_object($object)) + { + $id = $object; + $object = new Expedition($this->db); + $result=$object->fetch($id); + if ($result < 0) + { + dol_print_error($this->db,$object->error); + return -1; + } + } + + $dir = $conf->expedition->dir_output; + $objectref = dol_sanitizeFileName($object->ref); + if (! preg_match('/specimen/i',$objectref)) $dir.= "/" . $objectref; + $file = $dir . "/" . $objectref . ".odt"; + + if (! file_exists($dir)) + { + if (dol_mkdir($dir) < 0) + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + if (file_exists($dir)) + { + //print "srctemplatepath=".$srctemplatepath; // Src filename + $newfile=basename($srctemplatepath); + $newfiletmp=preg_replace('/\.od(t|s)/i','',$newfile); + $newfiletmp=preg_replace('/template_/i','',$newfiletmp); + $newfiletmp=preg_replace('/modele_/i','',$newfiletmp); + $newfiletmp=$objectref.'_'.$newfiletmp; + //$file=$dir.'/'.$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.odt'; + // Get extension (ods or odt) + $newfileformat=substr($newfile, strrpos($newfile, '.')+1); + if ( ! empty($conf->global->MAIN_DOC_USE_TIMING)) + { + $filename=$newfiletmp.'.'.dol_print_date(dol_now(),'%Y%m%d%H%M%S').'.'.$newfileformat; + } + else + { + $filename=$newfiletmp.'.'.$newfileformat; + } + $file=$dir.'/'.$filename; + //print "newdir=".$dir; + //print "newfile=".$newfile; + //print "file=".$file; + //print "conf->societe->dir_temp=".$conf->societe->dir_temp; + + dol_mkdir($conf->expedition->dir_temp); + + + // 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 + if (! empty($usecontact)) + { + // On peut utiliser le nom de la societe du contact + if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact; + else $socobject = $object->client; + } + else + { + $socobject=$object->client; + } + + // Make substitution + $substitutionarray=array( + '__FROM_NAME__' => $this->emetteur->nom, + '__FROM_EMAIL__' => $this->emetteur->email, + '__TOTAL_TTC__' => $object->total_ttc, + '__TOTAL_HT__' => $object->total_ht, + '__TOTAL_VAT__' => $object->total_vat + ); + complete_substitutions_array($substitutionarray, $langs, $object); + // Call the ODTSubstitution hook + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$substitutionarray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Line of free text + $newfreetext=''; + $paramfreetext='EXPEDITION_FREE_TEXT'; + if (! empty($conf->global->$paramfreetext)) + { + $newfreetext=make_substitutions($conf->global->$paramfreetext,$substitutionarray); + } + + // Open and load template + require_once ODTPHP_PATH.'odf.php'; + $odfHandler = new odf( + $srctemplatepath, + array( + 'PATH_TO_TMP' => $conf->expedition->dir_temp, + 'ZIP_PROXY' => 'PclZipProxy', // PhpZipProxy or PclZipProxy. Got "bad compression method" error when using PhpZipProxy. + 'DELIMITER_LEFT' => '{', + 'DELIMITER_RIGHT' => '}' + ) + ); + // After construction $odfHandler->contentXml contains content and + // [!-- BEGIN row.lines --]*[!-- END row.lines --] has been replaced by + // [!-- BEGIN lines --]*[!-- END lines --] + //print html_entity_decode($odfHandler->__toString()); + //print exit; + + + // Make substitutions into odt of freetext + try { + $odfHandler->setVars('free_text', $newfreetext, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + + // Make substitutions into odt of user info + $tmparray=$this->get_substitutionarray_user($user,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of mysoc + $tmparray=$this->get_substitutionarray_mysoc($mysoc,$outputlangs); + //var_dump($tmparray); exit; + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + //var_dump($value);exit; + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Make substitutions into odt of thirdparty + $tmparray=$this->get_substitutionarray_thirdparty($socobject,$outputlangs); + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Replace tags of object + external modules + $tmparray=$this->get_substitutionarray_object($object,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object); + // Call the ODTSubstitution hook + $parameters=array('file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray); + $reshook=$hookmanager->executeHooks('ODTSubstitution',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + foreach($tmparray as $key=>$value) + { + try { + if (preg_match('/logo$/',$key)) // Image + { + if (file_exists($value)) $odfHandler->setImage($key, $value); + else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8'); + } + else // Text + { + $odfHandler->setVars($key, $value, true, 'UTF-8'); + } + } + catch(OdfException $e) + { + } + } + // Replace tags of lines + try + { + $listlines = $odfHandler->setSegment('lines'); + foreach ($object->lines as $line) + { + $tmparray=$this->get_substitutionarray_lines($line,$outputlangs); + complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines"); + // Call the ODTSubstitutionLine hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs,'substitutionarray'=>&$tmparray,'line'=>$line); + $reshook=$hookmanager->executeHooks('ODTSubstitutionLine',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + foreach($tmparray as $key => $val) + { + try + { + $listlines->setVars($key, $val, true, 'UTF-8'); + } + catch(OdfException $e) + { + } + catch(SegmentException $e) + { + } + } + $listlines->merge(); + } + $odfHandler->mergeSegment($listlines); + } + catch(OdfException $e) + { + $this->error=$e->getMessage(); + dol_syslog($this->error, LOG_WARNING); + return -1; + } + + // Call the beforeODTSave hook + $parameters=array('odfHandler'=>&$odfHandler,'file'=>$file,'object'=>$object,'outputlangs'=>$outputlangs); + $reshook=$hookmanager->executeHooks('beforeODTSave',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + + // Write new file + if (!empty($conf->global->MAIN_ODT_AS_PDF)) { + try { + $odfHandler->exportAsAttachedPDF($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + else { + try { + $odfHandler->saveToDisk($file); + }catch (Exception $e){ + $this->error=$e->getMessage(); + return -1; + } + } + + if (! empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + + $odfHandler=null; // Destroy object + + return 1; // Success + } + else + { + $this->error=$langs->transnoentities("ErrorCanNotCreateDir",$dir); + return -1; + } + } + + return -1; + } + +} + +?> diff --git a/htdocs/core/modules/expedition/doc/pdf_expedition_merou.modules.php b/htdocs/core/modules/expedition/doc/pdf_merou.modules.php similarity index 99% rename from htdocs/core/modules/expedition/doc/pdf_expedition_merou.modules.php rename to htdocs/core/modules/expedition/doc/pdf_merou.modules.php index 4ffd39d0031..492c01be2da 100644 --- a/htdocs/core/modules/expedition/doc/pdf_expedition_merou.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_merou.modules.php @@ -20,7 +20,7 @@ */ /** - * \file htdocs/core/modules/expedition/doc/pdf_expedition_merou.modules.php + * \file htdocs/core/modules/expedition/doc/pdf_merou.modules.php * \ingroup expedition * \brief Fichier de la classe permettant de generer les bordereaux envoi au modele Merou */ @@ -34,7 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; /** * Classe permettant de generer les borderaux envoi au modele Merou */ -class pdf_expedition_merou extends ModelePdfExpedition +class pdf_merou extends ModelePdfExpedition { var $emetteur; // Objet societe qui emet diff --git a/htdocs/core/modules/expedition/doc/pdf_expedition_rouget.modules.php b/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php similarity index 99% rename from htdocs/core/modules/expedition/doc/pdf_expedition_rouget.modules.php rename to htdocs/core/modules/expedition/doc/pdf_rouget.modules.php index 15a94b8aaed..2f7a70b0e3f 100644 --- a/htdocs/core/modules/expedition/doc/pdf_expedition_rouget.modules.php +++ b/htdocs/core/modules/expedition/doc/pdf_rouget.modules.php @@ -19,7 +19,7 @@ */ /** - * \file htdocs/core/modules/expedition/doc/pdf_expedition_rouget.modules.php + * \file htdocs/core/modules/expedition/doc/pdf_rouget.modules.php * \ingroup expedition * \brief Fichier de la classe permettant de generer les bordereaux envoi au modele Rouget */ @@ -32,7 +32,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; /** * Classe permettant de generer les borderaux envoi au modele Rouget */ -class pdf_expedition_rouget extends ModelePdfExpedition +class pdf_rouget extends ModelePdfExpedition { var $emetteur; // Objet societe qui emet diff --git a/htdocs/core/modules/modExpedition.class.php b/htdocs/core/modules/modExpedition.class.php index 5704f96d0cc..40515f68fed 100644 --- a/htdocs/core/modules/modExpedition.class.php +++ b/htdocs/core/modules/modExpedition.class.php @@ -94,6 +94,13 @@ class modExpedition extends DolibarrModules $this->const[$r][3] = 'Nom du gestionnaire de numerotation des expeditions'; $this->const[$r][4] = 0; $r++; + + $r++; + $this->const[$r][0] = "EXPEDITION_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/shipment"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; $this->const[$r][0] = "LIVRAISON_ADDON_PDF"; $this->const[$r][1] = "chaine"; @@ -108,6 +115,13 @@ class modExpedition extends DolibarrModules $this->const[$r][3] = 'Nom du gestionnaire de numerotation des bons de reception'; $this->const[$r][4] = 0; $r++; + + $r++; + $this->const[$r][0] = "EXPEDITION_ADDON_PDF_ODT_PATH"; + $this->const[$r][1] = "chaine"; + $this->const[$r][2] = "DOL_DATA_ROOT/doctemplates/delivery"; + $this->const[$r][3] = ""; + $this->const[$r][4] = 0; // Boxes $this->boxes = array(); @@ -229,6 +243,24 @@ class modExpedition extends DolibarrModules // Permissions $this->remove($options); + + //ODT template + $src=DOL_DOCUMENT_ROOT.'/install/doctemplates/shipment/template_shipment.odt'; + $dirodt=DOL_DATA_ROOT.'/doctemplates/shipment'; + $dest=$dirodt.'/template_shipment.odt'; + + if (file_exists($src) && ! file_exists($dest)) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + dol_mkdir($dirodt); + $result=dol_copy($src,$dest,0,0); + if ($result < 0) + { + $langs->load("errors"); + $this->error=$langs->trans('ErrorFailToCopyFile',$src,$dest); + return 0; + } + } $sql = array(); diff --git a/htdocs/install/doctemplates/shipment/template_shipment.odt b/htdocs/install/doctemplates/shipment/template_shipment.odt new file mode 100644 index 0000000000000000000000000000000000000000..100afe5dac40738c940a936506829410a2e05243 GIT binary patch literal 25555 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 Date: Sun, 14 Jul 2013 16:35:02 +0200 Subject: [PATCH 02/13] Add option MAIN_GENERATE_DOCUMENT_WITH_PICTURE --- ChangeLog | 1 + htdocs/core/class/conf.class.php | 3 + htdocs/core/lib/pdf.lib.php | 24 ++-- .../modules/propale/doc/pdf_azur.modules.php | 132 ++++++++++-------- 4 files changed, 89 insertions(+), 71 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f2b10398e9..e586d1ac36a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -27,6 +27,7 @@ For users: - New: Add new graphical boxes (customer invoices and orders per month). - New: [ task #286 ] Enhance rounding function of prices to allow round of sum instead of sum of rounding. - New: Can add an event automatically when a projet is create. +- New: Add option MAIN_GENERATE_DOCUMENT_WITH_PICTURE. - Qual: Implement same rule for return value of all command line scripts (0 when success, <>0 if error). For translators: diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 4ce1bbf8c3d..2ed38d94e4a 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -396,6 +396,9 @@ class Conf if (! isset($this->global->MAIN_MAX_DECIMALS_TOT)) $this->global->MAIN_MAX_DECIMALS_TOT=2; if (! isset($this->global->MAIN_MAX_DECIMALS_SHOWN)) $this->global->MAIN_MAX_DECIMALS_SHOWN=8; + // Default pdf use dash between lines + if (! isset($this->global->MAIN_PDF_DASH_BETWEEN_LINES)) $this->global->MAIN_PDF_DASH_BETWEEN_LINES=1; + // Default max file size for upload $this->maxfilesize = (empty($this->global->MAIN_UPLOAD_DOC) ? 0 : $this->global->MAIN_UPLOAD_DOC * 1024); diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 61d247ff2c2..c895ea541d7 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -199,8 +199,8 @@ function pdf_getInstance($format='',$metric='mm',$pagetype='P') { $this->SetXY($x,$y); $val=str_replace('
',"\n",$html); - $val=dol_string_nohtmltag($val,false,'ISO-8859-1'); - //print 'eee'.$val;exit; + //$val=dol_string_nohtmltag($val,false,'ISO-8859-1'); + $val=dol_string_nohtmltag($val,false,'UTF-8'); $this->MultiCell($w,$h,$val,$border,$align,$fill); } } @@ -1554,25 +1554,29 @@ function pdf_getLinkedObjects($object,$outputlangs) } /** - * Return dimensions to use for images onto PDF + * Return dimensions to use for images onto PDF checking that width and height are not higher than + * maximum (16x32 by default). * * @param string $realpath Full path to photo file to use - * @return array Height/Width to use to output image (in pixel) + * @return array Height and width to use to output image (in pdf user unit, so mm) */ -function pdf_getHeightForImage($realpath) +function pdf_getSizeForImage($realpath) { - $maxheight=12; $maxwidth=16; + global $conf; + + $maxwidth=(empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH)?16:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_WIDTH); + $maxheight=(empty($conf->global->MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT)?32:$conf->global->MAIN_DOCUMENTS_WITH_PICTURE_HEIGHT); include_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php'; $tmp=dol_getImageSize($realpath); if ($tmp['height']) { - $width=(int) round($maxheight*$tmp['width']/$tmp['height']); - if ($width > $maxwidth) + $width=(int) round($maxheight*$tmp['width']/$tmp['height']); // I try to use maxheight + if ($width > $maxwidth) // Pb with maxheight, so i use maxwidth { - $height=(int) round($height*$maxwidth/$width); $width=$maxwidth; + $height=(int) round($maxwidth*$tmp['height']/$tmp['width']); } - else + else // No pb with maxheight { $height=$maxheight; } diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index caeb4c3be1d..cd916ae46a0 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -272,15 +272,76 @@ class pdf_azur extends ModelePDFPropales $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(); $realpath=''; + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITH_PICTURE)) + { + if ($object->lines[$i]->fk_product) + { + $objphoto = new Product($this->db); + $objphoto->fetch($object->lines[$i]->fk_product); + + $pdir = get_exdir($object->lines[$i]->fk_product,2) . $object->lines[$i]->fk_product ."/photos/"; + $dir = $conf->product->dir_output.'/'.$pdir; + + $realpath=''; + if ($object->ref == 'SPECIMEN' && $i == 1) + { + $realpath = DOL_DOCUMENT_ROOT.'/theme/common/nophoto.jpg'; + } + else + { + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + if ($obj['photo_vignette']) + { + $filename='thumbs/'.$obj['photo_vignette']; + } + else + { + $filename=$obj['photo']; + } + + $realpath = $dir.$filename; + break; + } + } + + if (!empty($realpath)) $imglinesize=pdf_getSizeForImage($realpath); + } + } + $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; + + // We start with Photo of product line + if (($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot))) // If photo to 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($pagenb+1); + + $curY = $tab_top_newpage; + $showpricebeforepagebreak=0; + } + + if (isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $curX = $this->posxpicture-1; + $pdf->Image($realpath, $curX + (($this->posxtva-$this->posxpicture-$imglinesize['width'])/2), $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 $curX = $this->posxdesc-1; - $showpricebeforepagebreak=1; - $pdf->startTransaction(); if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITH_PICTURE)) { @@ -329,6 +390,7 @@ class pdf_azur extends ModelePDFPropales { $pdf->commitTransaction(); } + $posYAfterDescription=$pdf->GetY(); $nexY = $pdf->GetY(); $pageposafter=$pdf->getPage(); @@ -336,67 +398,13 @@ class pdf_azur extends ModelePDFPropales $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 + // 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 - // Photo - if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITH_PICTURE)) - { - $curX = $this->posxpicture-1; - if ($object->lines[$i]->fk_product) - { - $objphoto = new Product($this->db); - $objphoto->fetch($object->lines[$i]->fk_product); - - $pdir = get_exdir($object->lines[$i]->fk_product,2) . $object->lines[$i]->fk_product ."/photos/"; - $dir = $conf->product->dir_output.'/'.$pdir; - - $realpath=''; - if ($object->ref == 'SPECIMEN') - { - $realpath = DOL_DOCUMENT_ROOT.'/theme/common/nophoto.jpg'; - } - else - { - foreach ($objphoto->liste_photos($dir,1) as $key => $obj) - { - if ($obj['photo_vignette']) - { - $filename='thumbs/'.$obj['photo_vignette']; - } - else - { - $filename=$obj['photo']; - } - - $realpath = $dir.$filename; - break; - } - } - - if (!empty($realpath)) - { - //$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); - $tmp=pdf_getHeightForImage($realpath); - //var_dump(constant('PDF_IMAGE_SCALE_RATIO'));var_dump($pdf->getImageScale());var_dump($tmp['width']);var_dump($pdf->pixelsToUnits($tmp['width']));exit; - // measures 1/72 of an inch, i.e. approximately 0.0139 inch or 25.4/72 = 0.3528 mm - var_dump($this->page_largeur);exit; - //var_dump(tmp['height']);exit; - $pdf->Line($this->posxtva,10,$this->posxtva+0.5,10); - $pdf->Image($realpath, $this->posxtva, 10, $tmp['width'], $tmp['height'],'','','',2,0); // Use 300 dpi - $pdf->Line($this->posxtva+$pdf->pixelsToUnits($tmp['width']),10,$this->posxtva+$pdf->pixelsToUnits($tmp['width'])+0.5,10); - $pdf->Image($realpath, $curX + ($this->posxtva-$this->posxpicture-($pdf->pixelsToUnits($tmp['width'])))/2, $curY-1, $tmp['width'], $tmp['height'],'','','',2, 300); // Use 300 dpi - //$nexY += 7; // +7 for height = 12 - $nexY += round($pdf->pixelsToUnits($tmp['height'])); - //var_dump($nexY);exit; - } - } - } - // VAT Rate if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) { @@ -459,6 +467,8 @@ class pdf_azur extends ModelePDFPropales if (! isset($this->tva[$vatrate])) $this->tva[$vatrate]=''; $this->tva[$vatrate] += $tvaligne; + if ($posYAfterImage > $posYAfterDescription) $nexY=$posYAfterImage; + // Add line if (! empty($conf->global->MAIN_PDF_DASH_BETWEEN_LINES) && $i < ($nblignes - 1)) { @@ -1063,7 +1073,7 @@ class pdf_azur extends ModelePDFPropales $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)); + 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, 6, 'F', null, explode(',',$conf->global->MAIN_PDF_TITLE_BACKGROUND_COLOR)); } $pdf->SetDrawColor(128,128,128); @@ -1074,7 +1084,7 @@ class pdf_azur extends ModelePDFPropales 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 + $pdf->line($this->marge_gauche, $tab_top+6, $this->page_largeur-$this->marge_droite, $tab_top+6); // line prend une position y en 2eme param et 4eme param $pdf->SetXY($this->posxdesc-1, $tab_top+1); $pdf->MultiCell(108,2, $outputlangs->transnoentities("Designation"),'','L'); @@ -1085,8 +1095,8 @@ class pdf_azur extends ModelePDFPropales $pdf->line($this->posxpicture-1, $tab_top, $this->posxpicture-1, $tab_top + $tab_height); if (empty($hidetop)) { - $pdf->SetXY($this->posxpicture-1, $tab_top+1); - $pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C'); + //$pdf->SetXY($this->posxpicture-1, $tab_top+1); + //$pdf->MultiCell($this->posxtva-$this->posxpicture-1,2, $outputlangs->transnoentities("Photo"),'','C'); } } From 001072d34c2346b93b41b2b22274b14121ec1975 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Jul 2013 18:43:58 +0200 Subject: [PATCH 03/13] Add option MAIN_GENERATE_DOCUMENT_WITH_PICTURE --- .../modules/propale/doc/pdf_azur.modules.php | 28 +++++-------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index cd916ae46a0..ce4c3d4d36f 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -285,29 +285,15 @@ class pdf_azur extends ModelePDFPropales $dir = $conf->product->dir_output.'/'.$pdir; $realpath=''; - if ($object->ref == 'SPECIMEN' && $i == 1) + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) { - $realpath = DOL_DOCUMENT_ROOT.'/theme/common/nophoto.jpg'; - } - else - { - foreach ($objphoto->liste_photos($dir,1) as $key => $obj) - { - if ($obj['photo_vignette']) - { - $filename='thumbs/'.$obj['photo_vignette']; - } - else - { - $filename=$obj['photo']; - } - - $realpath = $dir.$filename; - break; - } + $filename=$obj['photo']; + //if ($obj['photo_vignette']) $filename='thumbs/'.$obj['photo_vignette']; + $realpath = $dir.$filename; + break; } - if (!empty($realpath)) $imglinesize=pdf_getSizeForImage($realpath); + if (!empty($realpath)) $imglinesize=pdf_getSizeForImage($realpath); } } @@ -334,7 +320,7 @@ class pdf_azur extends ModelePDFPropales if (isset($imglinesize['width']) && isset($imglinesize['height'])) { $curX = $this->posxpicture-1; - $pdf->Image($realpath, $curX + (($this->posxtva-$this->posxpicture-$imglinesize['width'])/2), $curY, $imglinesize['width'], $imglinesize['height'],'','','',2, 300); // Use 300 dpi + $pdf->Image($realpath, $curX + (($this->posxtva-$this->posxpicture-$imglinesize['width'])/2), $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']; } From 08f8acc867af5a02d79207c9ceeb5ac84a8a617f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 00:41:27 +0200 Subject: [PATCH 04/13] More complete example --- htdocs/master.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/master.inc.php b/htdocs/master.inc.php index b39d5216218..a9bae9b8e72 100644 --- a/htdocs/master.inc.php +++ b/htdocs/master.inc.php @@ -84,7 +84,7 @@ if (! empty($dolibarr_main_document_root_alt)) print "\"/extensions\"
\n"; print "\"/extensions1,/extensions2,...\"
\n"; print "\"/../extensions\"
\n"; - print "\"/custom\"
\n"; + print "\"/dolibarr/custom\"
\n"; exit; } $conf->file->dol_url_root['alt'.($i++)]=(string) $value; From d637212dce98724fc9db3747a28c20e19385aba7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 00:58:40 +0200 Subject: [PATCH 05/13] Fix: alternative url were sometimes relative to server, sometimes to DOL_URL_ROOT. Fix to be always relative to DOL_URL_ROOT. --- htdocs/conf/conf.php.example | 11 ++++++++--- htdocs/core/lib/functions.lib.php | 2 +- htdocs/master.inc.php | 4 ++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example index 589cd212ef5..e0cee5e2719 100644 --- a/htdocs/conf/conf.php.example +++ b/htdocs/conf/conf.php.example @@ -37,8 +37,10 @@ $dolibarr_main_document_root=''; // dolibarr_main_url_root_alt -// This parameter defines the relative sub URLs of alternative Dolibarr root directories. -// It can be links to some other secondary htdocs directories, separated by a coma. +// This parameter defines the relative sub URLs to add to $dolibarr_main_url_root to +// forge alternative root directories (used by modules developers). +// You can put several values, separated by a coma, but number of entries must match +// number of entries into $dolibarr_main_document_root_alt. // Examples: // $dolibarr_main_url_root_alt='/extensions'; // $dolibarr_main_url_root_alt='/extensions1,/extensions2'; @@ -47,7 +49,10 @@ $dolibarr_main_url_root_alt=''; // dolibarr_main_document_root_alt -// This parameter contains absolute alternative root file system directories of Dolibarr +// This parameter contains absolute alternative root file system directories (used by +// modules developers). +// You can put several values, separated by a coma, but number of entries must match +// number of entries into $dolibarr_main_url_root_alt. // Examples: // $dolibarr_main_document_root_alt='/var/www/dolibarr/htdocs/extensions'; // $dolibarr_main_document_root_alt='C:/My web sites/dolibarr/htdocs/extensions1,C:/My web sites/dolibarr/htdocs/extensions2'; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 0767c13c9b1..1be018f61a9 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1729,7 +1729,7 @@ function img_picto($alt, $picto, $options = '', $pictoisfullpath = false, $srcon if ($type == 'main') continue; if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) { - $url=$conf->file->dol_url_root[$type]; + $url=DOL_URL_ROOT.$conf->file->dol_url_root[$type]; break; } } diff --git a/htdocs/master.inc.php b/htdocs/master.inc.php index a9bae9b8e72..161cb4aa30e 100644 --- a/htdocs/master.inc.php +++ b/htdocs/master.inc.php @@ -78,13 +78,13 @@ if (! empty($dolibarr_main_document_root_alt)) { if (preg_match('/^http(s)?:/',$value)) { - print 'Error: values for $dolibarr_main_url_root_alt into conf.php file must contains relative path to alternative URLs.
'."\n"; + print 'Error: values for $dolibarr_main_url_root_alt into conf.php file must contains relative path added to $dolibarr_main_url_root to get alternative URLs.
'."\n"; print "Found: \"".$value."\"
\n"; print "Should found something like following examples:
\n"; print "\"/extensions\"
\n"; print "\"/extensions1,/extensions2,...\"
\n"; print "\"/../extensions\"
\n"; - print "\"/dolibarr/custom\"
\n"; + print "\"/custom\"
\n"; exit; } $conf->file->dol_url_root['alt'.($i++)]=(string) $value; From 9d0fe3c1da979751eb610d06a3531f6ef536acf8 Mon Sep 17 00:00:00 2001 From: Florian Henry Date: Mon, 15 Jul 2013 09:33:26 +0200 Subject: [PATCH 06/13] Use reopen method to repoen proposal and fire trigger PROPAL_REOPEN --- htdocs/comm/propal.php | 2 +- htdocs/comm/propal/class/propal.class.php | 55 ++++++++++++++++++----- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index 09afbe57c34..155e2cc0e78 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -408,7 +408,7 @@ else if ($action == 'confirm_reopen' && $user->rights->propal->cloturer && ! GET // prevent browser refresh from reopening proposal several times if ($object->statut==2 || $object->statut==3) { - $object->setStatut(1); + $object->reopen($user,1); } } diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index f4c87387040..152ca164ed3 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1587,32 +1587,67 @@ class Propal extends CommonObject /** - * Close the commercial proposal + * Reopen the commercial proposal * * @param User $user Object user that close * @param int $statut Statut * @param text $note Comment + * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers * @return int <0 if KO, >0 if OK */ - function reopen($user, $statut, $note) + function reopen($user, $statut, $note, $notrigger=0) { global $langs,$conf; $this->statut = $statut; $error=0; - $now=dol_now(); - - $this->db->begin(); $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture=".$this->db->idate($now).", fk_user_cloture=".$user->id; + $sql.= " SET fk_statut = ".$statut.","; + if (! empty ( $note )) { + $sql .= " note_private = '" . $this->db->escape ( $note ) . "',"; + } + $sql.= " date_cloture=NULL, fk_user_cloture=NULL"; $sql.= " WHERE rowid = ".$this->id; - $resql=$this->db->query($sql); - if ($resql) - { + $this->db->begin(); - } + dol_syslog(get_class($this)."::reopen sql=".$sql, LOG_DEBUG); + $resql = $this->db->query($sql); + if (! $resql) { + $error++; $this->errors[]="Error ".$this->db->lasterror(); + } + if (! $error) + { + if (! $notrigger) + { + // Appel des triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('PROPAL_REOPEN',$this,$user,$langs,$conf); + if ($result < 0) { + $error++; $this->errors=$interface->errors; + } + // Fin appel triggers + } + } + + // Commit or rollback + if ($error) + { + foreach($this->errors as $errmsg) + { + dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR); + $this->error.=($this->error?', '.$errmsg:$errmsg); + } + $this->db->rollback(); + return -1*$error; + } + else + { + $this->db->commit(); + return 1; + } } From d09af2b18e2e0a06dc5ca132b662541a91509a6e Mon Sep 17 00:00:00 2001 From: Florian Henry Date: Mon, 15 Jul 2013 09:37:55 +0200 Subject: [PATCH 07/13] Better use of reopen method --- htdocs/comm/propal/class/propal.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 152ca164ed3..e3160dc61c9 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -1603,7 +1603,7 @@ class Propal extends CommonObject $error=0; $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql.= " SET fk_statut = ".$statut.","; + $sql.= " SET fk_statut = ".$this->statut.","; if (! empty ( $note )) { $sql .= " note_private = '" . $this->db->escape ( $note ) . "',"; } From 17f3d98fb3af3e509cb58c42cf641ccc69a4381c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 18:44:59 +0200 Subject: [PATCH 08/13] New: Add option to exclude some thirdparties --- htdocs/core/lib/invoice2.lib.php | 9 ++++++++- scripts/invoices/rebuild_merge_pdf.php | 12 +++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/htdocs/core/lib/invoice2.lib.php b/htdocs/core/lib/invoice2.lib.php index 52ff16d4964..7a90d55ad5c 100644 --- a/htdocs/core/lib/invoice2.lib.php +++ b/htdocs/core/lib/invoice2.lib.php @@ -43,9 +43,10 @@ require_once(DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'); * @param int $regenerate ''=Use existing PDF files, 'nameofpdf'=Regenerate all PDF files using the template * @param string $option Suffix to add into file name of generated PDF * @param string $paymentbankid Only if payment on this bank account id + * @param array $excludethirdpartiesid Exclude thirdparties from select * @return int Error code */ -function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate=0, $option='', $paymentbankid='') +function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate=0, $option='', $paymentbankid='', $excludethirdpartiesid='') { $sql = "SELECT DISTINCT f.rowid, f.facnumber"; $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; @@ -111,6 +112,12 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte else $sqlwhere.=" AND"; $sqlwhere.=' type <> 2'; } + if (in_array('excludethirdparties',$filter) && is_array($excludethirdpartiesid)) + { + if (empty($sqlwhere)) $sqlwhere=' WHERE '; + else $sqlwhere.=" AND"; + $sqlwhere.=' f.fk_soc NOT IN ('.join(',',$excludethirdpartiesid).')'; + } if ($sqlwhere) $sql.=$sqlwhere; if ($sqlorder) $sql.=$sqlorder; diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index 2bba8666e0c..d7b64bb92a4 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -183,6 +183,15 @@ foreach ($argv as $key => $value) print 'Exclude credit note invoices'."\n"; } + if ($value == 'filter=excludethirdparties') + { + $found=true; + $filter[]='excludethirdparties'; + + $excludethirdpartiesid=explode(',',$argv[$key+1]); + print 'Exclude thirdparties with id in list ('.join(',',$excludethirdpartiesid).").\n"; + } + if (! $found && preg_match('/filter=/i',$value)) { usage(); @@ -211,7 +220,7 @@ if (in_array('bank',$filter) && in_array('nopayment',$filter)) // Define SQL and SQL request to select invoices // Use $filter, $dateafterdate, datebeforedate, $paymentdateafter, $paymentdatebefore -$result=rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, 1, $regenerate, $option, $paymentonbankid); +$result=rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, 1, $regenerate, $option, $paymentonbankid, $excludethirdpartiesid); @@ -258,6 +267,7 @@ function usage() print "To exclude credit notes, use filter=nocreditnote\n"; print "To exclude replacement invoices, use filter=noreplacement\n"; print "To exclude deposit invoices, use filter=nodeposit\n"; + print "To exclude some thirdparties, use filter=excludethirdparties id1,id2...\n"; print "To regenerate existing PDF, use regenerate=crabe\n"; print "To generate invoices in a language, use lang=xx_XX\n"; print "\n"; From dd10ff8a11a599736aeb6ff2b1a9fbc1102dfa32 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 18:51:56 +0200 Subject: [PATCH 09/13] eol --- htdocs/core/lib/pdf.lib.php | 2 +- .../modules/propale/doc/pdf_azur.modules.php | 64 +++++++++---------- scripts/invoices/rebuild_merge_pdf.php | 14 ++-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index c895ea541d7..f22d35e7de1 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -1574,7 +1574,7 @@ function pdf_getSizeForImage($realpath) if ($width > $maxwidth) // Pb with maxheight, so i use maxwidth { $width=$maxwidth; - $height=(int) round($maxwidth*$tmp['height']/$tmp['width']); + $height=(int) round($maxwidth*$tmp['height']/$tmp['width']); } else // No pb with maxheight { diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index ce4c3d4d36f..ed501026c8a 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -273,29 +273,29 @@ class pdf_azur extends ModelePDFPropales $pdf->SetTextColor(0,0,0); // Define size of image if we need it - $imglinesize=array(); $realpath=''; - if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITH_PICTURE)) - { - if ($object->lines[$i]->fk_product) - { - $objphoto = new Product($this->db); - $objphoto->fetch($object->lines[$i]->fk_product); - - $pdir = get_exdir($object->lines[$i]->fk_product,2) . $object->lines[$i]->fk_product ."/photos/"; - $dir = $conf->product->dir_output.'/'.$pdir; - - $realpath=''; - foreach ($objphoto->liste_photos($dir,1) as $key => $obj) - { - $filename=$obj['photo']; + $imglinesize=array(); $realpath=''; + if (! empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITH_PICTURE)) + { + if ($object->lines[$i]->fk_product) + { + $objphoto = new Product($this->db); + $objphoto->fetch($object->lines[$i]->fk_product); + + $pdir = get_exdir($object->lines[$i]->fk_product,2) . $object->lines[$i]->fk_product ."/photos/"; + $dir = $conf->product->dir_output.'/'.$pdir; + + $realpath=''; + foreach ($objphoto->liste_photos($dir,1) as $key => $obj) + { + $filename=$obj['photo']; //if ($obj['photo_vignette']) $filename='thumbs/'.$obj['photo_vignette']; - $realpath = $dir.$filename; - break; - } - + $realpath = $dir.$filename; + break; + } + if (!empty($realpath)) $imglinesize=pdf_getSizeForImage($realpath); - } - } + } + } $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. @@ -308,23 +308,23 @@ class pdf_azur extends ModelePDFPropales // We start with Photo of product line if (($curY + $imglinesize['height']) > ($this->page_hauteur-($heightforfooter+$heightforfreetext+$heightforinfotot))) // If photo to 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->AddPage('','',true); + if (! empty($tplidx)) $pdf->useTemplate($tplidx); + if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs); $pdf->setPage($pagenb+1); $curY = $tab_top_newpage; - $showpricebeforepagebreak=0; - } + $showpricebeforepagebreak=0; + } - if (isset($imglinesize['width']) && isset($imglinesize['height'])) - { - $curX = $this->posxpicture-1; + if (isset($imglinesize['width']) && isset($imglinesize['height'])) + { + $curX = $this->posxpicture-1; $pdf->Image($realpath, $curX + (($this->posxtva-$this->posxpicture-$imglinesize['width'])/2), $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 $curX = $this->posxdesc-1; @@ -376,7 +376,7 @@ class pdf_azur extends ModelePDFPropales { $pdf->commitTransaction(); } - $posYAfterDescription=$pdf->GetY(); + $posYAfterDescription=$pdf->GetY(); $nexY = $pdf->GetY(); $pageposafter=$pdf->getPage(); diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index d7b64bb92a4..fca2a32ce13 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -183,13 +183,13 @@ foreach ($argv as $key => $value) print 'Exclude credit note invoices'."\n"; } - if ($value == 'filter=excludethirdparties') - { - $found=true; - $filter[]='excludethirdparties'; - - $excludethirdpartiesid=explode(',',$argv[$key+1]); - print 'Exclude thirdparties with id in list ('.join(',',$excludethirdpartiesid).").\n"; + if ($value == 'filter=excludethirdparties') + { + $found=true; + $filter[]='excludethirdparties'; + + $excludethirdpartiesid=explode(',',$argv[$key+1]); + print 'Exclude thirdparties with id in list ('.join(',',$excludethirdpartiesid).").\n"; } if (! $found && preg_match('/filter=/i',$value)) From 28c28bd21747e5eba0b9593945413c43390543d3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 20:56:43 +0200 Subject: [PATCH 10/13] New: Add option excludethirdparties and onlythirdparties into merge pdf scripts. --- ChangeLog | 1 + htdocs/core/lib/invoice2.lib.php | 14 ++++++++++---- scripts/invoices/rebuild_merge_pdf.php | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index e586d1ac36a..1de4a404620 100644 --- a/ChangeLog +++ b/ChangeLog @@ -28,6 +28,7 @@ For users: - New: [ task #286 ] Enhance rounding function of prices to allow round of sum instead of sum of rounding. - New: Can add an event automatically when a projet is create. - New: Add option MAIN_GENERATE_DOCUMENT_WITH_PICTURE. +- New: Add option excludethirdparties and onlythirdparties into merge pdf scripts. - Qual: Implement same rule for return value of all command line scripts (0 when success, <>0 if error). For translators: diff --git a/htdocs/core/lib/invoice2.lib.php b/htdocs/core/lib/invoice2.lib.php index 7a90d55ad5c..dcf98c9a70e 100644 --- a/htdocs/core/lib/invoice2.lib.php +++ b/htdocs/core/lib/invoice2.lib.php @@ -43,10 +43,10 @@ require_once(DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'); * @param int $regenerate ''=Use existing PDF files, 'nameofpdf'=Regenerate all PDF files using the template * @param string $option Suffix to add into file name of generated PDF * @param string $paymentbankid Only if payment on this bank account id - * @param array $excludethirdpartiesid Exclude thirdparties from select + * @param array $thirdpartiesid List of thirdparties id when using filter excludethirdpartiesid or onlythirdpartiesid * @return int Error code */ -function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate=0, $option='', $paymentbankid='', $excludethirdpartiesid='') +function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, $usestdout, $regenerate=0, $option='', $paymentbankid='', $thirdpartiesid='') { $sql = "SELECT DISTINCT f.rowid, f.facnumber"; $sql.= " FROM ".MAIN_DB_PREFIX."facture as f"; @@ -112,11 +112,17 @@ function rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filte else $sqlwhere.=" AND"; $sqlwhere.=' type <> 2'; } - if (in_array('excludethirdparties',$filter) && is_array($excludethirdpartiesid)) + if (in_array('excludethirdparties',$filter) && is_array($thirdpartiesid)) { if (empty($sqlwhere)) $sqlwhere=' WHERE '; else $sqlwhere.=" AND"; - $sqlwhere.=' f.fk_soc NOT IN ('.join(',',$excludethirdpartiesid).')'; + $sqlwhere.=' f.fk_soc NOT IN ('.join(',',$thirdpartiesid).')'; + } + if (in_array('onlythirdparties',$filter) && is_array($thirdpartiesid)) + { + if (empty($sqlwhere)) $sqlwhere=' WHERE '; + else $sqlwhere.=" AND"; + $sqlwhere.=' f.fk_soc IN ('.join(',',$thirdpartiesid).')'; } if ($sqlwhere) $sql.=$sqlwhere; if ($sqlorder) $sql.=$sqlorder; diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index fca2a32ce13..213c52c034f 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -188,8 +188,16 @@ foreach ($argv as $key => $value) $found=true; $filter[]='excludethirdparties'; - $excludethirdpartiesid=explode(',',$argv[$key+1]); - print 'Exclude thirdparties with id in list ('.join(',',$excludethirdpartiesid).").\n"; + $thirdpartiesid=explode(',',$argv[$key+1]); + print 'Exclude thirdparties with id in list ('.join(',',$thirdpartiesid).").\n"; + } + if ($value == 'filter=onlythirdparties') + { + $found=true; + $filter[]='onlythirdparties'; + + $thirdpartiesid=explode(',',$argv[$key+1]); + print 'Only thirdparties with id in list ('.join(',',$thirdpartiesid).").\n"; } if (! $found && preg_match('/filter=/i',$value)) @@ -220,7 +228,7 @@ if (in_array('bank',$filter) && in_array('nopayment',$filter)) // Define SQL and SQL request to select invoices // Use $filter, $dateafterdate, datebeforedate, $paymentdateafter, $paymentdatebefore -$result=rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, 1, $regenerate, $option, $paymentonbankid, $excludethirdpartiesid); +$result=rebuild_merge_pdf($db, $langs, $conf, $diroutputpdf, $newlangid, $filter, $dateafterdate, $datebeforedate, $paymentdateafter, $paymentdatebefore, 1, $regenerate, $option, $paymentonbankid, $thirdpartiesid); @@ -268,6 +276,7 @@ function usage() print "To exclude replacement invoices, use filter=noreplacement\n"; print "To exclude deposit invoices, use filter=nodeposit\n"; print "To exclude some thirdparties, use filter=excludethirdparties id1,id2...\n"; + print "To limit to some thirdparties, use filter=onlythirdparties id1,id2...\n"; print "To regenerate existing PDF, use regenerate=crabe\n"; print "To generate invoices in a language, use lang=xx_XX\n"; print "\n"; From 3e3af877bedf5582d5838d98245cf551b6595fa8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 21:30:11 +0200 Subject: [PATCH 11/13] Fix: File name not complete --- scripts/invoices/rebuild_merge_pdf.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index 213c52c034f..f42f2830445 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -186,6 +186,7 @@ foreach ($argv as $key => $value) if ($value == 'filter=excludethirdparties') { $found=true; + $option.=(empty($option)?'':'_').'excludethirdparties'.explode('-',$argv[$key+1]); $filter[]='excludethirdparties'; $thirdpartiesid=explode(',',$argv[$key+1]); @@ -194,6 +195,7 @@ foreach ($argv as $key => $value) if ($value == 'filter=onlythirdparties') { $found=true; + $option.=(empty($option)?'':'_').'onlythirdparty'.explode('-',$argv[$key+1]); $filter[]='onlythirdparties'; $thirdpartiesid=explode(',',$argv[$key+1]); From e4d28c81a77bea426a7aaa593c4ccebec32edc4d Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 21:33:54 +0200 Subject: [PATCH 12/13] Fix: Bad string --- scripts/invoices/rebuild_merge_pdf.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index f42f2830445..865adcfe336 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -186,20 +186,22 @@ foreach ($argv as $key => $value) if ($value == 'filter=excludethirdparties') { $found=true; - $option.=(empty($option)?'':'_').'excludethirdparties'.explode('-',$argv[$key+1]); $filter[]='excludethirdparties'; $thirdpartiesid=explode(',',$argv[$key+1]); print 'Exclude thirdparties with id in list ('.join(',',$thirdpartiesid).").\n"; + + $option.=(empty($option)?'':'_').'excludethirdparties'.join('-',$thirdpartiesid); } if ($value == 'filter=onlythirdparties') { $found=true; - $option.=(empty($option)?'':'_').'onlythirdparty'.explode('-',$argv[$key+1]); $filter[]='onlythirdparties'; $thirdpartiesid=explode(',',$argv[$key+1]); print 'Only thirdparties with id in list ('.join(',',$thirdpartiesid).").\n"; + + $option.=(empty($option)?'':'_').'onlythirdparty'.join('-',$thirdpartiesid); } if (! $found && preg_match('/filter=/i',$value)) From e2b63bb8dd12a899ef1c2f0b5763c511b73b8c68 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Jul 2013 21:47:45 +0200 Subject: [PATCH 13/13] Fix: Bad date ranges --- htdocs/core/lib/invoice2.lib.php | 4 ++-- scripts/invoices/rebuild_merge_pdf.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/core/lib/invoice2.lib.php b/htdocs/core/lib/invoice2.lib.php index dcf98c9a70e..5eed1e8e2df 100644 --- a/htdocs/core/lib/invoice2.lib.php +++ b/htdocs/core/lib/invoice2.lib.php @@ -37,8 +37,8 @@ require_once(DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'); * @param array $filter Array with filters * @param date $dateafterdate Invoice after date * @param date $datebeforedate Invoice before date - * @param date $paymentdateafter Payment after date - * @param date $paymentdatebefore Payment before date + * @param date $paymentdateafter Payment after date (must includes hour) + * @param date $paymentdatebefore Payment before date (must includes hour) * @param int $usestdout Add information onto standard output * @param int $regenerate ''=Use existing PDF files, 'nameofpdf'=Regenerate all PDF files using the template * @param string $option Suffix to add into file name of generated PDF diff --git a/scripts/invoices/rebuild_merge_pdf.php b/scripts/invoices/rebuild_merge_pdf.php index 865adcfe336..9646e808c37 100755 --- a/scripts/invoices/rebuild_merge_pdf.php +++ b/scripts/invoices/rebuild_merge_pdf.php @@ -112,7 +112,7 @@ foreach ($argv as $key => $value) $dateafterdate=dol_stringtotime($argv[$key+1]); $datebeforedate=dol_stringtotime($argv[$key+2]); - print 'Rebuild PDF for invoices validated between '.dol_print_date($dateafterdate,'day')." and ".dol_print_date($datebeforedate,'day').".\n"; + print 'Rebuild PDF for invoices validated between '.dol_print_date($dateafterdate,'day','gmt')." and ".dol_print_date($datebeforedate,'day','gmt').".\n"; } if ($value == 'filter=payments') @@ -121,14 +121,14 @@ foreach ($argv as $key => $value) $option.=(empty($option)?'':'_').'payments_'.$argv[$key+1].'_'.$argv[$key+2]; $filter[]='payments'; - $paymentdateafter=dol_stringtotime($argv[$key+1]); - $paymentdatebefore=dol_stringtotime($argv[$key+2]); + $paymentdateafter=dol_stringtotime($argv[$key+1].'000000'); + $paymentdatebefore=dol_stringtotime($argv[$key+2].'235959'); if (empty($paymentdateafter) || empty($paymentdatebefore)) { print 'Error: Bad date format or value'."\n"; exit(-1); } - print 'Rebuild PDF for invoices with at least one payment between '.dol_print_date($paymentdateafter,'day')." and ".dol_print_date($paymentdatebefore,'day').".\n"; + print 'Rebuild PDF for invoices with at least one payment between '.dol_print_date($paymentdateafter,'day','gmt')." and ".dol_print_date($paymentdatebefore,'day','gmt').".\n"; } if ($value == 'filter=nopayment')