diff --git a/htdocs/includes/modules/commande/pdf_einstein.modules.php b/htdocs/includes/modules/commande/pdf_einstein.modules.php index f12000a654c..747a44e1228 100644 --- a/htdocs/includes/modules/commande/pdf_einstein.modules.php +++ b/htdocs/includes/modules/commande/pdf_einstein.modules.php @@ -320,8 +320,8 @@ class pdf_einstein extends ModelePDFCommandes if($i < ($nblignes - 1)){ //on récupère la description du produit suivant $follow_descproduitservice = $com->lignes[$i+1]->desc; - //on compte le nombre de ligne afin de vérifier la place disponible - $nblineFollowDesc = (num_lines($follow_descproduitservice)*4); + //on compte le nombre de ligne afin de vérifier la place disponible (largeur de ligne 52 caracteres) + $nblineFollowDesc = (num_lines($follow_descproduitservice,52)*4); } else $nblineFollowDesc = 0; diff --git a/htdocs/includes/modules/facture/pdf_crabe.modules.php b/htdocs/includes/modules/facture/pdf_crabe.modules.php index 7f38c74e62c..85e0d2c5bc5 100644 --- a/htdocs/includes/modules/facture/pdf_crabe.modules.php +++ b/htdocs/includes/modules/facture/pdf_crabe.modules.php @@ -338,8 +338,8 @@ class pdf_crabe extends ModelePDFFactures if($i < ($nblignes - 1)){ //on récupère la description du produit suivant $follow_descproduitservice = $fac->lignes[$i+1]->desc; - //on compte le nombre de ligne afin de vérifier la place disponible - $nblineFollowDesc = (num_lines($follow_descproduitservice)*4); + //on compte le nombre de ligne afin de vérifier la place disponible (largeur de ligne 52 caracteres) + $nblineFollowDesc = (num_lines($follow_descproduitservice,52)*4); } else $nblineFollowDesc = 0; diff --git a/htdocs/includes/modules/propale/pdf_propale_azur.modules.php b/htdocs/includes/modules/propale/pdf_propale_azur.modules.php index 81ac63619d0..88de90c9fe3 100644 --- a/htdocs/includes/modules/propale/pdf_propale_azur.modules.php +++ b/htdocs/includes/modules/propale/pdf_propale_azur.modules.php @@ -1,985 +1,993 @@ - - * Copyright (C) 2005-2007 Regis Houssin - * Copyright (C) 2008 Raphael Bertrand (Resultic) - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * or see http://www.gnu.org/ - */ - -/** - \file htdocs/includes/modules/propale/pdf_propale_azur.modules.php - \ingroup propale - \brief Fichier de la classe permettant de générer les propales au modèle Azur - \author Laurent Destailleur - \version $Id$ - */ - -require_once(DOL_DOCUMENT_ROOT."/includes/modules/propale/modules_propale.php"); -require_once(DOL_DOCUMENT_ROOT."/product.class.php"); -require_once(DOL_DOCUMENT_ROOT."/lib/company.lib.php"); - - -/** - \class pdf_propale_azur - \brief Classe permettant de générer les propales au modèle Azur - */ - -class pdf_propale_azur extends ModelePDFPropales -{ - var $emetteur; // Objet societe qui emet - - - /** - \brief Constructeur - \param db Handler accès base de donnée - */ - function pdf_propale_azur($db) - { - global $conf,$langs,$mysoc; - - $langs->load("main"); - $langs->load("bills"); - - $this->db = $db; - $this->name = "azur"; - $this->description = $langs->trans('PDFAzurDescription'); - - // Dimension page pour format A4 - $this->type = 'pdf'; - $this->page_largeur = 210; - $this->page_hauteur = 297; - $this->format = array($this->page_largeur,$this->page_hauteur); - $this->marge_gauche=10; - $this->marge_droite=10; - $this->marge_haute=10; - $this->marge_basse=10; - - $this->option_logo = 1; // Affiche logo - $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION - $this->option_modereg = 1; // Affiche mode règlement - $this->option_condreg = 1; // Affiche conditions règlement - $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; // Gère les avoirs - $this->option_freetext = 1; // Support add of a personalised text - $this->option_draft_watermark = 1; //Support add of a watermark on drafts - - if (defined("FACTURE_TVAOPTION") && FACTURE_TVAOPTION == 'franchise') - $this->franchise=1; - - // Recupere emmetteur - $this->emetteur=$mysoc; - if (! $this->emetteur->pays_code) $this->emetteur->pays_code=substr($langs->defaultlang,-2); // Par defaut, si n'était pas défini - - // Defini position des colonnes - $this->posxdesc=$this->marge_gauche+1; - $this->posxtva=113; - $this->posxup=126; - $this->posxqty=145; - $this->posxdiscount=162; - $this->postotalht=174; - - $this->tva=array(); - $this->atleastoneratenotnull=0; - $this->atleastonediscount=0; - } - - /** - \brief Fonction générant la propale sur le disque - \param propale Objet propal à générer (ou id si ancienne methode) - \param outputlangs Lang object for output language - \return int 1=ok, 0=ko - */ - function write_file($propale,$outputlangs='') - { - global $user,$langs,$conf; - - if (! is_object($outputlangs)) $outputlangs=$langs; - $outputlangs->load("main"); - $outputlangs->load("dict"); - $outputlangs->load("companies"); - $outputlangs->load("bills"); - $outputlangs->load("propal"); - $outputlangs->load("products"); - - $outputlangs->setPhpLang(); - - if ($conf->propal->dir_output) - { - // Définition de l'objet $propale (pour compatibilite ascendante) - if (! is_object($propale)) - { - $id = $propale; - $propale = new Propal($this->db,"",$id); - $ret=$propale->fetch($id); - } - $deja_regle = ""; - - // Définition de $dir et $file - if ($propale->specimen) - { - $dir = $conf->propal->dir_output; - $file = $dir . "/SPECIMEN.pdf"; - } - else - { - $propref = sanitize_string($propale->ref); - $dir = $conf->propal->dir_output . "/" . $propref; - $file = $dir . "/" . $propref . ".pdf"; - } - - if (! file_exists($dir)) - { - if (create_exdir($dir) < 0) - { - $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); - return 0; - } - } - - if (file_exists($dir)) - { - $nblignes = sizeof($propale->lignes); - - // Protection et encryption du pdf - if ($conf->global->PDF_SECURITY_ENCRYPTION) - { - $pdf=new FPDI_Protection('P','mm',$this->format); - $pdfrights = array('print'); // Ne permet que l'impression du document - $pdfuserpass = ''; // Mot de passe pour l'utilisateur final - $pdfownerpass = NULL; // Mot de passe du propriétaire, créé aléatoirement si pas défini - $pdf->SetProtection($pdfrights,$pdfuserpass,$pdfownerpass); - } - else - { - $pdf=new FPDI('P','mm',$this->format); - } - - $pdf->Open(); - $pdf->AddPage(); - - $pdf->SetDrawColor(128,128,128); - - $pdf->SetTitle($propale->ref); - $pdf->SetSubject($outputlangs->transnoentities("CommercialProposal")); - $pdf->SetCreator("Dolibarr ".DOL_VERSION); - $pdf->SetAuthor($user->fullname); - - $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right - $pdf->SetAutoPageBreak(1,0); - - // Positionne $this->atleastonediscount si on a au moins une remise - for ($i = 0 ; $i < $nblignes ; $i++) - { - if ($propale->lignes[$i]->remise_percent) - { - $this->atleastonediscount++; - } - } - - // Tete de page - $this->_pagehead($pdf, $propale, 1, $outputlangs); - - $pagenb = 1; - $tab_top = 90; - $tab_top_newpage = 50; - $tab_height = 110; - $tab_height_newpage = 150; - $tab_height_middlepage = 190; - - // Affiche notes - if ($propale->note_public) - { - $tab_top = 88; - - $pdf->SetFont('Arial','', 9); // Dans boucle pour gérer multi-page - $pdf->SetXY ($this->posxdesc-1, $tab_top); - $pdf->MultiCell(190, 3, $propale->note_public, 0, 'J'); - $nexY = $pdf->GetY(); - $height_note=$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_note+1); - - $tab_height = $tab_height - $height_note; - $tab_top = $nexY+6; - } - else - { - $height_note=0; - } - - $iniY = $tab_top + 8; - $curY = $tab_top + 8; - $nexY = $tab_top + 8; - - // Boucle sur les lignes - for ($i = 0 ; $i < $nblignes ; $i++) - { - $curY = $nexY; - - // Description de la ligne produit - $libelleproduitservice=dol_htmlentitiesbr($propale->lignes[$i]->libelle,1); - if ($propale->lignes[$i]->desc && $propale->lignes[$i]->desc!=$propale->lignes[$i]->libelle) - { - if ($libelleproduitservice) $libelleproduitservice.="
"; - - if ($propale->lignes[$i]->desc == '(CREDIT_NOTE)' && $propale->lignes[$i]->fk_remise_except) - { - $discount=new DiscountAbsolute($this->db); - $discount->fetch($propale->lignes[$i]->fk_remise_except); - $libelleproduitservice=dol_htmlentitiesbr($langs->trans("DiscountFromCreditNote",$discount->ref_facture_source),1); - } - else - { - $libelleproduitservice.=dol_htmlentitiesbr($propale->lignes[$i]->desc,1); - } - } - // Si ligne associée à un code produit - if ($propale->lignes[$i]->fk_product) - { - $prodser = new Product($this->db); - $prodser->fetch($propale->lignes[$i]->fk_product); - - // On ajoute la ref - if ($prodser->ref) - { - $prefix_prodserv = ""; - if($prodser->isservice()) - $prefix_prodserv = $outputlangs->transnoentities("Service")." "; - else - $prefix_prodserv = $outputlangs->transnoentities("Product")." "; - - $libelleproduitservice=$prefix_prodserv.$prodser->ref." - ".$libelleproduitservice; - } - - } - if ($propale->lignes[$i]->date_start && $propale->lignes[$i]->date_end) - { - // Affichage durée si il y en a une - $libelleproduitservice.="
".dol_htmlentitiesbr("(".$outputlangs->transnoentities("From")." ".dolibarr_print_date($propale->lignes[$i]->date_start)." ".$outputlangs->transnoentities("to")." ".dolibarr_print_date($propale->lignes[$i]->date_end).")",1); - } - - $pdf->SetFont('Arial','', 9); // Dans boucle pour gérer multi-page - - // Description - $pdf->writeHTMLCell($this->posxtva-$this->posxdesc-1, 3, $this->posxdesc-1, $curY, $libelleproduitservice, 0, 1); - - $pdf->SetFont('Arial','', 9); // On repositionne la police par défaut - $nexY = $pdf->GetY(); - - // TVA - $pdf->SetXY ($this->posxtva, $curY); - $pdf->MultiCell($this->posxup-$this->posxtva-1, 3, vatrate($propale->lignes[$i]->tva_tx,1,$propale->lignes[$i]->info_bits), 0, 'R'); - - // Prix unitaire HT avant remise - $pdf->SetXY ($this->posxup, $curY); - $pdf->MultiCell($this->posxqty-$this->posxup-1, 3, price($propale->lignes[$i]->subprice), 0, 'R', 0); - - // Quantity - $pdf->SetXY ($this->posxqty, $curY); - if ($propale->lignes[$i]->special_code != 3) $pdf->MultiCell($this->posxdiscount-$this->posxqty-1, 4, $propale->lignes[$i]->qty, 0, 'R'); - - // Remise sur ligne - $pdf->SetXY ($this->posxdiscount, $curY); - if ($propale->lignes[$i]->remise_percent && $propale->lignes[$i]->special_code != 3) - { - $pdf->MultiCell($this->postotalht-$this->posxdiscount-1, 4, dolibarr_print_reduction($propale->lignes[$i]->remise_percent), 0, 'R'); - } - - // Total HT ligne - $pdf->SetXY ($this->postotalht, $curY); - if ($propale->lignes[$i]->special_code == 3) - { - // Ligne produit en option - $pdf->MultiCell(26, 4, $outputlangs->transnoentities("Option"), 0, 'R', 0); - } - else - { - $total = price($propale->lignes[$i]->total_ht); - $pdf->MultiCell(26, 4, $total, 0, 'R', 0); - } - - // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva - $tvaligne=$propale->lignes[$i]->total_tva; - if ($propale->remise_percent) $tvaligne-=($tvaligne*$propale->remise_percent)/100; - $vatrate=(string) $propale->lignes[$i]->tva_tx; - if ($propale->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; - $this->tva[$vatrate] += $tvaligne; - - $nexY+=2; // Passe espace entre les lignes - - //on récupère la description du produit suivant - $follow_descproduitservice = $propale->lignes[$i+1]->desc; - //on compte le nombre de ligne afin de vérifier la place disponible - $nblineFollowDesc = (num_lines($follow_descproduitservice)*4); - - if (($nexY+$nblineFollowDesc) > ($tab_top+$tab_height) && $i < ($nblignes - 1)) - { - if ($pagenb == 1) - { - $this->_tableau($pdf, $tab_top, $tab_height_newpage, $nexY, $outputlangs); - } - else - { - $this->_tableau($pdf, $tab_top_newpage, $tab_height_middlepage, $nexY, $outputlangs); - } - - $this->_pagefoot($pdf,$outputlangs); - - // Nouvelle page - $pdf->AddPage(); - $pagenb++; - $this->_pagehead($pdf, $propale, 0, $outputlangs); - - $nexY = $tab_top_newpage + 8; - $pdf->SetTextColor(0,0,0); - $pdf->SetFont('Arial','', 10); - } - - } - - // Affiche cadre tableau - if ($pagenb == 1) - { - $this->_tableau($pdf, $tab_top, $tab_height, $nexY, $outputlangs); - $bottomlasttab=$tab_top + $tab_height + 1; - } - else - { - $this->_tableau($pdf, $tab_top_newpage, $tab_height_newpage, $nexY, $outputlangs); - $bottomlasttab=$tab_top_newpage + $tab_height_newpage + 1; - } - - // Affiche zone infos - $posy=$this->_tableau_info($pdf, $propale, $bottomlasttab, $outputlangs); - - // Affiche zone totaux - $posy=$this->_tableau_tot($pdf, $propale, $deja_regle, $bottomlasttab, $outputlangs); - - // Affiche zone versements - if ($deja_regle) - { - $posy=$this->_tableau_versements($pdf, $propale, $posy, $outputlangs); - } - - // Pied de page - $this->_pagefoot($pdf,$outputlangs); - $pdf->AliasNbPages(); - - $pdf->Close(); - - $pdf->Output($file); - - $langs->setPhpLang(); // On restaure langue session - return 1; // Pas d'erreur - } - else - { - $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); - $langs->setPhpLang(); // On restaure langue session - return 0; - } - } - else - { - $this->error=$langs->trans("ErrorConstantNotDefined","PROP_OUTPUTDIR"); - $langs->setPhpLang(); // On restaure langue session - return 0; - } - - $this->error=$langs->trans("ErrorUnknown"); - $langs->setPhpLang(); // On restaure langue session - return 0; // Erreur par defaut - } - - /* - * \brief Affiche tableau des versement - * \param pdf Objet PDF - * \param object Objet propale - */ - function _tableau_versements(&$pdf, $object, $posy, $outputlangs) - { - - } - - - /* - * \brief Affiche infos divers - * \param pdf Objet PDF - * \param object Objet propale - * \param posy Position depart - * \param outputlangs Objet langs - * \return y Position pour suite - */ - function _tableau_info(&$pdf, $object, $posy, $outputlangs) - { - global $conf; - - $pdf->SetFont('Arial','', 9); - - /* - * If France, show VAT mention if not applicable - */ - if ($this->emetteur->pays_code == 'FR' && $this->franchise == 1) - { - $pdf->SetFont('Arial','B',8); - $pdf->SetXY($this->marge_gauche, $posy); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); - - $posy=$pdf->GetY()+4; - } - - /* - * Conditions de reglements - */ - if ($object->cond_reglement_code || $object->cond_reglement) - { - $pdf->SetFont('Arial','B',8); - $pdf->SetXY($this->marge_gauche, $posy); - $titre = $outputlangs->transnoentities("PaymentConditions").':'; - $pdf->MultiCell(80, 5, $titre, 0, 'L'); - - $pdf->SetFont('Arial','',8); - $pdf->SetXY(50, $posy); - $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$object->cond_reglement; - $pdf->MultiCell(80, 5, $lib_condition_paiement,0,'L'); - - $posy=$pdf->GetY()+3; - } - - /* - * Check si absence mode reglement - */ - if (! $conf->global->FACTURE_CHQ_NUMBER && ! $conf->global->FACTURE_RIB_NUMBER) - { - $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetTextColor(200,0,0); - $pdf->SetFont('Arial','B',8); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0); - $pdf->SetTextColor(0,0,0); - - $posy=$pdf->GetY()+1; - } - - /* - * Propose mode reglement par CHQ - */ - if (! $object->mode_reglement_code || $object->mode_reglement_code == 'CHQ') - { - // Si mode reglement non force ou si force a CHQ - if ($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('Arial','B',8); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio).':',0,'L',0); - $posy=$pdf->GetY()+1; - - $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('Arial','',8); - $pdf->MultiCell(80, 3, $account->adresse_proprio, 0, 'L', 0); - - $posy=$pdf->GetY()+2; - } - if ($conf->global->FACTURE_CHQ_NUMBER == -1) - { - $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('Arial','B',8); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByChequeOrderedToShort').' '.$this->emetteur->nom.' '.$outputlangs->transnoentities('SendTo').':',0,'L',0); - $posy=$pdf->GetY()+1; - - $pdf->SetXY($this->marge_gauche, $posy); - $pdf->SetFont('Arial','',8); - $pdf->MultiCell(80, 6, $this->emetteur->adresse_full, 0, 'L', 0); - - $posy=$pdf->GetY()+2; - } - } - } - - /* - * Propose mode reglement par RIB - */ - if (! $object->mode_reglement_code || $object->mode_reglement_code == 'VIR') - { - // Si mode reglement non force ou si force a VIR - if ($conf->global->FACTURE_RIB_NUMBER) - { - if ($conf->global->FACTURE_RIB_NUMBER) - { - $account = new Account($this->db); - $account->fetch($conf->global->FACTURE_RIB_NUMBER); - - $this->marges['g']=$this->marge_gauche; - - $cury=$posy; - $pdf->SetXY ($this->marges['g'], $cury); - $pdf->SetFont('Arial','B',8); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByTransferOnThisBankAccount').':', 0, 'L', 0); - $cury+=4; - $pdf->SetFont('Arial','B',6); - $pdf->line($this->marges['g']+1, $cury, $this->marges['g']+1, $cury+10 ); - $pdf->SetXY ($this->marges['g'], $cury); - $pdf->MultiCell(18, 3, $outputlangs->transnoentities("BankCode"), 0, 'C', 0); - $pdf->line($this->marges['g']+18, $cury, $this->marges['g']+18, $cury+10 ); - $pdf->SetXY ($this->marges['g']+18, $cury); - $pdf->MultiCell(18, 3, $outputlangs->transnoentities("DeskCode"), 0, 'C', 0); - $pdf->line($this->marges['g']+36, $cury, $this->marges['g']+36, $cury+10 ); - $pdf->SetXY ($this->marges['g']+36, $cury); - $pdf->MultiCell(24, 3, $outputlangs->transnoentities("BankAccountNumber"), 0, 'C', 0); - $pdf->line($this->marges['g']+60, $cury, $this->marges['g']+60, $cury+10 ); - $pdf->SetXY ($this->marges['g']+60, $cury); - $pdf->MultiCell(13, 3, $outputlangs->transnoentities("BankAccountNumberKey"), 0, 'C', 0); - $pdf->line($this->marges['g']+73, $cury, $this->marges['g']+73, $cury+10 ); - - $pdf->SetFont('Arial','',8); - $pdf->SetXY ($this->marges['g'], $cury+5); - $pdf->MultiCell(18, 3, $account->code_banque, 0, 'C', 0); - $pdf->SetXY ($this->marges['g']+18, $cury+5); - $pdf->MultiCell(18, 3, $account->code_guichet, 0, 'C', 0); - $pdf->SetXY ($this->marges['g']+36, $cury+5); - $pdf->MultiCell(24, 3, $account->number, 0, 'C', 0); - $pdf->SetXY ($this->marges['g']+60, $cury+5); - $pdf->MultiCell(13, 3, $account->cle_rib, 0, 'C', 0); - - $pdf->SetXY ($this->marges['g'], $cury+12); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities("Residence").' : ' . $account->domiciliation, 0, 'L', 0); - $pdf->SetXY ($this->marges['g'], $cury+22); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities("IbanPrefix").' : ' . $account->iban_prefix, 0, 'L', 0); - $pdf->SetXY ($this->marges['g'], $cury+25); - $pdf->MultiCell(90, 3, $outputlangs->transnoentities("BIC").' : ' . $account->bic, 0, 'L', 0); - - $posy=$pdf->GetY()+2; - } - } - } - - return $posy; - } - - - /* - * \brief Affiche le total a payer - * \param pdf Objet PDF - * \param object Objet propale - * \param deja_regle Montant deja regle - * \param posy Position depart - * \param outputlangs Objet langs - * \return y Position pour suite - */ - function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) - { - $tab2_top = $posy; - $tab2_hl = 5; - $tab2_height = $tab2_hl * 4; - $pdf->SetFont('Arial','', 9); - - // Tableau total - $lltot = 200; $col1x = 120; $col2x = 182; $largcol2 = $lltot - $col2x; - - // 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); - - $pdf->SetXY ($col2x, $tab2_top + 0); - $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ht + $object->remise), 0, 'R', 1); - - $index = 0; - - // Affichage des totaux de TVA par taux (conformément à réglementation) - $pdf->SetFillColor(248,248,248); - foreach( $this->tva as $tvakey => $tvaval ) - { - if ($tvakey) // On affiche pas taux 0 - { - $this->atleastoneratenotnull++; - - $index++; - $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); - - $tvacompl=''; - if (eregi('\*',$tvakey)) - { - $tvakey=eregi_replace('\*','',$tvakey); - $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; - } - $totalvat =$outputlangs->transnoentities("TotalVAT").' '; - $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, 'R', 1); - } - } - if (! $this->atleastoneratenotnull) // If not vat at all - { - $index++; - $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalVAT"), 0, 'L', 1); - - $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_tva), 0, 'R', 1); - } - - $useborder=0; - - $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($object->total_ttc), $useborder, 'R', 1); - $pdf->SetTextColor(0,0,0); - - if ($deja_regle > 0) - { - $index++; - - $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPayed"), 0, 'L', 0); - - $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle), 0, 'R', 0); - - $resteapayer = $object->total_ttc - $deja_regle; - if ($object->paye) $resteapayer=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("EscompteOffered"), $useborder, 'L', 1); - - $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle), $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), $useborder, 'R', 1); - - // Fin - $pdf->SetFont('Arial','', 9); - $pdf->SetTextColor(0,0,0); - } - - $index++; - return ($tab2_top + ($tab2_hl * $index)); - } - - /** - * \brief Affiche la grille des lignes de propales - * \param pdf objet PDF - */ - function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs) - { - global $conf; - - // Montants exprimés en (en tab_top - 1) - $pdf->SetTextColor(0,0,0); - $pdf->SetFont('Arial','',8); - $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentities("Currency".$conf->monnaie)); - $pdf->Text($this->page_largeur - $this->marge_droite - $pdf->GetStringWidth($titre), $tab_top-1, $titre); - - $pdf->SetDrawColor(128,128,128); - - // Rect prend une longueur en 3eme param - $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height); - // line prend une position y en 3eme param - $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); - - $pdf->SetFont('Arial','',9); - - $pdf->SetXY ($this->posxdesc-1, $tab_top+2); - $pdf->MultiCell(108,2, $outputlangs->transnoentities("Designation"),'','L'); - - $pdf->line($this->posxtva-1, $tab_top, $this->posxtva-1, $tab_top + $tab_height); - $pdf->SetXY ($this->posxtva-1, $tab_top+2); - $pdf->MultiCell($this->posxup-$this->posxtva-1,2, $outputlangs->transnoentities("VAT"),'','C'); - - $pdf->line($this->posxup-1, $tab_top, $this->posxup-1, $tab_top + $tab_height); - $pdf->SetXY ($this->posxup-1, $tab_top+2); - $pdf->MultiCell(18,2, $outputlangs->transnoentities("PriceUHT"),'','C'); - - $pdf->line($this->posxqty-1, $tab_top, $this->posxqty-1, $tab_top + $tab_height); - $pdf->SetXY ($this->posxqty-1, $tab_top+2); - $pdf->MultiCell($this->posxdiscount-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); - - $pdf->line($this->posxdiscount-1, $tab_top, $this->posxdiscount-1, $tab_top + $tab_height); - if ($this->atleastonediscount) - { - $pdf->SetXY ($this->posxdiscount-1, $tab_top+2); - $pdf->MultiCell(14,2, $outputlangs->transnoentities("ReductionShort"),'','C'); - } - - if ($this->atleastonediscount) - { - $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height); - } - $pdf->SetXY ($this->postotalht-1, $tab_top+2); - $pdf->MultiCell(28,2, $outputlangs->transnoentities("TotalHT"),'','C'); - - } - - /* - * \brief Affiche en-tête propale - * \param pdf Objet PDF - * \param object Objet propale - * \param showadress 0=non, 1=oui - * \param outputlang Objet lang cible - */ - function _pagehead(&$pdf, $object, $showadress=1, $outputlangs) - { - global $conf,$langs; - - $outputlangs->load("main"); - $outputlangs->load("bills"); - $outputlangs->load("propal"); - $outputlangs->load("companies"); - - //Affiche le filigrane brouillon - Print Draft Watermark - if($object->statut==0 && (! empty($conf->global->PROPALE_DRAFT_WATERMARK)) ) - { - $watermark_angle=atan($this->page_hauteur/$this->page_largeur); - $watermark_x=5; - $watermark_y=$this->page_hauteur-25; //Set to $this->page_hauteur-50 or less if problems - $watermark_width=$this->page_hauteur; - $pdf->SetFont('Arial','B',50); - $pdf->SetTextColor(255,192,203); - //rotate - $pdf->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',cos($watermark_angle),sin($watermark_angle),-sin($watermark_angle),cos($watermark_angle),$watermark_x*$pdf->k,($pdf->h-$watermark_y)*$pdf->k,-$watermark_x*$pdf->k,-($pdf->h-$watermark_y)*$pdf->k)); - //print watermark - $pdf->SetXY($watermark_x,$watermark_y); - $pdf->Cell($watermark_width,25,clean_html($conf->global->PROPALE_DRAFT_WATERMARK),0,2,"C",0); - //antirotate - $pdf->_out('Q'); - } - - //Prepare la suite - $pdf->SetTextColor(0,0,60); - $pdf->SetFont('Arial','B',13); - - $posy=$this->marge_haute; - - $pdf->SetXY($this->marge_gauche,$posy); - - // Logo - $logo=$conf->societe->dir_logos.'/'.$this->emetteur->logo; - if ($this->emetteur->logo) - { - if (is_readable($logo)) - { - $pdf->Image($logo, $this->marge_gauche, $posy, 0, 24); - } - else - { - $pdf->SetTextColor(200,0,0); - $pdf->SetFont('Arial','B',8); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); - } - } - else if (defined("FAC_PDF_INTITULE")) - { - $pdf->MultiCell(100, 4, FAC_PDF_INTITULE, 0, 'L'); - } - - $pdf->SetFont('Arial','B',13); - $pdf->SetXY(100,$posy); - $pdf->SetTextColor(0,0,60); - $title=$outputlangs->transnoentities("CommercialProposal"); - $pdf->MultiCell(100, 4, $title, '' , 'R'); - - $pdf->SetFont('Arial','B',12); - - $posy+=6; - $pdf->SetXY(100,$posy); - $pdf->SetTextColor(0,0,60); - $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $object->ref, '', 'R'); - - $posy+=1; - $pdf->SetFont('Arial','',10); - - $posy+=5; - $pdf->SetXY(100,$posy); - $pdf->SetTextColor(0,0,60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Date")." : " . dolibarr_print_date($object->date,"day"), '', 'R'); - - $posy+=5; - $pdf->SetXY(100,$posy); - $pdf->SetTextColor(0,0,60); - $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : " . dolibarr_print_date($object->fin_validite,"day"), '', 'R'); - - if ($showadress) - { - // Emetteur - $posy=42; - $hautcadre=40; - $pdf->SetTextColor(0,0,0); - $pdf->SetFont('Arial','',8); - $pdf->SetXY($this->marge_gauche,$posy-5); - $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":"); - - - $pdf->SetXY($this->marge_gauche,$posy); - $pdf->SetFillColor(230,230,230); - $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1); - - - $pdf->SetXY($this->marge_gauche+2,$posy+3); - - // Nom emetteur - $pdf->SetTextColor(0,0,60); - $pdf->SetFont('Arial','B',11); - if (defined("FAC_PDF_SOCIETE_NOM") && FAC_PDF_SOCIETE_NOM) $pdf->MultiCell(80, 4, FAC_PDF_SOCIETE_NOM, 0, 'L'); - else $pdf->MultiCell(80, 4, $this->emetteur->nom, 0, 'L'); - - // Caractéristiques emetteur - $carac_emetteur = ''; - if (defined("FAC_PDF_ADRESSE") && FAC_PDF_ADRESSE) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).FAC_PDF_ADRESSE; - else { - $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$this->emetteur->adresse; - $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$this->emetteur->cp.' '.$this->emetteur->ville; - } - $carac_emetteur .= "\n"; - // Tel - if (defined("FAC_PDF_TEL") && FAC_PDF_TEL) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ".FAC_PDF_TEL; - elseif ($this->emetteur->tel) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ".$this->emetteur->tel; - // Fax - if (defined("FAC_PDF_FAX") && FAC_PDF_FAX) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".FAC_PDF_FAX; - elseif ($this->emetteur->fax) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".$this->emetteur->fax; - // EMail - if (defined("FAC_PDF_MEL") && FAC_PDF_MEL) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".FAC_PDF_MEL; - elseif ($this->emetteur->email) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".$this->emetteur->email; - // Web - if (defined("FAC_PDF_WWW") && FAC_PDF_WWW) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".FAC_PDF_WWW; - elseif ($this->emetteur->url) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".$this->emetteur->url; - - $pdf->SetFont('Arial','',9); - $pdf->SetXY($this->marge_gauche+2,$posy+8); - $pdf->MultiCell(80,4, $carac_emetteur); - - // Client destinataire - $posy=42; - $pdf->SetTextColor(0,0,0); - $pdf->SetFont('Arial','',8); - $pdf->SetXY(102,$posy-5); - $pdf->MultiCell(80,5, $outputlangs->transnoentities("BillTo").":"); - $object->fetch_client(); - - // Cadre client destinataire - $pdf->rect(100, $posy, 100, $hautcadre); - - // If BILLING contact defined on invoice, we use it - $usecontact=false; - if ($conf->global->PROPALE_USE_CUSTOMER_CONTACT_AS_RECIPIENT) - { - $arrayidcontact=$object->getIdContact('external','CUSTOMER'); - if (sizeof($arrayidcontact) > 0) - { - $usecontact=true; - $result=$object->fetch_contact($arrayidcontact[0]); - } - } - - if ($usecontact) - { - // Nom societe - $pdf->SetXY(102,$posy+3); - $pdf->SetFont('Arial','B',11); - $pdf->MultiCell(96,4, $object->client->nom, 0, 'L'); - - // Nom client - $carac_client = "\n".$object->contact->getFullName($outputlangs,1,1); - - // Caractéristiques client - $carac_client.="\n".$object->contact->adresse; - $carac_client.="\n".$object->contact->cp . " " . $object->contact->ville."\n"; - //Pays si different de l'emetteur - if ($this->emetteur->pays_code != $object->contact->pays_code) - { - $carac_client.=dol_entity_decode($object->contact->pays)."\n"; - } - } - else - { - // Nom client - $pdf->SetXY(102,$posy+3); - $pdf->SetFont('Arial','B',11); - $pdf->MultiCell(96,4, $object->client->nom, 0, 'L'); - - // Nom du contact suivi propal si c'est une société - $arrayidcontact = $object->getIdContact('external','CUSTOMER'); - if (sizeof($arrayidcontact) > 0) - { - $object->fetch_contact($arrayidcontact[0]); - // On vérifie si c'est une société ou un particulier - if( !preg_match('#'.$object->contact->getFullName($outputlangs,1).'#isU',$object->client->nom) ) - { - $carac_client .= "\n".$object->contact->getFullName($outputlangs,1,1); - } - } - - // Caractéristiques client - $carac_client.="\n".$object->client->adresse; - $carac_client.="\n".$object->client->cp . " " . $object->client->ville."\n"; - - //Pays si different de l'emetteur - if ($this->emetteur->pays_code != $object->client->pays_code) - { - $carac_client.=dol_entity_decode($object->client->pays)."\n"; - } - } - // Numéro TVA intracom - if ($object->client->tva_intra) $carac_client.="\n".$outputlangs->transnoentities("VATIntraShort").': '.$object->client->tva_intra; - $pdf->SetFont('Arial','',9); - $posy=$pdf->GetY()-9; //Auto Y coord readjust for multiline name - $pdf->SetXY(102,$posy+6); - $pdf->MultiCell(86,4, $carac_client); - } - } - - /* - * \brief Affiche le pied de page - * \param pdf objet PDF - */ - function _pagefoot(&$pdf,$outputlangs) - { - return pdf_pagefoot($pdf,$outputlangs,'PROPALE_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur); - } - -} - -?> + + * Copyright (C) 2005-2007 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand (Resultic) + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * or see http://www.gnu.org/ + */ + +/** + \file htdocs/includes/modules/propale/pdf_propale_azur.modules.php + \ingroup propale + \brief Fichier de la classe permettant de générer les propales au modèle Azur + \author Laurent Destailleur + \version $Id$ + */ + +require_once(DOL_DOCUMENT_ROOT."/includes/modules/propale/modules_propale.php"); +require_once(DOL_DOCUMENT_ROOT."/product.class.php"); +require_once(DOL_DOCUMENT_ROOT."/lib/company.lib.php"); + + +/** + \class pdf_propale_azur + \brief Classe permettant de générer les propales au modèle Azur + */ + +class pdf_propale_azur extends ModelePDFPropales +{ + var $emetteur; // Objet societe qui emet + + + /** + \brief Constructeur + \param db Handler accès base de donnée + */ + function pdf_propale_azur($db) + { + global $conf,$langs,$mysoc; + + $langs->load("main"); + $langs->load("bills"); + + $this->db = $db; + $this->name = "azur"; + $this->description = $langs->trans('PDFAzurDescription'); + + // Dimension page pour format A4 + $this->type = 'pdf'; + $this->page_largeur = 210; + $this->page_hauteur = 297; + $this->format = array($this->page_largeur,$this->page_hauteur); + $this->marge_gauche=10; + $this->marge_droite=10; + $this->marge_haute=10; + $this->marge_basse=10; + + $this->option_logo = 1; // Affiche logo + $this->option_tva = 1; // Gere option tva FACTURE_TVAOPTION + $this->option_modereg = 1; // Affiche mode règlement + $this->option_condreg = 1; // Affiche conditions règlement + $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; // Gère les avoirs + $this->option_freetext = 1; // Support add of a personalised text + $this->option_draft_watermark = 1; //Support add of a watermark on drafts + + if (defined("FACTURE_TVAOPTION") && FACTURE_TVAOPTION == 'franchise') + $this->franchise=1; + + // Recupere emmetteur + $this->emetteur=$mysoc; + if (! $this->emetteur->pays_code) $this->emetteur->pays_code=substr($langs->defaultlang,-2); // Par defaut, si n'était pas défini + + // Defini position des colonnes + $this->posxdesc=$this->marge_gauche+1; + $this->posxtva=113; + $this->posxup=126; + $this->posxqty=145; + $this->posxdiscount=162; + $this->postotalht=174; + + $this->tva=array(); + $this->atleastoneratenotnull=0; + $this->atleastonediscount=0; + } + + /** + \brief Fonction générant la propale sur le disque + \param propale Objet propal à générer (ou id si ancienne methode) + \param outputlangs Lang object for output language + \return int 1=ok, 0=ko + */ + function write_file($propale,$outputlangs='') + { + global $user,$langs,$conf; + + if (! is_object($outputlangs)) $outputlangs=$langs; + $outputlangs->load("main"); + $outputlangs->load("dict"); + $outputlangs->load("companies"); + $outputlangs->load("bills"); + $outputlangs->load("propal"); + $outputlangs->load("products"); + + $outputlangs->setPhpLang(); + + if ($conf->propal->dir_output) + { + // Définition de l'objet $propale (pour compatibilite ascendante) + if (! is_object($propale)) + { + $id = $propale; + $propale = new Propal($this->db,"",$id); + $ret=$propale->fetch($id); + } + $deja_regle = ""; + + // Définition de $dir et $file + if ($propale->specimen) + { + $dir = $conf->propal->dir_output; + $file = $dir . "/SPECIMEN.pdf"; + } + else + { + $propref = sanitize_string($propale->ref); + $dir = $conf->propal->dir_output . "/" . $propref; + $file = $dir . "/" . $propref . ".pdf"; + } + + if (! file_exists($dir)) + { + if (create_exdir($dir) < 0) + { + $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); + return 0; + } + } + + if (file_exists($dir)) + { + $nblignes = sizeof($propale->lignes); + + // Protection et encryption du pdf + if ($conf->global->PDF_SECURITY_ENCRYPTION) + { + $pdf=new FPDI_Protection('P','mm',$this->format); + $pdfrights = array('print'); // Ne permet que l'impression du document + $pdfuserpass = ''; // Mot de passe pour l'utilisateur final + $pdfownerpass = NULL; // Mot de passe du propriétaire, créé aléatoirement si pas défini + $pdf->SetProtection($pdfrights,$pdfuserpass,$pdfownerpass); + } + else + { + $pdf=new FPDI('P','mm',$this->format); + } + + $pdf->Open(); + $pdf->AddPage(); + + $pdf->SetDrawColor(128,128,128); + + $pdf->SetTitle($propale->ref); + $pdf->SetSubject($outputlangs->transnoentities("CommercialProposal")); + $pdf->SetCreator("Dolibarr ".DOL_VERSION); + $pdf->SetAuthor($user->fullname); + + $pdf->SetMargins($this->marge_gauche, $this->marge_haute, $this->marge_droite); // Left, Top, Right + $pdf->SetAutoPageBreak(1,0); + + // Positionne $this->atleastonediscount si on a au moins une remise + for ($i = 0 ; $i < $nblignes ; $i++) + { + if ($propale->lignes[$i]->remise_percent) + { + $this->atleastonediscount++; + } + } + + // Tete de page + $this->_pagehead($pdf, $propale, 1, $outputlangs); + + $pagenb = 1; + $tab_top = 90; + $tab_top_newpage = 50; + $tab_height = 110; + $tab_height_newpage = 150; + $tab_height_middlepage = 190; + + // Affiche notes + if ($propale->note_public) + { + $tab_top = 88; + + $pdf->SetFont('Arial','', 9); // Dans boucle pour gérer multi-page + $pdf->SetXY ($this->posxdesc-1, $tab_top); + $pdf->MultiCell(190, 3, $propale->note_public, 0, 'J'); + $nexY = $pdf->GetY(); + $height_note=$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_note+1); + + $tab_height = $tab_height - $height_note; + $tab_top = $nexY+6; + } + else + { + $height_note=0; + } + + $iniY = $tab_top + 8; + $curY = $tab_top + 8; + $nexY = $tab_top + 8; + + // Boucle sur les lignes + for ($i = 0 ; $i < $nblignes ; $i++) + { + $curY = $nexY; + + // Description de la ligne produit + $libelleproduitservice=dol_htmlentitiesbr($propale->lignes[$i]->libelle,1); + if ($propale->lignes[$i]->desc && $propale->lignes[$i]->desc!=$propale->lignes[$i]->libelle) + { + if ($libelleproduitservice) $libelleproduitservice.="
"; + + if ($propale->lignes[$i]->desc == '(CREDIT_NOTE)' && $propale->lignes[$i]->fk_remise_except) + { + $discount=new DiscountAbsolute($this->db); + $discount->fetch($propale->lignes[$i]->fk_remise_except); + $libelleproduitservice=dol_htmlentitiesbr($langs->trans("DiscountFromCreditNote",$discount->ref_facture_source),1); + } + else + { + $libelleproduitservice.=dol_htmlentitiesbr($propale->lignes[$i]->desc,1); + } + } + // Si ligne associée à un code produit + if ($propale->lignes[$i]->fk_product) + { + $prodser = new Product($this->db); + $prodser->fetch($propale->lignes[$i]->fk_product); + + // On ajoute la ref + if ($prodser->ref) + { + $prefix_prodserv = ""; + if($prodser->isservice()) + $prefix_prodserv = $outputlangs->transnoentities("Service")." "; + else + $prefix_prodserv = $outputlangs->transnoentities("Product")." "; + + $libelleproduitservice=$prefix_prodserv.$prodser->ref." - ".$libelleproduitservice; + } + + } + if ($propale->lignes[$i]->date_start && $propale->lignes[$i]->date_end) + { + // Affichage durée si il y en a une + $libelleproduitservice.="
".dol_htmlentitiesbr("(".$outputlangs->transnoentities("From")." ".dolibarr_print_date($propale->lignes[$i]->date_start)." ".$outputlangs->transnoentities("to")." ".dolibarr_print_date($propale->lignes[$i]->date_end).")",1); + } + + $pdf->SetFont('Arial','', 9); // Dans boucle pour gérer multi-page + + // Description + $pdf->writeHTMLCell($this->posxtva-$this->posxdesc-1, 3, $this->posxdesc-1, $curY, $libelleproduitservice, 0, 1); + + $pdf->SetFont('Arial','', 9); // On repositionne la police par défaut + $nexY = $pdf->GetY(); + + // TVA + $pdf->SetXY ($this->posxtva, $curY); + $pdf->MultiCell($this->posxup-$this->posxtva-1, 3, vatrate($propale->lignes[$i]->tva_tx,1,$propale->lignes[$i]->info_bits), 0, 'R'); + + // Prix unitaire HT avant remise + $pdf->SetXY ($this->posxup, $curY); + $pdf->MultiCell($this->posxqty-$this->posxup-1, 3, price($propale->lignes[$i]->subprice), 0, 'R', 0); + + // Quantity + $pdf->SetXY ($this->posxqty, $curY); + if ($propale->lignes[$i]->special_code != 3) $pdf->MultiCell($this->posxdiscount-$this->posxqty-1, 4, $propale->lignes[$i]->qty, 0, 'R'); + + // Remise sur ligne + $pdf->SetXY ($this->posxdiscount, $curY); + if ($propale->lignes[$i]->remise_percent && $propale->lignes[$i]->special_code != 3) + { + $pdf->MultiCell($this->postotalht-$this->posxdiscount-1, 4, dolibarr_print_reduction($propale->lignes[$i]->remise_percent), 0, 'R'); + } + + // Total HT ligne + $pdf->SetXY ($this->postotalht, $curY); + if ($propale->lignes[$i]->special_code == 3) + { + // Ligne produit en option + $pdf->MultiCell(26, 4, $outputlangs->transnoentities("Option"), 0, 'R', 0); + } + else + { + $total = price($propale->lignes[$i]->total_ht); + $pdf->MultiCell(26, 4, $total, 0, 'R', 0); + } + + // Collecte des totaux par valeur de tva dans $this->tva["taux"]=total_tva + $tvaligne=$propale->lignes[$i]->total_tva; + if ($propale->remise_percent) $tvaligne-=($tvaligne*$propale->remise_percent)/100; + $vatrate=(string) $propale->lignes[$i]->tva_tx; + if ($propale->lignes[$i]->info_bits & 0x01 == 0x01) $vatrate.='*'; + $this->tva[$vatrate] += $tvaligne; + + $nexY+=2; // Passe espace entre les lignes + + //on compte le nombre de ligne afin de vérifier la place disponible + $nblineFollowDesc = (num_lines($follow_descproduitservice)*4); + // cherche nombre de lignes a venir pour savoir si place suffisante + if($i < ($nblignes - 1)){ + //on récupère la description du produit suivant + $follow_descproduitservice = $propale->lignes[$i+1]->desc; + //on compte le nombre de ligne afin de vérifier la place disponible (largeur de ligne 52 caracteres) + $nblineFollowDesc = (num_lines($follow_descproduitservice,52)*4); + } + else + $nblineFollowDesc = 0; + + // test si besoin nouvelle page + if (($nexY+$nblineFollowDesc) > ($tab_top+$tab_height) && $i < ($nblignes - 1)) + { + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $tab_height_newpage, $nexY, $outputlangs); + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $tab_height_middlepage, $nexY, $outputlangs); + } + + $this->_pagefoot($pdf,$outputlangs); + + // Nouvelle page + $pdf->AddPage(); + $pagenb++; + $this->_pagehead($pdf, $propale, 0, $outputlangs); + + $nexY = $tab_top_newpage + 8; + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('Arial','', 10); + } + + } + + // Affiche cadre tableau + if ($pagenb == 1) + { + $this->_tableau($pdf, $tab_top, $tab_height, $nexY, $outputlangs); + $bottomlasttab=$tab_top + $tab_height + 1; + } + else + { + $this->_tableau($pdf, $tab_top_newpage, $tab_height_newpage, $nexY, $outputlangs); + $bottomlasttab=$tab_top_newpage + $tab_height_newpage + 1; + } + + // Affiche zone infos + $posy=$this->_tableau_info($pdf, $propale, $bottomlasttab, $outputlangs); + + // Affiche zone totaux + $posy=$this->_tableau_tot($pdf, $propale, $deja_regle, $bottomlasttab, $outputlangs); + + // Affiche zone versements + if ($deja_regle) + { + $posy=$this->_tableau_versements($pdf, $propale, $posy, $outputlangs); + } + + // Pied de page + $this->_pagefoot($pdf,$outputlangs); + $pdf->AliasNbPages(); + + $pdf->Close(); + + $pdf->Output($file); + + $langs->setPhpLang(); // On restaure langue session + return 1; // Pas d'erreur + } + else + { + $this->error=$langs->trans("ErrorCanNotCreateDir",$dir); + $langs->setPhpLang(); // On restaure langue session + return 0; + } + } + else + { + $this->error=$langs->trans("ErrorConstantNotDefined","PROP_OUTPUTDIR"); + $langs->setPhpLang(); // On restaure langue session + return 0; + } + + $this->error=$langs->trans("ErrorUnknown"); + $langs->setPhpLang(); // On restaure langue session + return 0; // Erreur par defaut + } + + /* + * \brief Affiche tableau des versement + * \param pdf Objet PDF + * \param object Objet propale + */ + function _tableau_versements(&$pdf, $object, $posy, $outputlangs) + { + + } + + + /* + * \brief Affiche infos divers + * \param pdf Objet PDF + * \param object Objet propale + * \param posy Position depart + * \param outputlangs Objet langs + * \return y Position pour suite + */ + function _tableau_info(&$pdf, $object, $posy, $outputlangs) + { + global $conf; + + $pdf->SetFont('Arial','', 9); + + /* + * If France, show VAT mention if not applicable + */ + if ($this->emetteur->pays_code == 'FR' && $this->franchise == 1) + { + $pdf->SetFont('Arial','B',8); + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("VATIsNotUsedForInvoice"), 0, 'L', 0); + + $posy=$pdf->GetY()+4; + } + + /* + * Conditions de reglements + */ + if ($object->cond_reglement_code || $object->cond_reglement) + { + $pdf->SetFont('Arial','B',8); + $pdf->SetXY($this->marge_gauche, $posy); + $titre = $outputlangs->transnoentities("PaymentConditions").':'; + $pdf->MultiCell(80, 5, $titre, 0, 'L'); + + $pdf->SetFont('Arial','',8); + $pdf->SetXY(50, $posy); + $lib_condition_paiement=$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code)!=('PaymentCondition'.$object->cond_reglement_code)?$outputlangs->transnoentities("PaymentCondition".$object->cond_reglement_code):$object->cond_reglement; + $pdf->MultiCell(80, 5, $lib_condition_paiement,0,'L'); + + $posy=$pdf->GetY()+3; + } + + /* + * Check si absence mode reglement + */ + if (! $conf->global->FACTURE_CHQ_NUMBER && ! $conf->global->FACTURE_RIB_NUMBER) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('Arial','B',8); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities("ErrorNoPaiementModeConfigured"),0,'L',0); + $pdf->SetTextColor(0,0,0); + + $posy=$pdf->GetY()+1; + } + + /* + * Propose mode reglement par CHQ + */ + if (! $object->mode_reglement_code || $object->mode_reglement_code == 'CHQ') + { + // Si mode reglement non force ou si force a CHQ + if ($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('Arial','B',8); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByChequeOrderedTo',$account->proprio).':',0,'L',0); + $posy=$pdf->GetY()+1; + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('Arial','',8); + $pdf->MultiCell(80, 3, $account->adresse_proprio, 0, 'L', 0); + + $posy=$pdf->GetY()+2; + } + if ($conf->global->FACTURE_CHQ_NUMBER == -1) + { + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('Arial','B',8); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByChequeOrderedToShort').' '.$this->emetteur->nom.' '.$outputlangs->transnoentities('SendTo').':',0,'L',0); + $posy=$pdf->GetY()+1; + + $pdf->SetXY($this->marge_gauche, $posy); + $pdf->SetFont('Arial','',8); + $pdf->MultiCell(80, 6, $this->emetteur->adresse_full, 0, 'L', 0); + + $posy=$pdf->GetY()+2; + } + } + } + + /* + * Propose mode reglement par RIB + */ + if (! $object->mode_reglement_code || $object->mode_reglement_code == 'VIR') + { + // Si mode reglement non force ou si force a VIR + if ($conf->global->FACTURE_RIB_NUMBER) + { + if ($conf->global->FACTURE_RIB_NUMBER) + { + $account = new Account($this->db); + $account->fetch($conf->global->FACTURE_RIB_NUMBER); + + $this->marges['g']=$this->marge_gauche; + + $cury=$posy; + $pdf->SetXY ($this->marges['g'], $cury); + $pdf->SetFont('Arial','B',8); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities('PaymentByTransferOnThisBankAccount').':', 0, 'L', 0); + $cury+=4; + $pdf->SetFont('Arial','B',6); + $pdf->line($this->marges['g']+1, $cury, $this->marges['g']+1, $cury+10 ); + $pdf->SetXY ($this->marges['g'], $cury); + $pdf->MultiCell(18, 3, $outputlangs->transnoentities("BankCode"), 0, 'C', 0); + $pdf->line($this->marges['g']+18, $cury, $this->marges['g']+18, $cury+10 ); + $pdf->SetXY ($this->marges['g']+18, $cury); + $pdf->MultiCell(18, 3, $outputlangs->transnoentities("DeskCode"), 0, 'C', 0); + $pdf->line($this->marges['g']+36, $cury, $this->marges['g']+36, $cury+10 ); + $pdf->SetXY ($this->marges['g']+36, $cury); + $pdf->MultiCell(24, 3, $outputlangs->transnoentities("BankAccountNumber"), 0, 'C', 0); + $pdf->line($this->marges['g']+60, $cury, $this->marges['g']+60, $cury+10 ); + $pdf->SetXY ($this->marges['g']+60, $cury); + $pdf->MultiCell(13, 3, $outputlangs->transnoentities("BankAccountNumberKey"), 0, 'C', 0); + $pdf->line($this->marges['g']+73, $cury, $this->marges['g']+73, $cury+10 ); + + $pdf->SetFont('Arial','',8); + $pdf->SetXY ($this->marges['g'], $cury+5); + $pdf->MultiCell(18, 3, $account->code_banque, 0, 'C', 0); + $pdf->SetXY ($this->marges['g']+18, $cury+5); + $pdf->MultiCell(18, 3, $account->code_guichet, 0, 'C', 0); + $pdf->SetXY ($this->marges['g']+36, $cury+5); + $pdf->MultiCell(24, 3, $account->number, 0, 'C', 0); + $pdf->SetXY ($this->marges['g']+60, $cury+5); + $pdf->MultiCell(13, 3, $account->cle_rib, 0, 'C', 0); + + $pdf->SetXY ($this->marges['g'], $cury+12); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities("Residence").' : ' . $account->domiciliation, 0, 'L', 0); + $pdf->SetXY ($this->marges['g'], $cury+22); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities("IbanPrefix").' : ' . $account->iban_prefix, 0, 'L', 0); + $pdf->SetXY ($this->marges['g'], $cury+25); + $pdf->MultiCell(90, 3, $outputlangs->transnoentities("BIC").' : ' . $account->bic, 0, 'L', 0); + + $posy=$pdf->GetY()+2; + } + } + } + + return $posy; + } + + + /* + * \brief Affiche le total a payer + * \param pdf Objet PDF + * \param object Objet propale + * \param deja_regle Montant deja regle + * \param posy Position depart + * \param outputlangs Objet langs + * \return y Position pour suite + */ + function _tableau_tot(&$pdf, $object, $deja_regle, $posy, $outputlangs) + { + $tab2_top = $posy; + $tab2_hl = 5; + $tab2_height = $tab2_hl * 4; + $pdf->SetFont('Arial','', 9); + + // Tableau total + $lltot = 200; $col1x = 120; $col2x = 182; $largcol2 = $lltot - $col2x; + + // 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); + + $pdf->SetXY ($col2x, $tab2_top + 0); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ht + $object->remise), 0, 'R', 1); + + $index = 0; + + // Affichage des totaux de TVA par taux (conformément à réglementation) + $pdf->SetFillColor(248,248,248); + foreach( $this->tva as $tvakey => $tvaval ) + { + if ($tvakey) // On affiche pas taux 0 + { + $this->atleastoneratenotnull++; + + $index++; + $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); + + $tvacompl=''; + if (eregi('\*',$tvakey)) + { + $tvakey=eregi_replace('\*','',$tvakey); + $tvacompl = " (".$outputlangs->transnoentities("NonPercuRecuperable").")"; + } + $totalvat =$outputlangs->transnoentities("TotalVAT").' '; + $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, 'R', 1); + } + } + if (! $this->atleastoneratenotnull) // If not vat at all + { + $index++; + $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("TotalVAT"), 0, 'L', 1); + + $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_tva), 0, 'R', 1); + } + + $useborder=0; + + $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($object->total_ttc), $useborder, 'R', 1); + $pdf->SetTextColor(0,0,0); + + if ($deja_regle > 0) + { + $index++; + + $pdf->SetXY ($col1x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($col2x-$col1x, $tab2_hl, $outputlangs->transnoentities("AlreadyPayed"), 0, 'L', 0); + + $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($deja_regle), 0, 'R', 0); + + $resteapayer = $object->total_ttc - $deja_regle; + if ($object->paye) $resteapayer=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("EscompteOffered"), $useborder, 'L', 1); + + $pdf->SetXY ($col2x, $tab2_top + $tab2_hl * $index); + $pdf->MultiCell($largcol2, $tab2_hl, price($object->total_ttc - $deja_regle), $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), $useborder, 'R', 1); + + // Fin + $pdf->SetFont('Arial','', 9); + $pdf->SetTextColor(0,0,0); + } + + $index++; + return ($tab2_top + ($tab2_hl * $index)); + } + + /** + * \brief Affiche la grille des lignes de propales + * \param pdf objet PDF + */ + function _tableau(&$pdf, $tab_top, $tab_height, $nexY, $outputlangs) + { + global $conf; + + // Montants exprimés en (en tab_top - 1) + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('Arial','',8); + $titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentities("Currency".$conf->monnaie)); + $pdf->Text($this->page_largeur - $this->marge_droite - $pdf->GetStringWidth($titre), $tab_top-1, $titre); + + $pdf->SetDrawColor(128,128,128); + + // Rect prend une longueur en 3eme param + $pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height); + // line prend une position y en 3eme param + $pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5); + + $pdf->SetFont('Arial','',9); + + $pdf->SetXY ($this->posxdesc-1, $tab_top+2); + $pdf->MultiCell(108,2, $outputlangs->transnoentities("Designation"),'','L'); + + $pdf->line($this->posxtva-1, $tab_top, $this->posxtva-1, $tab_top + $tab_height); + $pdf->SetXY ($this->posxtva-1, $tab_top+2); + $pdf->MultiCell($this->posxup-$this->posxtva-1,2, $outputlangs->transnoentities("VAT"),'','C'); + + $pdf->line($this->posxup-1, $tab_top, $this->posxup-1, $tab_top + $tab_height); + $pdf->SetXY ($this->posxup-1, $tab_top+2); + $pdf->MultiCell(18,2, $outputlangs->transnoentities("PriceUHT"),'','C'); + + $pdf->line($this->posxqty-1, $tab_top, $this->posxqty-1, $tab_top + $tab_height); + $pdf->SetXY ($this->posxqty-1, $tab_top+2); + $pdf->MultiCell($this->posxdiscount-$this->posxqty-1,2, $outputlangs->transnoentities("Qty"),'','C'); + + $pdf->line($this->posxdiscount-1, $tab_top, $this->posxdiscount-1, $tab_top + $tab_height); + if ($this->atleastonediscount) + { + $pdf->SetXY ($this->posxdiscount-1, $tab_top+2); + $pdf->MultiCell(14,2, $outputlangs->transnoentities("ReductionShort"),'','C'); + } + + if ($this->atleastonediscount) + { + $pdf->line($this->postotalht, $tab_top, $this->postotalht, $tab_top + $tab_height); + } + $pdf->SetXY ($this->postotalht-1, $tab_top+2); + $pdf->MultiCell(28,2, $outputlangs->transnoentities("TotalHT"),'','C'); + + } + + /* + * \brief Affiche en-tête propale + * \param pdf Objet PDF + * \param object Objet propale + * \param showadress 0=non, 1=oui + * \param outputlang Objet lang cible + */ + function _pagehead(&$pdf, $object, $showadress=1, $outputlangs) + { + global $conf,$langs; + + $outputlangs->load("main"); + $outputlangs->load("bills"); + $outputlangs->load("propal"); + $outputlangs->load("companies"); + + //Affiche le filigrane brouillon - Print Draft Watermark + if($object->statut==0 && (! empty($conf->global->PROPALE_DRAFT_WATERMARK)) ) + { + $watermark_angle=atan($this->page_hauteur/$this->page_largeur); + $watermark_x=5; + $watermark_y=$this->page_hauteur-25; //Set to $this->page_hauteur-50 or less if problems + $watermark_width=$this->page_hauteur; + $pdf->SetFont('Arial','B',50); + $pdf->SetTextColor(255,192,203); + //rotate + $pdf->_out(sprintf('q %.5F %.5F %.5F %.5F %.2F %.2F cm 1 0 0 1 %.2F %.2F cm',cos($watermark_angle),sin($watermark_angle),-sin($watermark_angle),cos($watermark_angle),$watermark_x*$pdf->k,($pdf->h-$watermark_y)*$pdf->k,-$watermark_x*$pdf->k,-($pdf->h-$watermark_y)*$pdf->k)); + //print watermark + $pdf->SetXY($watermark_x,$watermark_y); + $pdf->Cell($watermark_width,25,clean_html($conf->global->PROPALE_DRAFT_WATERMARK),0,2,"C",0); + //antirotate + $pdf->_out('Q'); + } + + //Prepare la suite + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('Arial','B',13); + + $posy=$this->marge_haute; + + $pdf->SetXY($this->marge_gauche,$posy); + + // Logo + $logo=$conf->societe->dir_logos.'/'.$this->emetteur->logo; + if ($this->emetteur->logo) + { + if (is_readable($logo)) + { + $pdf->Image($logo, $this->marge_gauche, $posy, 0, 24); + } + else + { + $pdf->SetTextColor(200,0,0); + $pdf->SetFont('Arial','B',8); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L'); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorGoToGlobalSetup"), 0, 'L'); + } + } + else if (defined("FAC_PDF_INTITULE")) + { + $pdf->MultiCell(100, 4, FAC_PDF_INTITULE, 0, 'L'); + } + + $pdf->SetFont('Arial','B',13); + $pdf->SetXY(100,$posy); + $pdf->SetTextColor(0,0,60); + $title=$outputlangs->transnoentities("CommercialProposal"); + $pdf->MultiCell(100, 4, $title, '' , 'R'); + + $pdf->SetFont('Arial','B',12); + + $posy+=6; + $pdf->SetXY(100,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 4, $outputlangs->transnoentities("Ref")." : " . $object->ref, '', 'R'); + + $posy+=1; + $pdf->SetFont('Arial','',10); + + $posy+=5; + $pdf->SetXY(100,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("Date")." : " . dolibarr_print_date($object->date,"day"), '', 'R'); + + $posy+=5; + $pdf->SetXY(100,$posy); + $pdf->SetTextColor(0,0,60); + $pdf->MultiCell(100, 3, $outputlangs->transnoentities("DateEndPropal")." : " . dolibarr_print_date($object->fin_validite,"day"), '', 'R'); + + if ($showadress) + { + // Emetteur + $posy=42; + $hautcadre=40; + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('Arial','',8); + $pdf->SetXY($this->marge_gauche,$posy-5); + $pdf->MultiCell(66,5, $outputlangs->transnoentities("BillFrom").":"); + + + $pdf->SetXY($this->marge_gauche,$posy); + $pdf->SetFillColor(230,230,230); + $pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1); + + + $pdf->SetXY($this->marge_gauche+2,$posy+3); + + // Nom emetteur + $pdf->SetTextColor(0,0,60); + $pdf->SetFont('Arial','B',11); + if (defined("FAC_PDF_SOCIETE_NOM") && FAC_PDF_SOCIETE_NOM) $pdf->MultiCell(80, 4, FAC_PDF_SOCIETE_NOM, 0, 'L'); + else $pdf->MultiCell(80, 4, $this->emetteur->nom, 0, 'L'); + + // Caractéristiques emetteur + $carac_emetteur = ''; + if (defined("FAC_PDF_ADRESSE") && FAC_PDF_ADRESSE) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).FAC_PDF_ADRESSE; + else { + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$this->emetteur->adresse; + $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$this->emetteur->cp.' '.$this->emetteur->ville; + } + $carac_emetteur .= "\n"; + // Tel + if (defined("FAC_PDF_TEL") && FAC_PDF_TEL) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ".FAC_PDF_TEL; + elseif ($this->emetteur->tel) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Phone").": ".$this->emetteur->tel; + // Fax + if (defined("FAC_PDF_FAX") && FAC_PDF_FAX) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".FAC_PDF_FAX; + elseif ($this->emetteur->fax) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Fax").": ".$this->emetteur->fax; + // EMail + if (defined("FAC_PDF_MEL") && FAC_PDF_MEL) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".FAC_PDF_MEL; + elseif ($this->emetteur->email) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Email").": ".$this->emetteur->email; + // Web + if (defined("FAC_PDF_WWW") && FAC_PDF_WWW) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".FAC_PDF_WWW; + elseif ($this->emetteur->url) $carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->transnoentities("Web").": ".$this->emetteur->url; + + $pdf->SetFont('Arial','',9); + $pdf->SetXY($this->marge_gauche+2,$posy+8); + $pdf->MultiCell(80,4, $carac_emetteur); + + // Client destinataire + $posy=42; + $pdf->SetTextColor(0,0,0); + $pdf->SetFont('Arial','',8); + $pdf->SetXY(102,$posy-5); + $pdf->MultiCell(80,5, $outputlangs->transnoentities("BillTo").":"); + $object->fetch_client(); + + // Cadre client destinataire + $pdf->rect(100, $posy, 100, $hautcadre); + + // If BILLING contact defined on invoice, we use it + $usecontact=false; + if ($conf->global->PROPALE_USE_CUSTOMER_CONTACT_AS_RECIPIENT) + { + $arrayidcontact=$object->getIdContact('external','CUSTOMER'); + if (sizeof($arrayidcontact) > 0) + { + $usecontact=true; + $result=$object->fetch_contact($arrayidcontact[0]); + } + } + + if ($usecontact) + { + // Nom societe + $pdf->SetXY(102,$posy+3); + $pdf->SetFont('Arial','B',11); + $pdf->MultiCell(96,4, $object->client->nom, 0, 'L'); + + // Nom client + $carac_client = "\n".$object->contact->getFullName($outputlangs,1,1); + + // Caractéristiques client + $carac_client.="\n".$object->contact->adresse; + $carac_client.="\n".$object->contact->cp . " " . $object->contact->ville."\n"; + //Pays si different de l'emetteur + if ($this->emetteur->pays_code != $object->contact->pays_code) + { + $carac_client.=dol_entity_decode($object->contact->pays)."\n"; + } + } + else + { + // Nom client + $pdf->SetXY(102,$posy+3); + $pdf->SetFont('Arial','B',11); + $pdf->MultiCell(96,4, $object->client->nom, 0, 'L'); + + // Nom du contact suivi propal si c'est une société + $arrayidcontact = $object->getIdContact('external','CUSTOMER'); + if (sizeof($arrayidcontact) > 0) + { + $object->fetch_contact($arrayidcontact[0]); + // On vérifie si c'est une société ou un particulier + if( !preg_match('#'.$object->contact->getFullName($outputlangs,1).'#isU',$object->client->nom) ) + { + $carac_client .= "\n".$object->contact->getFullName($outputlangs,1,1); + } + } + + // Caractéristiques client + $carac_client.="\n".$object->client->adresse; + $carac_client.="\n".$object->client->cp . " " . $object->client->ville."\n"; + + //Pays si different de l'emetteur + if ($this->emetteur->pays_code != $object->client->pays_code) + { + $carac_client.=dol_entity_decode($object->client->pays)."\n"; + } + } + // Numéro TVA intracom + if ($object->client->tva_intra) $carac_client.="\n".$outputlangs->transnoentities("VATIntraShort").': '.$object->client->tva_intra; + $pdf->SetFont('Arial','',9); + $posy=$pdf->GetY()-9; //Auto Y coord readjust for multiline name + $pdf->SetXY(102,$posy+6); + $pdf->MultiCell(86,4, $carac_client); + } + } + + /* + * \brief Affiche le pied de page + * \param pdf objet PDF + */ + function _pagefoot(&$pdf,$outputlangs) + { + return pdf_pagefoot($pdf,$outputlangs,'PROPALE_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur); + } + +} + +?> diff --git a/htdocs/lib/functions.lib.php b/htdocs/lib/functions.lib.php index 385876f91f7..921f2d31225 100644 --- a/htdocs/lib/functions.lib.php +++ b/htdocs/lib/functions.lib.php @@ -1,3031 +1,3049 @@ - - * Copyright (C) 2003 Jean-Louis Bergamo - * Copyright (C) 2004-2008 Laurent Destailleur - * Copyright (C) 2004 Sebastien Di Cintio - * Copyright (C) 2004 Benoit Mortier - * Copyright (C) 2004 Christophe Combelles - * Copyright (C) 2005-2007 Regis Houssin - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * or see http://www.gnu.org/ - */ - -/** - \file htdocs/lib/functions.lib.php - \brief Ensemble de fonctions de base de dolibarr sous forme d'include - \version $Id$ - */ - -// For compatibility during upgrade -if (! defined('DOL_DOCUMENT_ROOT')) define('DOL_DOCUMENT_ROOT', '..'); -if (! defined('ADODB_DATE_VERSION')) include_once(DOL_DOCUMENT_ROOT."/includes/adodbtime/adodb-time.inc.php"); - - - -/** - \brief Renvoi vrai si l'email est syntaxiquement valide - \param address adresse email (Ex: "toto@titi.com", "John Do ") - \return boolean true si email valide, false sinon - */ -function ValidEmail($address) -{ - if (ereg( ".*<(.+)>", $address, $regs)) { - $address = $regs[1]; - } - if (ereg( "^[^@ ]+@([a-zA-Z0-9\-]+\.)+([a-zA-Z0-9\-]{2}|coop|aero|biz|com|edu|gov|info|int|mil|name|net|org)\$",$address)) - { - return true; - } - else - { - return false; - } -} - -/** - \brief Renvoi vrai si l'email a un nom de domaine qui r�soud via dns - \param mail adresse email (Ex: "toto@titi.com", "John Do ") - \return boolean true si email valide, false sinon - */ -function check_mail ($mail) -{ - list($user, $domain) = split("@", $mail, 2); - if (checkdnsrr($domain, "MX")) - { - return true; - } - else - { - return false; - } -} - -/** - \brief Nettoie chaine de caractere iso des accents - \param str Chaine a nettoyer - \return string Chaine nettoyee - */ -function unaccent_isostring($str) -{ - $translation = array( - "\xE0" => "a", - "\xE1" => "a", - "\xE2" => "a", - "\xE8" => "e", - "\xE9" => "e", - "\xEA" => "e", - "\xEB" => "e", - "\xEE" => "i", - "\xEF" => "i", - "\xF4" => "o", - "\xF6" => "o", - "\xFB" => "u", - "\xFC" => "u" - ); - - return str_replace(array_keys($translation), array_values($translation), $str); -} - -/** - * \brief Nettoie chaine de caractere de caracteres speciaux - * \remarks Fonction appelee par exemple pour definir un nom de fichier depuis un identifiant chaine libre - * \param str String to clean - * \param newstr String to replace bad chars by - * \return string String cleaned (a-zA-Z_) - */ -function sanitize_string($str,$newstr='_') -{ - $forbidden_chars_to_underscore=array(" ","'","/","\\",":","*","?","\"","<",">","|","[","]",",",";","="); - //$forbidden_chars_to_remove=array("(",")"); - $forbidden_chars_to_remove=array(); - - return str_replace($forbidden_chars_to_underscore,$newstr,str_replace($forbidden_chars_to_remove,"",$str)); -} - - -/** - * \brief Returns text escaped for inclusion in javascript code - * \param $stringtoescape String to escape - * \return string Escaped string - */ -function dol_escape_js($stringtoescape) -{ - // escape quotes and backslashes, newlines, etc. - return strtr($stringtoescape, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); -} - - - - -/** - \brief Envoi des messages dolibarr dans un fichier ou dans syslog - Pour fichier: fichier defini par SYSLOG_FILE - Pour syslog: facility defini par SYSLOG_FACILITY - \param message Message a tracer. Ne doit pas etre traduit si level = LOG_ERR - \param level Niveau de l'erreur - \remarks Cette fonction n'a un effet que si le module syslog est activ�. - Warning, les fonctions syslog sont buggu�s sous Windows et g�n�rent des - fautes de protection m�moire. Pour r�soudre, utiliser le loggage fichier, - au lieu du loggage syslog (configuration du module). - Si SYSLOG_FILE_NO_ERROR d�fini, on ne g�re pas erreur ecriture log - \remarks On Windows LOG_ERR=4, LOG_WARNING=5, LOG_NOTICE=LOG_INFO=LOG_DEBUG=6 - On Linux LOG_ERR=3, LOG_WARNING=4, LOG_INFO=6, LOG_DEBUG=7 - */ -function dolibarr_syslog($message, $level=LOG_INFO) -{ - global $conf,$user,$langs; - - if (isset($conf->syslog->enabled) && $conf->syslog->enabled) - { - //print $level.' - '.$conf->global->SYSLOG_LEVEL.' - '.$conf->syslog->enabled." \n"; - if ($level > $conf->global->SYSLOG_LEVEL) return; - - // Traduction du message - if ($level == LOG_ERR) - { - $langs->load("errors"); - if ($message != $langs->trans($message)) $message = $langs->trans($message); - } - - // Ajout user a la log - $login='???'; - if (is_object($user) && $user->id) $login=$user->login; - $message=sprintf("%-8s",$login)." ".$message; - - if (defined("SYSLOG_FILE") && SYSLOG_FILE) - { - $filelog=SYSLOG_FILE; - $filelog=eregi_replace('DOL_DATA_ROOT',DOL_DATA_ROOT,$filelog); - if (defined("SYSLOG_FILE_NO_ERROR")) $file=@fopen($filelog,"a+"); - else $file=fopen($filelog,"a+"); - if ($file) - { - $ip='unknown_ip'; - if (! empty($_SERVER["REMOTE_ADDR"])) $ip=$_SERVER["REMOTE_ADDR"]; - - $liblevelarray=array(LOG_ERR=>'ERROR',LOG_WARNING=>'WARN',LOG_INFO=>'INFO',LOG_DEBUG=>'DEBUG'); - $liblevel=$liblevelarray[$level]; - if (! $liblevel) $liblevel='UNDEF'; - - $message=strftime("%Y-%m-%d %H:%M:%S",time())." ".sprintf("%-5s",$liblevel)." ".$ip." ".$message; - - fwrite($file,$message."\n"); - fclose($file); - - // If enable html log tag enabled and url parameter log defined, we show output log on HTML comments - if (! empty($conf->global->MAIN_ENABLE_LOG_HTML) && ! empty($_GET["log"])) - { - print "\n\n\n"; - } - } - elseif (! defined("SYSLOG_FILE_NO_ERROR")) - { - $langs->load("main"); - print $langs->trans("ErrorFailedToOpenFile",$filelog); - } - } - else - { - //define_syslog_variables(); d�ja d�finit dans master.inc.php - if (defined("MAIN_SYSLOG_FACILITY") && MAIN_SYSLOG_FACILITY) - { - $facility = MAIN_SYSLOG_FACILITY; - } - elseif (defined("SYSLOG_FACILITY") && SYSLOG_FACILITY && defined(SYSLOG_FACILITY)) - { - // Exemple: SYSLOG_FACILITY vaut LOG_USER qui vaut 8. On a besoin de 8 dans $facility. - $facility = constant(SYSLOG_FACILITY); - } - else - { - $facility = LOG_USER; - } - - openlog("dolibarr", LOG_PID | LOG_PERROR, $facility); - - if (! $level) - { - syslog(LOG_ERR, $message); - } - else - { - syslog($level, $message); - } - - closelog(); - } - } -} - -/** - \brief Affiche le header d'une fiche - \param links Tableau de titre d'onglets - \param active 0=onglet non actif, 1=onglet actif - \param title Titre tabelau ("" par defaut) - \param notab 0=Add tab header, 1=no tab header - */ -function dolibarr_fiche_head($links, $active='0', $title='', $notab=0) -{ - print "\n".'
'."\n"; - - // Affichage titre - if ($title) - { - $limittitle=30; - print ''; - print - ((!defined('MAIN_USE_SHORT_TITLE')) || (defined('MAIN_USE_SHORT_TITLE') && MAIN_USE_SHORT_TITLE)) - ? dolibarr_trunc($title,$limittitle) - : $title; - print ''; - } - - // Affichage onglets - for ($i = 0 ; $i < sizeof($links) ; $i++) - { - if ($links[$i][2] == 'image') - { - print ''.$links[$i][1].''."\n"; - } - else - { - //print "x $i $active ".$links[$i][2]." z"; - if ((is_numeric($active) && $i == $active) - || (! is_numeric($active) && $active == $links[$i][2])) - { - print ''.$links[$i][1].''."\n"; - } - else - { - print ''.$links[$i][1].''."\n"; - } - } - } - - print "
\n"; - - if (! $notab) print '
'."\n\n"; -} - - -/** - \brief Sauvegarde parametrage personnel - \param db Handler d'acc�s base - \param user Objet utilisateur - \param url Si defini, on sauve parametre du tableau tab dont cl� = (url avec sortfield, sortorder, begin et page) - Si non defini on sauve tous parametres du tableau tab - \param tab Tableau (cl�=>valeur) des param�tres a sauvegarder - \return int <0 si ko, >0 si ok - */ -function dolibarr_set_user_page_param($db, &$user, $url='', $tab) -{ - // Verification parametres - if (sizeof($tab) < 1) return -1; - - $db->begin(); - - // On efface anciens param�tres pour toutes les cl� dans $tab - $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param"; - $sql.= " WHERE fk_user = ".$user->id; - if ($url) $sql.=" AND page='".$url."'"; - else $sql.=" AND page=''"; // Page ne peut etre null - $sql.= " AND param in ("; - $i=0; - foreach ($tab as $key => $value) - { - if ($i > 0) $sql.=','; - $sql.="'".$key."'"; - $i++; - } - $sql.= ")"; - dolibarr_syslog("functions.lib.php::dolibarr_set_user_page_param $sql"); - - $resql=$db->query($sql); - if (! $resql) - { - dolibarr_print_error($db); - $db->rollback(); - exit; - } - - foreach ($tab as $key => $value) - { - // On positionne nouveaux param�tres - if ($value && (! $url || in_array($key,array('sortfield','sortorder','begin','page')))) - { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,page,param,value)"; - $sql.= " VALUES (".$user->id.","; - if ($url) $sql.= " '".urlencode($url)."',"; - else $sql.= " '',"; - $sql.= " '".$key."','".addslashes($value)."');"; - dolibarr_syslog("functions.lib.php::dolibarr_set_user_page_param $sql"); - - $result=$db->query($sql); - if (! $result) - { - dolibarr_print_error($db); - $db->rollback(); - exit; - } - - $user->page_param[$key] = $value; - } - } - - $db->commit(); - return 1; -} - - -/** - \brief Formattage des nombres - \param ca valeur a formater - \return int valeur format�e - */ -function dolibarr_print_ca($ca) -{ - global $langs,$conf; - - if ($ca > 1000) - { - $cat = round(($ca / 1000),2); - $cat = "$cat K".$langs->trans("Currency".$conf->monnaie); - } - else - { - $cat = round($ca,2); - $cat = "$cat ".$langs->trans("Currency".$conf->monnaie); - } - - if ($ca > 1000000) - { - $cat = round(($ca / 1000000),2); - $cat = "$cat M".$langs->trans("Currency".$conf->monnaie); - } - - return $cat; -} - - -/** - \brief Effectue un d�calage de date par rapport a une dur�e - \param time Date timestamp ou au format YYYY-MM-DD - \param duration_value Valeur de la dur�e a ajouter - \param duration_unit Unit� de la dur�e a ajouter (d, m, y) - \return int Nouveau timestamp - */ -function dolibarr_time_plus_duree($time,$duration_value,$duration_unit) -{ - if ($duration_value == 0) return $time; - if ($duration_value > 0) $deltastring="+".abs($duration_value); - if ($duration_value < 0) $deltastring="-".abs($duration_value); - if ($duration_unit == 'd') { $deltastring.=" day"; } - if ($duration_unit == 'm') { $deltastring.=" month"; } - if ($duration_unit == 'y') { $deltastring.=" year"; } - return strtotime($deltastring,$time); -} - - -/** - * \brief Formattage de la date en fonction de la langue $conf->langage - * \param time Date 'timestamp' ou format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' - * \param format Format d'affichage de la date - * "%d %b %Y", - * "%d/%m/%Y %H:%M", - * "%d/%m/%Y %H:%M:%S", - * "day", "daytext", "dayhour", "dayhourldap", "dayhourtext" - * \return string Date formatee ou '' si time null - */ -function dolibarr_print_date($time,$format='',$to_gmt=false) -{ - global $conf; - - // Si format non defini, on prend $conf->format_date_text_short sinon %Y-%m-%d %H:%M:%S - if (! $format) $format=(isset($conf->format_date_text_short) ? $conf->format_date_text_short : '%Y-%m-%d %H:%M:%S'); - - if ($format == 'day') $format=$conf->format_date_short; - if ($format == 'hour') $format=$conf->format_hour_short; - if ($format == 'daytext') $format=$conf->format_date_text_short; - if ($format == 'dayhour') $format=$conf->format_date_hour_short; - if ($format == 'dayhourtext') $format=$conf->format_date_hour_text_short; - if ($format == 'dayhourldap') $format='%Y%m%d%H%M%SZ'; - if ($format == 'dayhourxcard') $format='%Y%m%dT%H%M%SZ'; - - // Si date non definie, on renvoie '' - if ($time == '') return ''; // $time=0 permis car signifie 01/01/1970 00:00:00 - - // Analyse de la date - if (eregi('^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$time,$reg)) - { - // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' - $syear = $reg[1]; - $smonth = $reg[2]; - $sday = $reg[3]; - $shour = $reg[4]; - $smin = $reg[5]; - $ssec = $reg[6]; - - return adodb_strftime($format,dolibarr_mktime($shour,$smin,$ssec,$smonth,$sday,$syear),$to_gmt); - } - else - { - // Date est un timestamps - return adodb_strftime($format,$time,$to_gmt); - } -} - - -/** - * \brief Convert a string date into a TMS date - * \param string Date in a string - * YYYYMMDD - * YYYYMMDDHHMMSS - * DD/MM/YY ou DD/MM/YYYY - * DD/MM/YY HH:MM:SS ou DD/MM/YYYY HH:MM:SS - * \return date Date - */ -function dolibarr_stringtotime($string) -{ - if (eregi('^([0-9]+)\/([0-9]+)\/([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$string,$reg)) - { - // Date est au format 'DD/MM/YY' ou 'DD/MM/YY HH:MM:SS' - // Date est au format 'DD/MM/YYYY' ou 'DD/MM/YYYY HH:MM:SS' - $sday = $reg[1]; - $smonth = $reg[2]; - $syear = $reg[3]; - $shour = $reg[4]; - $smin = $reg[5]; - $ssec = $reg[6]; - if ($syear < 50) $syear+=1900; - if ($syear >= 50 && $syear < 100) $syear+=2000; - $string=sprintf("%04d%02d%02d%02d%02d%02d",$syear,$smonth,$sday,$shour,$smin,$ssec); - } - - $string=eregi_replace('[^0-9]','',$string); - $tmp=$string.'000000'; - $date=dolibarr_mktime(substr($tmp,8,2),substr($tmp,10,2),substr($tmp,12,2),substr($tmp,4,2),substr($tmp,6,2),substr($tmp,0,4)); - return $date; -} - - -/** - \brief Return an array with date info - \param timestamp Timestamp - \param fast Fast mode - \return array Array of informations - If no fast mode: - 'seconds' => $secs, - 'minutes' => $min, - 'hours' => $hour, - 'mday' => $day, - 'wday' => $dow, - 'mon' => $month, - 'year' => $year, - 'yday' => floor($secsInYear/$_day_power), - 'weekday' => gmdate('l',$_day_power*(3+$dow)), - 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), - 0 => $origd - If fast mode: - 'seconds' => $secs, - 'minutes' => $min, - 'hours' => $hour, - 'mday' => $day, - 'mon' => $month, - 'year' => $year, - 'yday' => floor($secsInYear/$_day_power), - 'leap' => $leaf, - 'ndays' => $ndays - \remarks PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows - */ -function dolibarr_getdate($timestamp,$fast=false) -{ - $usealternatemethod=false; - if ($timestamp <= 0) $usealternatemethod=true; // <= 1970 - if ($timestamp >= 2145913200) $usealternatemethod=true; // >= 2038 - - if ($usealternatemethod) - { - $arrayinfo=adodb_getdate($timestamp,$fast); - } - else - { - $arrayinfo=getdate($timestamp); - } - - return $arrayinfo; -} - -/** - \brief Retourne une date fabriquee depuis infos. - Remplace la fonction mktime non implementee sous Windows si annee < 1970 - \param hour Hour - \param minute Minute - \param second Second - \param month Month - \param day Day - \param year Year - \param gm Time gm - \param check No check on parameters (Can use day 32, etc...) - \return timestamp Date en timestamp, '' if error - \remarks PHP mktime is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows - */ -function dolibarr_mktime($hour,$minute,$second,$month,$day,$year,$gm=0,$check=1) -{ - //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -"; - - // Check parameters - if ($check) - { - if (! $month || ! $day) return ''; - if ($day > 31) return ''; - if ($month > 12) return ''; - if ($min < 0 || $min > 60) return ''; - if ($hour < 0 || $hour > 24) return ''; - if ($min < 0 || $min > 60) return ''; - } - - $usealternatemethod=false; - if ($year <= 1970) $usealternatemethod=true; // <= 1970 - if ($year >= 2038) $usealternatemethod=true; // >= 2038 - - if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir - { - /* - // On peut utiliser strtotime pour obtenir la traduction. - // strtotime is ok for range: Vendredi 13 D�cembre 1901 20:45:54 GMT au Mardi 19 Janvier 2038 03:14:07 GMT. - $montharray=array(1=>'january',2=>'february',3=>'march',4=>'april',5=>'may',6=>'june', - 7=>'july',8=>'august',9=>'september',10=>'october',11=>'november',12=>'december'); - $string=$day." ".$montharray[0+$month]." ".$year." ".$hour.":".$minute.":".$second." GMT"; - $date=strtotime($string); - print "- ".$string." ".$date." -"; - */ - $date=adodb_mktime($hour,$minute,$second,$month,$day,$year,0,$gm); - } - else - { - $date=mktime($hour,$minute,$second,$month,$day,$year); - } - return $date; -} - - - -/** - \brief Returns formated date - \param fmt Format (Exemple: 'Y-m-d H:i:s') - \param timestamp Date. Exemple: Si timestamp=0 et gm=1, renvoi 01/01/1970 00:00:00 - \param gm 1 if timestamp was built with gmmktime, 0 if timestamp was build with mktime - \return string Formated date - */ -function dolibarr_date($fmt, $timestamp, $gm=0) -{ - $usealternatemethod=false; - if ($timestamp <= 0) $usealternatemethod=true; - if ($timestamp >= 2145913200) $usealternatemethod=true; - - if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir - { - $string=adodb_date($fmt,$timestamp,$gm); - } - else - { - $string=date($fmt,$timestamp); - } - - return $string; -} - - -/** - \brief Affiche les informations d'un objet - \param object objet a afficher - */ -function dolibarr_print_object_info($object) -{ - global $langs; - $langs->load("other"); - - if (isset($object->user_creation) && $object->user_creation->fullname) - print $langs->trans("CreatedBy")." : " . $object->user_creation->fullname . '
'; - - if (isset($object->date_creation)) - print $langs->trans("DateCreation")." : " . dolibarr_print_date($object->date_creation,"dayhourtext") . '
'; - - if (isset($object->user_modification) && $object->user_modification->fullname) - print $langs->trans("ModifiedBy")." : " . $object->user_modification->fullname . '
'; - - if (isset($object->date_modification)) - print $langs->trans("DateLastModification")." : " . dolibarr_print_date($object->date_modification,"dayhourtext") . '
'; - - if (isset($object->user_validation) && $object->user_validation->fullname) - print $langs->trans("ValidatedBy")." : " . $object->user_validation->fullname . '
'; - - if (isset($object->date_validation)) - print $langs->trans("DateValidation")." : " . dolibarr_print_date($object->date_validation,"dayhourtext") . '
'; - - if (isset($object->user_cloture) && $object->user_cloture->fullname ) - print $langs->trans("ClosedBy")." : " . $object->user_cloture->fullname . '
'; - - if (isset($object->date_cloture)) - print $langs->trans("DateClosing")." : " . dolibarr_print_date($object->date_cloture,"dayhourtext") . '
'; - - if (isset($object->user_rappro) && $object->user_rappro->fullname ) - print $langs->trans("ConciliatedBy")." : " . $object->user_rappro->fullname . '
'; - - if (isset($object->date_rappro)) - print $langs->trans("DateConciliating")." : " . dolibarr_print_date($object->date_rappro,"dayhourtext") . '
'; -} - -/** - \brief Formatage des num�ros de telephone en fonction du format d'un pays - \param phone Num�ro de telephone a formater - \param country Pays selon lequel formatter - \return string Num�ro de t�l�phone format� - */ -function dolibarr_print_phone($phone,$country="FR") -{ - $phone=trim($phone); - if (! $phone) { return $phone; } - - if (strtoupper($country) == "FR") - { - // France - if (strlen($phone) == 10) { - return substr($phone,0,2)." ".substr($phone,2,2)." ".substr($phone,4,2)." ".substr($phone,6,2)." ".substr($phone,8,2); - } - elseif (strlen($phone) == 7) - { - - return substr($phone,0,3)." ".substr($phone,3,2)." ".substr($phone,5,2); - } - elseif (strlen($phone) == 9) - { - return substr($phone,0,2)." ".substr($phone,2,3)." ".substr($phone,5,2)." ".substr($phone,7,2); - } - elseif (strlen($phone) == 11) - { - return substr($phone,0,3)." ".substr($phone,3,2)." ".substr($phone,5,2)." ".substr($phone,7,2)." ".substr($phone,9,2); - } - elseif (strlen($phone) == 12) - { - return substr($phone,0,4)." ".substr($phone,4,2)." ".substr($phone,6,2)." ".substr($phone,8,2)." ".substr($phone,10,2); - } - } - - return $phone; -} - - -/** - * \brief Return string with formated size - * \param size Size to print - * \return string Link - */ -function dol_print_size($size) -{ - global $langs; - - return $size.' '.$langs->trans("Bytes"); -} - - -/** - * \brief Show click to dial link - * \param phone Phone to call - * \param option Type of picto - * \return string Link - */ -function dol_phone_link($phone,$option=0) -{ - global $conf,$user; - - $link=''; - //if (! empty($conf->global->CLICKTODIAL_URL)) - if ($conf->clicktodial->enabled) - { - $phone=trim($phone); - $url = $conf->global->CLICKTODIAL_URL; - $url.= "?login=".urlencode($user->clicktodial_login)."&password=".urlencode($user->clicktodial_password); - $url.= "&caller=".urlencode($user->clicktodial_poste)."&called=".urlencode(trim($phone)); - $link.=''.img_phone("default",0).''; - } - return $link; -} - -/** - \brief Truncate a string to a particular length adding '...' if string larger than length - \param string String to truncate - \param size Max string size. 0 for no limit. - \param trunc Where to trunc: right, left, middle - \return string Truncated string - \remarks USE_SHORT_TITLE=0 can disable all truncings - */ -function dolibarr_trunc($string,$size=40,$trunc='right') -{ - if ($size==0) return $string; - if (! defined('USE_SHORT_TITLE') || (defined('USE_SHORT_TITLE') && USE_SHORT_TITLE)) - { - // We go always here - if ($trunc == 'right') - { - if (strlen($string) > $size) - return substr($string,0,$size).'...'; - else - return $string; - } - if ($trunc == 'middle') - { - if (strlen($string) > 2 && strlen($string) > $size) - { - $size1=round($size/2); - $size2=round($size/2); - return substr($string,0,$size1).'...'.substr($string,strlen($string) - $size2,$size2); - } - else - return $string; - } - if ($trunc == 'left') - { - if (strlen($string) > $size) - return '...'.substr($string,strlen($string) - $size,$size); - else - return $string; - } - } - else - { - return $string; - } -} - -/** - \brief Compl�te une chaine a une taille donn�e par des espaces - \param string Chaine a compl�ter - \param size Longueur de la chaine. - \param side 0=Compl�tion a droite, 1=Compl�tion a gauche - \param char Chaine de compl�tion - \return string Chaine compl�t�e - */ -function dolibarr_pad($string,$size,$side,$char=' ') -{ - $taille=sizeof($string); - $i=0; - while($i < ($size - $taille)) - { - if ($side > 0) $string.=$char; - else $string=$char.$string; - $i++; - } - return $string; -} - -/** - \brief Affiche picto propre a une notion/module (fonction g�n�rique) - \param alt Texte sur le alt de l'image - \param object Objet pour lequel il faut afficher le logo (exemple: user, group, action, bill, contract, propal, product, ...) - \return string Retourne tag img - */ -function img_object($alt, $object) -{ - global $conf,$langs; - return ''.$alt.''; -} - -/** - \brief Affiche picto (fonction g�n�rique) - \param alt Texte sur le alt de l'image - \param picto Nom de l'image a afficher (Si pas d'extension, on met '.png') - \param options Attribut suppl�mentaire a la balise img - \param pictoisfullpath If 1, image path is a full path - \return string Retourne tag img - */ -function img_picto($alt, $picto, $options='', $pictoisfullpath=0) -{ - global $conf; - if (! eregi('(\.png|\.gif)$',$picto)) $picto.='.png'; - if ($pictoisfullpath) return ''.$alt.''; - return ''.$alt.''; -} - -/** - \brief Affiche logo action - \param alt Texte sur le alt de l'image - \param numaction Determine image action - \return string Retourne tag img - */ -function img_action($alt = "default", $numaction) -{ - global $conf,$langs; - if ($alt=="default") { - if ($numaction == -1) $alt=$langs->trans("ChangeDoNotContact"); - if ($numaction == 0) $alt=$langs->trans("ChangeNeverContacted"); - if ($numaction == 1) $alt=$langs->trans("ChangeToContact"); - if ($numaction == 2) $alt=$langs->trans("ChangeContactInProcess"); - if ($numaction == 3) $alt=$langs->trans("ChangeContactDone"); - } - return ''.$alt.''; -} - - -/** - \brief Affiche logo fichier - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_file($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Show"); - return ''.$alt.''; -} - -/** - \brief Affiche logo refresh - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_refresh($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Refresh"); - return ''.$alt.''; -} - -/** - \brief Affiche logo dossier - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_folder($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Dossier"); - return ''.$alt.''; -} - -/** - \brief Affiche logo nouveau fichier - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_file_new($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Show"); - return ''.$alt.''; -} - -/** - \brief Affiche logo pdf - \param alt Texte sur le alt de l'image - \param $size Taille de l'icone : 3 = 16x16px , 2 = 14x14px - \return string Retourne tag img - */ -function img_pdf($alt = "default",$size=3) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Show"); - return ''.$alt.''; -} - -/** - \brief Affiche logo vcard - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_vcard($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("VCard"); - return ''.$alt.''; -} - -/** - \brief Affiche logo + - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_edit_add($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Add"); - return ''.$alt.''; -} -/** - \brief Affiche logo - - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_edit_remove($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Remove"); - return ''.$alt.''; -} - -/** - \brief Affiche logo editer/modifier fiche - \param alt Texte sur le alt de l'image - \param float Si il faut y mettre le style "float: right" - \return string Retourne tag img - */ -function img_edit($alt = "default", $float=0, $other='') -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Modify"); - $img=''.$alt.'trans("Delete"); - return ''.$alt.''; -} - -/** - \brief Affiche logo d�sactiver - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_disable($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Disable"); - return ''.$alt.''; -} - - -/** - \brief Affiche logo help avec curseur "?" - \return string Retourne tag img - */ -function img_help($usehelpcursor=1,$usealttitle=1) -{ - global $conf,$langs; - $s ='theme.'/img/info.png" border="0"'; - if ($usealttitle) $s.=' alt="'.$langs->trans("Info").'" title="'.$langs->trans("Info").'"'; - $s.='>'; - return $s; -} - -/** - \brief Affiche picto calendrier "?" - \return string Retourne tag img - */ -function img_cal() -{ - global $conf,$langs; - return ''; -} - -/** - \brief Affiche logo info - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_info($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Informations"); - return ''.$alt.''; -} - -/** - \brief Affiche logo calculatrice - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_calc($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Calculate"); - return ''.$alt.''; -} - -/** - \brief Affiche logo warning - \param alt Texte sur le alt de l'image - \param float Si il faut afficher le style "float: right" - \return string Retourne tag img - */ -function img_warning($alt = "default",$float=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Warning"); - $img=''.$alt.'trans("Error"); - return ''.$alt.''; -} - -/** - \brief Affiche logo alerte - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_alerte($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Alert"); - return ''.$alt.''; -} - -/** - \brief Affiche logo t�l�phone - \param alt Texte sur le alt de l'image - \param option Choose of logo - \return string Retourne tag img - */ -function img_phone($alt = "default",$option=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Call"); - $img='call_out'; - if ($option == 1) $img='call'; - $img='object_commercial'; - return ''.$alt.''; -} - - -/** - \brief Affiche logo suivant - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_next($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") { - $alt=$langs->trans("Next"); - } - return ''.$alt.''; -} - -/** - \brief Affiche logo pr�c�dent - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_previous($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Previous"); - return ''.$alt.''; -} - -/** - \brief Affiche logo bas - \param alt Texte sur le alt de l'image - \param selected Affiche version "selected" du logo - \return string Retourne tag img - */ -function img_down($alt = "default", $selected=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Down"); - if ($selected) return ''.$alt.''; - else return ''.$alt.''; -} - -/** - \brief Affiche logo haut - \param alt Texte sur le alt de l'image - \param selected Affiche version "selected" du logo - \return string Retourne tag img - */ -function img_up($alt = "default", $selected=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Up"); - if ($selected) return ''.$alt.''; - else return ''.$alt.''; -} - -/** - \brief Affiche logo gauche - \param alt Texte sur le alt de l'image - \param selected Affiche version "selected" du logo - \return string Retourne tag img - */ -function img_left($alt = "default", $selected=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Left"); - if ($selected) return ''.$alt.''; - else return ''.$alt.''; -} - -/** - \brief Affiche logo droite - \param alt Texte sur le alt de l'image - \param selected Affiche version "selected" du logo - \return string Retourne tag img - */ -function img_right($alt = "default", $selected=0) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Right"); - if ($selected) return ''.$alt.''; - else return ''.$alt.''; -} - -/** - \brief Affiche logo tick - \param alt Texte sur le alt de l'image - \return string Retourne tag img - */ -function img_tick($alt = "default") -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Active"); - return ''.$alt.''; -} - -/** - \brief Affiche le logo tick si allow - \param allow Authorise ou non - \return string Retourne tag img - */ -function img_allow($allow) -{ - global $conf,$langs; - if ($alt=="default") $alt=$langs->trans("Active"); - - if ($allow == 1) - { - return ''.$alt.''; - } - else - { - return "-"; - } -} - - -/** - * \brief Show mime picto - * \param file Filename - * \param alt Alternate text - * \return string Return img tag - */ -function img_mime($file,$alt='') -{ - $mime='other'; - if (eregi('\.pdf',$file)) { $mime='pdf'; } - if (eregi('\.(html|htm)',$file)) { $mime='html'; } - if (eregi('\.txt',$file)) { $mime='other'; } - if (eregi('\.php',$file)) { $mime='php'; } - if (eregi('\.pl',$file)) { $mime='pl'; } - if (eregi('\.js',$file)) { $mime='jscript'; } - if (eregi('\.(png|bmp|jpg|jpeg|gif)',$file)) $mime='image'; - if (eregi('\.(mp3|ogg|au)',$file)) $mime='audio'; - if (eregi('\.(avi|mvw|divx|xvid)',$file)) $mime='video'; - if (eregi('\.(zip|rar|gz|tgz|z|cab|bz2)',$file)) $mime='archive'; - if (empty($alt)) $alt='Mime type: '.$mime; - - $mime.='.png'; - return ''.$alt.''; -} - - -/** - \brief Return if a filename is file name of a supported image format - \param file Filename - \return int -1=Not image filename, 0=Image filename but format not supported by PHP, 1=Image filename with format supported - */ -function image_format_supported($file) -{ - // Case filename is not a format image - if (! eregi('(\.gif|\.jpg|\.jpeg|\.png|\.bmp)$',$file,$reg)) return -1; - - // Case filename is a format image but not supported by this PHP - $imgfonction=''; - if (strtolower($reg[1]) == '.gif') $imgfonction = 'imagecreatefromgif'; - if (strtolower($reg[1]) == '.png') $imgfonction = 'imagecreatefrompng'; - if (strtolower($reg[1]) == '.jpg') $imgfonction = 'imagecreatefromjpeg'; - if (strtolower($reg[1]) == '.jpeg') $imgfonction = 'imagecreatefromjpeg'; - if (strtolower($reg[1]) == '.bmp') $imgfonction = 'imagecreatefromwbmp'; - if ($imgfonction) - { - if (! function_exists($imgfonction)) - { - // Fonctions de conversion non presente dans ce PHP - return 0; - } - } - - // Filename is a format image and supported by this PHP - return 1; -} - -/** - \brief Affiche info admin - \param text Text info - \param infoonimgalt Info is shown on alt of star picto - \return string String with info text - */ -function info_admin($texte,$infoonimgalt=0) -{ - global $conf,$langs; - $s=''; - if ($infoonimgalt) - { - $s.=img_picto($texte,'star'); - } - else - { - $s.='
'; - $s.=img_picto($langs->trans("InfoAdmin"),'star'); - $s.=' '; - $s.=$texte; - $s.='
'; - } - return $s; -} - - -/** - \brief Check permissions of a user to show a page and an object. - \param user User to check - \param feature Feature to check (in most cases, it's module name) - \param objectid Object ID if we want to check permission on on object (optionnal) - \param dbtable Table name where object is stored. Not used if objectid is null (optionnel) - \param feature Feature to check (second level of permission) - */ -function restrictedArea($user, $feature='societe', $objectid=0, $dbtablename='',$feature2='') -{ - global $db; - - //print "$user->id, $feature, $objectid, $dbtablename, $list ".$user->rights->societe->contact->lire; - - // Check read permission from module - // TODO Replace "feature" param by permission for reading - $readok=1; - if ($feature == 'societe') - { - if (! $user->rights->societe->lire && ! $user->rights->fournisseur->lire) $readok=0; - } - else if ($feature == 'contact') - { - if (! $user->rights->societe->contact->lire) $readok=0; - } - else if ($feature == 'prelevement') - { - if (! $user->rights->prelevement->bons->lire) $readok=0; - } - else if ($feature == 'commande_fournisseur') - { - if (! $user->rights->fournisseur->commande->lire) $readok=0; - } - else if ($feature == 'cheque') - { - if (! $user->rights->banque->cheque) $readok=0; - } - else if (! empty($feature2)) // This should be used for future changes - { - if (! $user->rights->$feature->$feature2->read) $readok=0; - } - else if (! empty($feature)) // This is for old permissions - { - if (! $user->rights->$feature->lire) $readok=0; - } - if (! $readok) accessforbidden(); - //print "Read access is ok"; - - // Check write permission from module - // TODO Add after "feature" a param for permission for writing - $createok=1; - if ($_GET["action"] == 'create' || $_POST["action"] == 'create') - { - if ($feature == 'societe') - { - if (! $user->rights->societe->creer && ! $user->rights->fournisseur->creer) $createok=0; - } - else if ($feature == 'contact') - { - if (! $user->rights->societe->contact->creer) $createok=0; - } - else if ($feature == 'prelevement') - { - if (! $user->rights->prelevement->bons->creer) $createok=0; - } - else if ($feature == 'commande_fournisseur') - { - if (! $user->rights->fournisseur->commande->creer) $createok=0; - } - else if ($feature == 'banque') - { - if (! $user->rights->banque->modifier) $createok=0; - } - else if ($feature == 'cheque') - { - if (! $user->rights->banque->cheque) $createok=0; - } - else - { - if (! $user->rights->$feature->creer) $createok=0; - } - if (! $createok) accessforbidden(); - //print "Write access is ok"; - } - - // If we have a particular object to check permissions on - if ($objectid) - { - $sql=''; - // Check permission for external users - if ($user->societe_id > 0) - { - if ($feature == 'societe') - { - if ($user->societe_id <> $objectid) accessforbidden(); - } - else - { - if (!$dbtablename) $dbtablename = $feature; // Si dbtable non d�fini, meme nom que le module - - $sql = "SELECT dbt.fk_soc"; - $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; - $sql.= " WHERE dbt.rowid = ".$objectid; - $sql.= " AND dbt.fk_soc = ".$user->societe_id; - } - } - // Check permission for internal users that are restricted on their objects - else if (! $user->rights->societe->client->voir) - { - if ($feature == 'societe') - { - $sql = "SELECT sc.fk_soc"; - $sql.= " FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc"; - $sql.= " WHERE sc.fk_soc = ".$objectid." AND sc.fk_user = ".$user->id; - } - else - { - if (!$dbtablename) $dbtablename = $feature; // Si dbtable non d�fini, meme nom que le module - - $sql = "SELECT sc.fk_soc"; - $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.fk_soc"; - $sql.= " WHERE dbt.rowid = ".$objectid; - $sql.= " AND IFNULL(sc.fk_user, ".$user->id.") = ".$user->id; - } - } - - //print $sql; - if ($sql) - { - $resql=$db->query($sql); - if ($resql) - { - if ($db->num_rows($resql) == 0) accessforbidden(); - } - else - { - dolibarr_syslog("functions.lib.php::restrictedArea sql=".$sql, LOG_ERR); - accessforbidden(); - } - } - } - - return 1; -} - - -/** - \brief Affiche message erreur de type acces interdit et arrete le programme - \param message Force error message - \param printheader Affiche avant le header - \remarks L'appel a cette fonction termine le code. - */ -function accessforbidden($message='',$printheader=1) -{ - global $user, $langs; - $langs->load("other"); - - if ($printheader && function_exists("llxHeader")) llxHeader(); - print '
'; - if (! $message) print $langs->trans("ErrorForbidden"); - else print $message; - print '
'; - print '
'; - if ($user->login) - { - print $langs->trans("CurrentLogin").': '.$user->login.'
'; - print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); - } - elseif (! empty($_SERVER["REMOTE_USER"])) - { - print $langs->trans("CurrentLogin").': '.$_SERVER["REMOTE_USER"]."
"; - print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); - } - else - { - print $langs->trans("ErrorForbidden3"); - } - if (function_exists("llxFooter")) llxFooter(); - exit(0); -} - - -/** - * \brief Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remont�e des bugs. - * On doit appeler cette fonction quand une erreur technique bloquante est rencontree. - * Toutefois, il faut essayer de ne l'appeler qu'au sein de pages php, les classes devant - * renvoyer leur erreur par l'intermediaire de leur propriete "error". - * \param db Database handler - * \param error Chaine erreur ou tableau de chaines erreur complementaires a afficher - */ -function dolibarr_print_error($db='',$error='') -{ - global $conf,$langs,$argv; - $syslog = ''; - - // Si erreur intervenue avant chargement langue - if (! $langs) - { - require_once(DOL_DOCUMENT_ROOT ."/translate.class.php"); - $langs = new Translate("", $conf); - } - $langs->load("main"); - - if ($_SERVER['DOCUMENT_ROOT']) // Mode web - { - print $langs->trans("DolibarrHasDetectedError").".
\n"; - print $langs->trans("InformationToHelpDiagnose").":

\n"; - - print "".$langs->trans("Dolibarr").": ".DOL_VERSION."
\n";; - if (isset($conf->global->MAIN_FEATURES_LEVEL)) print "".$langs->trans("LevelOfFeature").": ".$conf->global->MAIN_FEATURES_LEVEL."
\n";; - print "".$langs->trans("Server").": ".$_SERVER["SERVER_SOFTWARE"]."
\n";; - print "".$langs->trans("RequestedUrl").": ".$_SERVER["REQUEST_URI"]."
\n";; - print "".$langs->trans("Referer").": ".$_SERVER["HTTP_REFERER"]."
\n";; - $syslog.="url=".$_SERVER["REQUEST_URI"]; - $syslog.=", query_string=".$_SERVER["QUERY_STRING"]; - } - else // Mode CLI - { - print '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n"; - $syslog.="pid=".getmypid(); - } - - if (is_object($db)) - { - if ($_SERVER['DOCUMENT_ROOT']) // Mode web - { - print "
\n"; - print "".$langs->trans("DatabaseTypeManager").": ".$db->type."
\n"; - print "".$langs->trans("RequestLastAccessInError").": ".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."
\n"; - print "".$langs->trans("ReturnCodeLastAccessInError").": ".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."
\n"; - print "".$langs->trans("InformationLastAccessInError").": ".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."
\n"; - } - else // Mode CLI - { - print '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n"; - print '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."\n"; - print '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."\n"; - print '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."\n"; - - } - $syslog.=", sql=".$db->lastquery(); - $syslog.=", db_error=".$db->lasterror(); - } - - if ($error) - { - $langs->load("errors"); - - if (is_array($error)) $errors=$error; - else $errors=array($error); - - foreach($errors as $msg) - { - $msg=$langs->trans($msg); - if ($_SERVER['DOCUMENT_ROOT']) // Mode web - { - print "".$langs->trans("Message").": ".$msg."
\n" ; - } - else // Mode CLI - { - print '> '.$langs->transnoentities("Message").":\n".$msg."\n" ; - } - $syslog.=", msg=".$msg; - } - } - - dolibarr_syslog("Error ".$syslog, LOG_ERR); -} - - -/** - * \brief Deplacer les fichiers telecharg�s, apres quelques controles divers - * \param src_file Source filename - * \param dest_file Target filename - * \param allowoverwrite Overwrite if exists - * \return int >0 if OK, <0 if KO, Name of virus if virus found - */ -function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite) -{ - global $conf; - - $file_name = $dest_file; - - // If we need to make a virus scan - if ($conf->global->MAIN_USE_AVSCAN) - { - $malware = dol_avscan_file($src_file); - if ($malware) return $malware; - } - - // Security: - // On renomme les fichiers avec extention script web car si on a mis le rep - // documents dans un rep de la racine web (pas bien), cela permet d'executer - // du code a la demande. - if (eregi('\.htm|\.html|\.php|\.pl|\.cgi$',$file_name)) - { - $file_name.= '.noexe'; - } - - // Security: - // On interdit les remont�es de repertoire ainsi que les pipes dans - // les noms de fichiers. - if (eregi('\.\.',$src_file) || eregi('[<>|]',$src_file)) - { - dolibarr_syslog("Refused to deliver file ".$src_file); - return -1; - } - - // Security: - // On interdit les remont�es de repertoire ainsi que les pipe dans - // les noms de fichiers. - if (eregi('\.\.',$dest_file) || eregi('[<>|]',$dest_file)) - { - dolibarr_syslog("Refused to deliver file ".$dest_file); - return -1; - } - - // Check if destination file already exists - if (! $allowoverwrite) - { - if (file_exists($file_name)) - { - dolibarr_syslog("Functions.lib::dol_move_uploaded_file File ".$file_name." already exists", LOG_WARNING); - return -2; - } - } - - // Move file - $return=move_uploaded_file($src_file, $file_name); - if ($return) - { - dolibarr_syslog("Functions.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name, LOG_DEBUG); - return 1; - } - else - { - dolibarr_syslog("Functions.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR); - return -3; - } -} - - -/** - \brief Show title line of an array - \param name libelle champ - \param file url pour clic sur tri - \param field champ de tri - \param begin ("" par defaut) - \param options ("" par defaut) - \param td options de l'attribut td ("" par defaut) - \param sortfield nom du champ sur lequel est effectu� le tri du tableau - \param sortorder ordre du tri - */ -function print_liste_field_titre($name, $file, $field, $begin="", $options="", $td="", $sortfield="", $sortorder="") -{ - global $conf; - //print "$name, $file, $field, $begin, $options, $td, $sortfield, $sortorder
\n"; - - // Le champ de tri est mis en �vidence. - // Exemple si (sortfield,field)=("nom","xxx.nom") ou (sortfield,field)=("nom","nom") - if ($sortfield == $field || $sortfield == ereg_replace("^[^\.]+\.","",$field)) - { - print ''; - } - else - { - print ''; - } - print $name; - - // If this is a sort field - if ($field) - { - //print " "; - print ''; - if (! $sortorder) - { - print ''.img_down("A-Z",0).''; - print ''.img_up("Z-A",0).''; - } - else - { - if ($field != $sortfield) - { - print ''.img_down("A-Z",0).''; - print ''.img_up("Z-A",0).''; - } - else { - $sortorder=strtoupper($sortorder); - if ($sortorder == 'DESC' ) { - print ''.img_down("A-Z",0).''; - print ''.img_up("Z-A",1).''; - } - if ($sortorder == 'ASC' ) { - print ''.img_down("A-Z",1).''; - print ''.img_up("Z-A",0).''; - } - } - } - } - print ""; -} - -/** - \brief Affichage d'un titre - \param titre Le titre a afficher - */ -function print_titre($titre) -{ - print '
'.$titre.'
'; -} - -/** - \brief Affichage d'un titre d'une fiche, align� a gauche - \param titre Le titre a afficher - \param mesg Message supl�mentaire a afficher a droite - \param picto Picto pour ligne de titre - \param pictoisfullpath 1=Picto is a full absolute url of image - */ -function print_fiche_titre($titre, $mesg='', $picto='', $pictoisfullpath=0) -{ - print "\n"; - print ''; - if ($picto) print ''; - print ''; - if (strlen($mesg)) - { - print ''; - } - print '
'.img_picto('',$picto, '', $pictoisfullpath).''; - print '
'.$titre.'
'; - print '
'.$mesg.'
'."\n"; -} - -/** - \brief Effacement d'un fichier - \param file Fichier a effacer ou masque de fichier a effacer - \param boolean true if file deleted, false if error - */ -function dol_delete_file($file) -{ - $ok=true; - foreach (glob($file) as $filename) - { - $ok=unlink($filename); - if ($ok) dolibarr_syslog("Removed file $filename",LOG_DEBUG); - else dolibarr_syslog("Failed to remove file $filename",LOG_ERR); - } - return $ok; -} - -/** - \brief Effacement d'un r�pertoire - \param file R�pertoire a effacer - */ -function dol_delete_dir($dir) -{ - return rmdir($dir); -} - -/** - \brief Effacement d'un r�pertoire $dir et de son arborescence - \param file R�pertoire a effacer - \param count Compteur pour comptage nb elements supprim�s - \return int Nombre de fichier+rep�rtoires supprim�s - */ -function dol_delete_dir_recursive($dir,$count=0) -{ - if ($handle = opendir("$dir")) - { - while (false !== ($item = readdir($handle))) - { - if ($item != "." && $item != "..") - { - if (is_dir("$dir/$item")) - { - $count=dol_delete_dir_recursive("$dir/$item",$count); - } - else - { - unlink("$dir/$item"); - $count++; - //echo " removing $dir/$item
\n"; - } - } - } - closedir($handle); - rmdir($dir); - $count++; - //echo "removing $dir
\n"; - } - - //echo "return=".$count; - return $count; -} - -/** - \brief Scan les fichiers avec un anti-virus - \param file Fichier a scanner - \return malware Nom du virus si infect� sinon retourne "null" - */ -function dol_avscan_file($file) -{ - $malware = ''; - - // Clamav - if (function_exists("cl_scanfile")) - { - $maxreclevel = 5 ; // maximal recursion level - $maxfiles = 1000; // maximal number of files to be scanned within archive - $maxratio = 200; // maximal compression ratio - $archivememlim = 0; // limit memory usage for bzip2 (0/1) - $maxfilesize = 10485760; // archived files larger than this value (in bytes) will not be scanned - - cl_setlimits($maxreclevel, $maxfiles, $maxratio, $archivememlim, $maxfilesize); - $malware = cl_scanfile($file); - } - - return $malware; -} - -/** - \brief Fonction print_barre_liste - \param titre Titre de la page - \param page num�ro de la page - \param file lien - \param options parametres complementaires lien ('' par defaut) - \param sortfield champ de tri ('' par defaut) - \param sortorder ordre de tri ('' par defaut) - \param center chaine du centre ('' par defaut) - \param num number of records found by select with limit+1 - \param totalnboflines Total number of records/lines for all pages (if known) - */ -function print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $center='', $num=-1, $totalnboflines=0) -{ - global $conf,$langs; - - if ($num > $conf->liste_limit or $num == -1) - { - $nextpage = 1; - } - else - { - $nextpage = 0; - } - - print ''; - - $pagelist = ''; - - if ($page > 0 || $num > $conf->liste_limit) - { - if ($totalnboflines) - { - print ''; - - $maxnbofpage=10; - - $nbpages=ceil($totalnboflines/$conf->liste_limit); - $cpt=($page-$maxnbofpage); - if ($cpt < 0) { $cpt=0; } - $pagelist.=$langs->trans('Page'); - if ($cpt>=1) - { - $pagelist.=' 1'; - if ($cpt >= 2) $pagelist.=' ...'; - } - do - { - if($cpt==$page) - { - $pagelist.= ' '.($page+1).''; - } - else - { - $pagelist.= ' '.($cpt+1).''; - } - $cpt++; - } - while ($cpt < $nbpages && $cpt<=$page+$maxnbofpage); - if ($cpt<$nbpages) - { - if ($cpt<$nbpages-1) $pagelist.= ' ...'; - $pagelist.= ' '.$nbpages.''; - } - } - else - { - print ''; - } - } - else - { - print ''; - } - - if ($center) - { - print ''; - } - - print '
'; - print '
'.$titre.'
'; - print '
'; - print '
'.$titre.'
'; - $pagelist.= $langs->trans('Page').' '.($page+1); - print '
'.$titre.'
'.$center.''; - - if ($sortfield) $options .= "&sortfield=".$sortfield; - if ($sortorder) $options .= "&sortorder=".$sortorder; - - // Affichage des fleches de navigation - print_fleche_navigation($page,$file,$options,$nextpage,$pagelist); - - print '
'; -} - -/** - \brief Fonction servant a afficher les fleches de navigation dans les pages de listes - \param page Num�ro de la page - \param file Lien - \param options Autres parametres d'url a propager dans les liens ("" par defaut) - \param nextpage Faut-il une page suivante - \param betweenarraows HTML Content to show between arrows - */ -function print_fleche_navigation($page,$file,$options='',$nextpage,$betweenarrows='') -{ - global $conf, $langs; - if ($page > 0) - { - print ''.img_previous($langs->trans("Previous")).''; - } - if ($betweenarrows) print ($page > 0?' ':'').$betweenarrows.($nextpage>0?' ':''); - if ($nextpage > 0) - { - print ''.img_next($langs->trans("Next")).''; - } -} - - -/** - * \brief Fonction qui retourne un taux de tva format� pour visualisation - * \remarks Fonction utilis�e dans les pdf et les pages html - * \param rate Rate value to format (19.6 19,6 19.6% 19,6%,...) - * \param foundpercent Add a percent % sign in output - * \param info_bits Miscellanous information on vat - * \return string Chaine avec montant format� (19,6 ou 19,6% ou 8.5% *) - */ -function vatrate($rate,$addpercent=false,$info_bits=0) -{ - // Test for compatibility - if (eregi('%',$rate)) - { - $rate=eregi_replace('%','',$rate); - $addpercent=true; - } - if (eregi('\*',$rate) || eregi(MAIN_LABEL_MENTION_NPR,$rate)) - { - $rate=eregi_replace('\*','',$rate); - $info_bits |= 1; - } - - $ret=price($rate,0,'',0,0).($addpercent?'%':''); - if ($info_bits & 1) $ret.=' '.MAIN_LABEL_MENTION_NPR; - return $ret; -} - - -/** - * \brief Fonction qui retourne un montant mon�taire format� pour visualisation - * \remarks Fonction utilis�e dans les pdf et les pages html - * \param amount Montant a formater - * \param html Formatage html ou pas (0 par defaut) - * \param outlangs Objet langs pour formatage text - * \param trunc 1=Tronque affichage si trop de d�cimales,0=Force le non troncage - * \param nbdecimal Nbre decimals minimum. - * \return string Chaine avec montant format� - * \seealso price2num Fonction inverse de price - */ -function price($amount, $html=0, $outlangs='', $trunc=1, $nbdecimal=2) -{ - global $langs,$conf; - - // Separateurs par defaut - $dec='.'; $thousand=' '; - - // Si $outlangs non force, on prend langue utilisateur - if (! is_object($outlangs)) $outlangs=$langs; - - if ($outlangs->trans("SeparatorDecimal") != "SeparatorDecimal") $dec=$outlangs->trans("SeparatorDecimal"); - if ($outlangs->trans("SeparatorThousand")!= "SeparatorThousand") $thousand=$outlangs->trans("SeparatorThousand"); - //print "amount=".$amount." html=".$html." trunc=".$trunc." nbdecimal=".$nbdecimal." dec=".$dec." thousand=".$thousand; - - //print "amount=".$amount."-"; - $amount = ereg_replace(',','.',$amount); - //print $amount."-"; - $datas = split('\.',$amount); - $decpart = $datas[1]; - $decpart = eregi_replace('0+$','',$decpart); // Supprime les 0 de fin de partie d�cimale - //print "decpart=".$decpart."
"; - $end=''; - - // On augmente au besoin si il y a plus de 2 d�cimales - if (strlen($decpart) > $nbdecimal) $nbdecimal=strlen($decpart); - // Si on depasse max - if ($trunc && $nbdecimal > $conf->global->MAIN_MAX_DECIMALS_SHOWN) - { - $nbdecimal=$conf->global->MAIN_MAX_DECIMALS_SHOWN; - if (eregi('\.\.\.',$conf->global->MAIN_MAX_DECIMALS_SHOWN)) - { - // Si un affichage est tronqu�, on montre des ... - $end='...'; - } - } - - // Formate nombre - if ($html) - { - $output=ereg_replace(' ',' ',number_format($amount, $nbdecimal, $dec, $thousand)); - } - else - { - $output=number_format($amount, $nbdecimal, $dec, $thousand); - } - $output.=$end; - - return $output; -} - -/** - * \brief Fonction qui retourne un numerique conforme PHP et SQL, depuis un montant au - * format utilisateur. - * \remarks Fonction a appeler sur montants saisis avant un insert en base - * \param amount Montant a formater - * \param rounding 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT) - * 'MT'=Round to Max with Tax (MAIN_MAX_DECIMALS_TOT) - * 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN) - * ''=No rounding - * \return string Montant au format num�rique PHP et SQL (Exemple: '99.99999') - * \seealso price Fonction inverse de price2num - */ -function price2num($amount,$rounding='') -{ - global $conf; - - // Round PHP function does not allow number like '1,234.5'. - // Numbers must be '1234.5' - // \TODO If there is already a ".", we remove ",", otherwise replace by "." - $amount=ereg_replace(',','.',$amount); - $amount=ereg_replace(' ','',$amount); - if ($rounding) - { - if ($rounding == 'MU') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_UNIT); - elseif ($rounding == 'MT') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_TOT); - elseif ($rounding == 'MS') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_SHOWN); - else $amount='ErrorBadParameterProvidedToFunction'; - $amount=ereg_replace(',','.',$amount); - $amount=ereg_replace(' ','',$amount); - } - return $amount; -} - - -/** - * \brief Return vat rate of a product in a particular selling country - */ -function get_product_vat_for_country($idprod, $countrycode) -{ - global $db; - - $product=new Product($db); - $product->fetch($idprod); - - // \TODO Read rate according to countrycode - // For the moment only one rate supported - - return $product->tva_tx; -} - - -/** - \brief Fonction qui renvoie la tva d'une ligne (en fonction du vendeur, acheteur et taux du produit) - \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. - Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle. - Sinon TVA propos�e par d�faut=0. Fin de r�gle. - \param societe_vendeuse Objet soci�t� vendeuse - \param societe_acheteuse Objet soci�t� acheteuse - \param taux_produit Taux par defaut du produit vendu (old way to get product vat rate) - \param idprod Id product (new way to get product vat rate) - \return float Taux de tva a appliquer, -1 si ne peut etre d�termin� - */ -function get_default_tva($societe_vendeuse, $societe_acheteuse, $taux_produit, $idprod=0) -{ - if (!is_object($societe_vendeuse)) return -1; - if (!is_object($societe_acheteuse)) return -1; - - dolibarr_syslog("get_default_tva vendeur_assujeti=".$societe_vendeuse->tva_assuj." pays_vendeur=".$societe_vendeuse->pays_code.", seller in cee=".$societe_vendeuse->isInEEC().", pays_acheteur=".$societe_acheteuse->pays_code.", buyer in cee=".$societe_acheteuse->isInEEC().", taux_produit(deprecated)=".$taux_produit.", idprod=".$idprod); - - // Si vendeur non assujeti a TVA (tva_assuj vaut 0/1 ou franchise/reel) - if (is_numeric($societe_vendeuse->tva_assuj) && ! $societe_vendeuse->tva_assuj) return 0; - if (! is_numeric($societe_vendeuse->tva_assuj) && $societe_vendeuse->tva_assuj=='franchise') return 0; - - // Si le (pays vendeur = pays acheteur) alors la TVA par d�faut=TVA du produit vendu. Fin de r�gle. - //if (is_object($societe_acheteuse) && ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) && ($societe_acheteuse->tva_assuj == 1 || $societe_acheteuse->tva_assuj == 'reel')) - // Le test ci-dessus ne devrait pas etre necessaire. Me signaler l'exemple du cas juridique concercn� si le test suivant n'est pas suffisant. - if ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) - { - if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); - if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva - return $taux_produit; - } - - // Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. - // Non g�r� - - // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. - if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && ! $societe_acheteuse->tva_intra) - { - if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); - if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva - return $taux_produit; - } - - // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA intra) alors TVA par d�faut=0. Fin de r�gle. - if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && $societe_acheteuse->tva_intra) - { - return 0; - } - - // Sinon la TVA propos�e par d�faut=0. Fin de r�gle. - // Rem: Cela signifie qu'au moins un des 2 est hors Communaut� europ�enne et que le pays diff�re - return 0; -} - - -/** - \brief Fonction qui renvoie si tva doit etre tva percue r�cup�rable - \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. - Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. - Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle. - Sinon TVA propos�e par d�faut=0. Fin de r�gle. - \param societe_vendeuse Objet soci�t� vendeuse - \param societe_acheteuse Objet soci�t� acheteuse - \param taux_produit Taux par defaut du produit vendu - \return float 0 or 1 - */ -function get_default_npr($societe_vendeuse, $societe_acheteuse, $taux_produit) -{ - - return 0; -} - - -/** - \brief Renvoie oui ou non dans la langue choisie - \param yesno Variable pour test si oui ou non - \param case 1=Yes/No, 0=yes/no - \param color 0=texte only, 1=Text is format with a color font style - */ -function yn($yesno, $case=1, $color=0) -{ - global $langs; - $result='unknown'; - if ($yesno == 1 || strtolower($yesno) == 'yes' || strtolower($yesno) == 'true') // A mettre avant test sur no a cause du == 0 - { - $result=($case?$langs->trans("Yes"):$langs->trans("yes")); - $class='ok'; - } - elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') - { - $result=($case?$langs->trans("No"):$langs->trans("no")); - $class='error'; - } - if ($color) return ''.$result.''; - return $result; -} - - -/** - \brief Fonction pour qui retourne le rowid d'un departement par son code - \param db handler d'acc�s base - \param code Code r�gion - \param pays_id Id du pays - */ -function departement_rowid($db,$code, $pays_id) -{ - $sql = "SELECT c.rowid FROM ".MAIN_DB_PREFIX."c_departements as c,".MAIN_DB_PREFIX."c_regions as r"; - $sql .= " WHERE c.code_departement=". $code; - $sql .= " AND c.fk_region = r.code_region"; - $sql .= " AND r.fk_pays =".$pays_id; - - if ($db->query($sql)) - { - $num = $db->num_rows(); - if ($num) - { - $obj = $db->fetch_object(); - return $obj->rowid; - } - else - { - return 0; - } - $db->free(); - } - else - { - return 0; - } -} - -/** - \brief Renvoi un chemin de classement r�pertoire en fonction d'un id - \remarks Examples: 1->"0/0/1/", 15->"0/1/5/" - \param $num Id a d�composer - \param $level Niveau de decoupage (1, 2 ou 3 niveaux) - */ -function get_exdir($num,$level=3) -{ - $num = eregi_replace('[^0-9]','',$num); - $num = substr("000".$num, -$level); - if ($level == 1) return substr($num,0,1).'/'; - if ($level == 2) return substr($num,1,1).'/'.substr($num,0,1).'/'; - if ($level == 3) return substr($num,2,1).'/'.substr($num,1,1).'/'.substr($num,0,1).'/'; - return ''; -} - -/** - \brief Cr�ation de r�pertoire recursive - \param $dir R�pertoire a cr�er - \return int < 0 si erreur, >= 0 si succ�s - */ -function create_exdir($dir) -{ - dolibarr_syslog("functions.lib.php::create_exdir: dir=$dir",LOG_INFO); - - if (@is_dir($dir)) return 0; - - $nberr=0; - $nbcreated=0; - - $ccdir = ''; - $cdir = explode("/",$dir); - for ($i = 0 ; $i < sizeof($cdir) ; $i++) - { - if ($i > 0) $ccdir .= '/'.$cdir[$i]; - else $ccdir = $cdir[$i]; - if (eregi("^.:$",$ccdir,$regs)) continue; // Si chemin Windows incomplet, on poursuit par rep suivant - - // Attention, le is_dir() peut �chouer bien que le rep existe. - // (ex selon config de open_basedir) - if ($ccdir) - { - if (! @is_dir($ccdir)) - { - dolibarr_syslog("functions.lib.php::create_exdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.",LOG_DEBUG); - - umask(0); - if (! @mkdir($ccdir, 0755)) - { - // Si le is_dir a renvoy� une fausse info, alors on passe ici. - dolibarr_syslog("functions.lib.php::create_exdir: Fails to create directory '".$ccdir."' or directory already exists.",LOG_WARNING); - $nberr++; - } - else - { - dolibarr_syslog("functions.lib.php::create_exdir: Directory '".$ccdir."' created",LOG_DEBUG); - $nberr=0; // On remet a z�ro car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s - $nbcreated++; - } - } - else - { - $nberr=0; // On remet a z�ro car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s - } - } - } - return ($nberr ? -$nberr : $nbcreated); -} - - - - -/** - \brief Retourne le num�ro de la semaine par rapport a une date - \param time Date au format 'timestamp' - \return int Num�ro de semaine - */ -function numero_semaine($time) -{ - $stime = strftime( '%Y-%m-%d',$time); - - if (eregi('^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?',$stime,$reg)) - { - // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' - $annee = $reg[1]; - $mois = $reg[2]; - $jour = $reg[3]; - } - - /* - * Norme ISO-8601: - * - La semaine 1 de toute ann�e est celle qui contient le 4 janvier ou que la semaine 1 de toute ann�e est celle qui contient le 1er jeudi de janvier. - * - La majorit� des ann�es ont 52 semaines mais les ann�es qui commence un jeudi et les ann�es bissextiles commen�ant un mercredi en poss�de 53. - * - Le 1er jour de la semaine est le Lundi - */ - - // D�finition du Jeudi de la semaine - if (date("w",mktime(12,0,0,$mois,$jour,$annee))==0) // Dimanche - $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-3*24*60*60; - else if (date("w",mktime(12,0,0,$mois,$jour,$annee))<4) // du Lundi au Mercredi - $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)+(4-date("w",mktime(12,0,0,$mois,$jour,$annee)))*24*60*60; - else if (date("w",mktime(12,0,0,$mois,$jour,$annee))>4) // du Vendredi au Samedi - $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-(date("w",mktime(12,0,0,$mois,$jour,$annee))-4)*24*60*60; - else // Jeudi - $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee); - - // D�finition du premier Jeudi de l'ann�e - if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==0) // Dimanche - { - $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+4*24*60*60; - } - else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))<4) // du Lundi au Mercredi - { - $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(4-date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine))))*24*60*60; - } - else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))>4) // du Vendredi au Samedi - { - $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(7-(date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))-4))*24*60*60; - } - else // Jeudi - { - $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine)); - } - - // D�finition du num�ro de semaine: nb de jours entre "premier Jeudi de l'ann�e" et "Jeudi de la semaine"; - $numeroSemaine = ( - ( - date("z",mktime(12,0,0,date("m",$jeudiSemaine),date("d",$jeudiSemaine),date("Y",$jeudiSemaine))) - - - date("z",mktime(12,0,0,date("m",$premierJeudiAnnee),date("d",$premierJeudiAnnee),date("Y",$premierJeudiAnnee))) - ) / 7 - ) + 1; - - // Cas particulier de la semaine 53 - if ($numeroSemaine==53) - { - // Les ann�es qui commence un Jeudi et les ann�es bissextiles commen�ant un Mercredi en poss�de 53 - if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==4 || (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==3 && date("z",mktime(12,0,0,12,31,date("Y",$jeudiSemaine)))==365)) - { - $numeroSemaine = 53; - } - else - { - $numeroSemaine = 1; - } - } - - //echo $jour."-".$mois."-".$annee." (".date("d-m-Y",$premierJeudiAnnee)." - ".date("d-m-Y",$jeudiSemaine).") -> ".$numeroSemaine."
"; - - return sprintf("%02d",$numeroSemaine); -} - - -/** - \brief Retourne le picto champ obligatoire - \return string Chaine avec picto obligatoire - */ -function picto_required() -{ - return '*'; -} -/** - \brief Convertit une masse d'une unite vers une autre unite - \param weight float Masse a convertir - \param from_unit int Unite originale en puissance de 10 - \param to_unit int Nouvelle unite en puissance de 10 - \return float Masse convertie - */ -function weight_convert($weight,&$from_unit,$to_unit) -{ - /* Pour convertire 320 gr en Kg appeler - * $f = -3 - * weigh_convert(320, $f, 0) retournera 0.32 - * - */ - while ($from_unit <> $to_unit) - { - if ($from_unit > $to_unit) - { - $weight = $weight * 10; - $from_unit = $from_unit - 1; - $weight = weight_convert($weight,$from_unit, $to_unit); - } - if ($from_unit < $to_unit) - { - $weight = $weight / 10; - $from_unit = $from_unit + 1; - $weight = weight_convert($weight,$from_unit, $to_unit); - } - } - - return $weight; -} - -/** - \brief Renvoi le texte d'une unite - \param int Unit - \param measuring_style Le style de mesure : weight, volume,... - \return string Unite - \todo gerer les autres unit�s de mesure comme la livre, le gallon, le litre, ... - */ -function measuring_units_string($unit,$measuring_style='') -{ - /* Note Rodo aux dev :) - * Ne pas ins�rer dans la base de donn�es ces valeurs - * cela surchagerait inutilement d'une requete suppl�mentaire - * pour quelque chose qui est somme toute peu variable - */ - - global $langs; - - if ($measuring_style == 'weight') - { - $measuring_units[3] = $langs->trans("WeightUnitton"); - $measuring_units[0] = $langs->trans("WeightUnitkg"); - $measuring_units[-3] = $langs->trans("WeightUnitg"); - $measuring_units[-6] = $langs->trans("WeightUnitmg"); - } - else if ($measuring_style == 'volume') - { - $measuring_units[0] = $langs->trans("VolumeUnitm3"); - $measuring_units[-3] = $langs->trans("VolumeUnitdm3"); - $measuring_units[-6] = $langs->trans("VolumeUnitcm3"); - $measuring_units[-9] = $langs->trans("VolumeUnitmm3"); - } - - return $measuring_units[$unit]; -} - -/** - \brief Clean an url - \param url Url - \param http 1: keep http, 0: remove also http - \return string CleanUrl - */ -function clean_url($url,$http=1) -{ - if (eregi('^(https?:[\\\/]+)?([0-9A-Z\-\.]+\.[A-Z]{2,4})(:[0-9]+)?',$url,$regs)) - { - $proto=$regs[1]; - $domain=$regs[2]; - $port=$regs[3]; - //print $url." -> ".$proto." - ".$domain." - ".$port; - $url = unaccent_isostring(trim($url)); - - // Si http: defini on supprime le http (Si https on ne supprime pas) - if ($http==0) - { - if (eregi('^http:[\\\/]+',$url)) - { - $url = eregi_replace('^http:[\\\/]+','',$url); - $proto = ''; - } - } - - // On passe le nom de domaine en minuscule - $url = eregi_replace('^(https?:[\\\/]+)?'.$domain,$proto.strtolower($domain),$url); - - return $url; - } -} - - - -/** - \brief Clean a string from all html tags - \param StringHtml String to clean - \param removelinefeed Replace also all lines feeds by a space - \return string String cleaned - */ -function clean_html($StringHtml,$removelinefeed=1) -{ - $pattern = "<[^>]+>"; - $temp = dol_entity_decode($StringHtml); - $temp = ereg_replace($pattern,"",$temp); - - // Supprime aussi les retours - if ($removelinefeed) $temp=str_replace("\n"," ",$temp); - - // et les espaces doubles - while(STRPOS($temp," ")) - { - $temp = STR_REPLACE(" "," ",$temp); - } - $CleanString = $temp; - return $CleanString; -} - -/** - \brief Convert a binaray data to string that represent hexadecimal value - \param bin Value to convert - \param pad Add 0 - \param upper Convert to tupper - \return string x - */ -function binhex($bin, $pad=false, $upper=false){ - $last = strlen($bin)-1; - for($i=0; $i<=$last; $i++){ $x += $bin[$last-$i] * pow(2,$i); } - $x = dechex($x); - if($pad){ while(strlen($x) < intval(strlen($bin))/4){ $x = "0$x"; } } - if($upper){ $x = strtoupper($x); } - return $x; -} - -/** - \brief Convertir de l'h�xad�cimal en binaire - \param string hexa - \return string bin - */ -function hexbin($hexa){ - $bin=''; - for($i=0;$i",$ret); - return $ret; - } -} - -/** - * \brief This function is called to encode a string into a HTML string - * \param stringtoencode String to encode - * \param nl2brmode 0=Adding br before \n, 1=Replacing \n by br (for use with FPDF writeHTMLCell function for example) - * \remarks For PDF usage, you can show text by 2 ways: - * - writeHTMLCell -> param must be encoded into HTML. - * - MultiCell -> param must not be encoded into HTML. - * Because writeHTMLCell convert also \n into
, if function - * is used to build PDF, nl2brmode must be 1. - */ -function dol_htmlentitiesbr($stringtoencode,$nl2brmode=0) -{ - if (dol_textishtml($stringtoencode)) - { - // Replace "
" by "
". It's same and avoid pb with FPDF. - $stringtoencode=eregi_replace('",$ret); - $ret=eregi_replace(''; - if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) { $ok=0; break; } - if ($ordchar > 126 && $ordchar < 160) { $ok=0; break; } - } - return $ok; -} - - -/** - * \brief Return nb of lines of a text - * \param s String to check - * \param maxchar Not yet used - * \return int 0 if bad iso, 1 if good iso - */ -function dol_nboflines($s,$maxchar=0) -{ - $arraystring=split("\n",$s); - $nb=sizeof($arraystring); - - return $nb; -} - - -/** - \brief Fonction retournant le nombre de jour fieries samedis et dimanches entre 2 dates entrees en timestamp - \remarks SERVANT AU CALCUL DES JOURS OUVRABLES - \param timestampStart Timestamp de debut - \param timestampEnd Timestamp de fin - \return nbFerie Nombre de jours feries - */ -function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR') -{ - $nbFerie = 0; - - while ($timestampStart != $timestampEnd) - { - $ferie=false; - $countryfound=0; - - $jour = date("d", $timestampStart); - $mois = date("m", $timestampStart); - $annee = date("Y", $timestampStart); - - if ($countrycode == 'FR') - { - $countryfound=1; - - // Definition des dates feriees fixes - if($jour == 1 && $mois == 1) $ferie=true; // 1er janvier - if($jour == 1 && $mois == 5) $ferie=true; // 1er mai - if($jour == 8 && $mois == 5) $ferie=true; // 5 mai - if($jour == 14 && $mois == 7) $ferie=true; // 14 juillet - if($jour == 15 && $mois == 8) $ferie=true; // 15 aout - if($jour == 1 && $mois == 11) $ferie=true; // 1 novembre - if($jour == 11 && $mois == 11) $ferie=true; // 11 novembre - if($jour == 25 && $mois == 12) $ferie=true; // 25 decembre - - // Calcul du jour de paques - $date_paques = easter_date($annee); - $jour_paques = date("d", $date_paques); - $mois_paques = date("m", $date_paques); - if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; - // Paques - - // Calcul du jour de l ascension (38 jours apres Paques) - $date_ascension = mktime(date("H", $date_paques), - date("i", $date_paques), - date("s", $date_paques), - date("m", $date_paques), - date("d", $date_paques) + 38, - date("Y", $date_paques) - ); - $jour_ascension = date("d", $date_ascension); - $mois_ascension = date("m", $date_ascension); - if($jour_ascension == $jour && $mois_ascension == $mois) $ferie=true; - //Ascension - - // Calcul de Pentecote (11 jours apres Paques) - $date_pentecote = mktime(date("H", $date_ascension), - date("i", $date_ascension), - date("s", $date_ascension), - date("m", $date_ascension), - date("d", $date_ascension) + 11, - date("Y", $date_ascension) - ); - $jour_pentecote = date("d", $date_pentecote); - $mois_pentecote = date("m", $date_pentecote); - if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true; - //Pentecote - - // Calul des samedis et dimanches - $jour_julien = unixtojd($timestampStart); - $jour_semaine = jddayofweek($jour_julien, 0); - if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true; - //Samedi (6) et dimanche (0) - } - - // Mettre ici cas des autres pays - - - // Cas pays non defini - if (! $countryfound) - { - // Calul des samedis et dimanches - $jour_julien = unixtojd($timestampStart); - $jour_semaine = jddayofweek($jour_julien, 0); - if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true; - //Samedi (6) et dimanche (0) - } - - // On incremente compteur - if ($ferie) $nbFerie++; - - // Incrementation du nombre de jour (on avance dans la boucle) - $jour++; - $timestampStart=mktime(0,0,0,$mois,$jour,$annee); - } - - return $nbFerie; -} - -/** - \brief Fonction retournant le nombre de jour entre deux dates - \param timestampStart Timestamp de d�but - \param timestampEnd Timestamp de fin - \param lastday On prend en compte le dernier jour, 0: non, 1:oui - \return nbjours Nombre de jours - */ -function num_between_day($timestampStart, $timestampEnd, $lastday=0) -{ - if ($timestampStart < $timestampEnd) - { - if ($lastday == 1) - { - $bit = 0; - } - else - { - $bit = 1; - } - $nbjours = round(($timestampEnd - $timestampStart)/(60*60*24)-$bit); - } - return $nbjours; -} - -/** - \brief Fonction retournant le nombre de jour entre deux dates sans les jours f�ri�s (jours ouvr�s) - \param timestampStart Timestamp de d�but - \param timestampEnd Timestamp de fin - \param inhour 0: sort le nombre de jour , 1: sort le nombre d'heure (72 max) - \param lastday On prend en compte le dernier jour, 0: non, 1:oui - \return nbjours Nombre de jours ou d'heures - */ -function num_open_day($timestampStart, $timestampEnd,$inhour=0,$lastday=0) -{ - global $langs; - - if ($timestampStart < $timestampEnd) - { - $bit = 0; - if ($lastday == 1) $bit = 1; - $nbOpenDay = num_between_day($timestampStart, $timestampEnd, $bit) - num_public_holiday($timestampStart, $timestampEnd); - $nbOpenDay.= " ".$langs->trans("Days"); - if ($inhour == 1 && $nbOpenDay <= 3) $nbOpenDay = $nbOpenDay*24 . $langs->trans("HourShort"); - return $nbOpenDay; - } - else - { - return $langs->trans("Error"); - } -} - -/** - \brief Fonction retournant le nombre de lignes dans un texte format� - \param texte Texte - \return nblines Nombre de lignes - */ -function num_lines($texte) -{ - $repTable = array("\t" => " ", "\n" => "
", "\r" => " ", "\0" => " ", "\x0B" => " "); - $texte = strtr($texte, $repTable); - $pattern = '/(<[^>]+>)/Uu'; - $a = preg_split($pattern, $texte, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $nblines = ((count($a)+1)/2); - return $nblines; -} - -/** - * \brief Fonction simple identique a microtime de PHP 5 mais compatible PHP 4 - * \return float Time en millisecondes avec decimal pour microsecondes - */ -function dol_microtime_float() -{ - list($usec, $sec) = explode(" ", microtime()); - return ((float)$usec + (float)$sec); -} - -/* - * \brief Return if a text is a html content - * \param msg Content to check - * \param option 0=Full detection, 1=Fast check - * \return boolean true/false - */ -function dol_textishtml($msg,$option=0) -{ - if ($option == 1) - { - if (eregi('',$msg)) return true; - elseif (eregi('',$msg)) return true; - elseif (eregi('&[A-Z0-9]{1,6};',$msg)) return true; - return false; - } -} - -/* - * \brief Effectue les substitutions des mots cl�s par les donn�es en fonction du tableau - * \param chaine Chaine dans laquelle faire les substitutions - * \param substitutionarray Tableau cl� substitution => valeur a mettre - * \return string Chaine avec les substitutions effectu�es - */ -function make_substitutions($chaine,$substitutionarray) -{ - foreach ($substitutionarray as $key => $value) - { - $chaine=ereg_replace($key,$value,$chaine); - } - return $chaine; -} - - -/* - * \brief Formate l'affichage de date de d�but et de fin - * \param date_start date de d�but - * \param date_end date de fin - */ -function print_date_range($date_start,$date_end) -{ - global $langs; - - if ($date_start && $date_end) - { - print ' ('.$langs->trans('DateFromTo',dolibarr_print_date($date_start),dolibarr_print_date($date_end)).')'; - } - if ($date_start && ! $date_end) - { - print ' ('.$langs->trans('DateFrom',dolibarr_print_date($date_start)).')'; - } - if (! $date_start && $date_end) - { - print ' ('.$langs->trans('DateUntil',dolibarr_print_date($date_end)).')'; - } -} - - -/* - * - */ -function make_alpha_from_numbers($number) -{ - $numeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if($numberload("main"); - - $month = array (1 => $langs->trans("January"), - 2 => $langs->trans("February"), - 3 => $langs->trans("March"), - 4 => $langs->trans("April"), - 5 => $langs->trans("May"), - 6 => $langs->trans("June"), - 7 => $langs->trans("July"), - 8 => $langs->trans("August"), - 9 => $langs->trans("September"), - 10 => $langs->trans("October"), - 11 => $langs->trans("November"), - 12 => $langs->trans("December") - ); - - if ($selected >=0) - { - $return=''; - foreach ($month as $key => $val) - { - if ($selected == $key) - { - $return = $val; - } - } - return $return; - } - else - { - return $month; - } -} - -/** - \brief Returns formated reduction - \param reduction Reduction percentage - \return string Formated reduction - */ -function dolibarr_print_reduction($reduction=0) -{ - global $langs; - $langs->load("main"); - - $string = ''; - - if ($reduction == 100) - { - $string = $langs->trans("Offered"); - } - else - { - $string = $reduction.'%'; - } - - return $string; -} - - -/** - \brief Returns formated reduction - \param reduction Reduction percentage - \return int Return number of error messages shown - */ -function dol_htmloutput_errors($mesgstring='',$mesgarray='') -{ - global $langs; - - $ret = 0; - $langs->load("errors"); - - if (is_array($mesgarray) && sizeof($mesgarray)) - { - print '
'; - foreach($mesgarray as $message) - { - $ret++; - print $langs->trans($message)."
\n"; - } - print '
'; - } - if ($mesgstring) - { - $ret++; - print '
'; - print $mesgstring; - print '
'; - } - - return $ret; -} - - -/** - * \brief This function output memory used by PHP and exit everything. Used for debugging purpose. - */ -function stopwithmem() -{ - print memory_get_usage(); - llxFooter(); - exit; -} - - -/** - * \brief Advanced sort array by second index function, which produces - * ascending (default) or descending output and uses optionally - * natural case insensitive sorting (which can be optionally case - * sensitive as well). - */ -function dol_sort_array($array, $index, $order='asc', $natsort, $case_sensitive) -{ - // Clean parameters - $order=strtolower($order); - - if (is_array($array) && count($array)>0) - { - foreach(array_keys($array) as $key) $temp[$key]=$array[$key][$index]; - if (!$natsort) ($order=='asc') ? asort($temp) : arsort($temp); - else - { - ($case_sensitive) ? natsort($temp) : natcasesort($temp); - if($order!='asc') $temp=array_reverse($temp,TRUE); - } - foreach(array_keys($temp) as $key) (is_numeric($key))? $sorted[]=$array[$key] : $sorted[$key]=$array[$key]; - return $sorted; - } - return $array; -} - -?> + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2008 Laurent Destailleur + * Copyright (C) 2004 Sebastien Di Cintio + * Copyright (C) 2004 Benoit Mortier + * Copyright (C) 2004 Christophe Combelles + * Copyright (C) 2005-2007 Regis Houssin + * Copyright (C) 2008 Raphael Bertrand (Resultic) + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * or see http://www.gnu.org/ + */ + +/** + \file htdocs/lib/functions.lib.php + \brief Ensemble de fonctions de base de dolibarr sous forme d'include + \version $Id$ + */ + +// For compatibility during upgrade +if (! defined('DOL_DOCUMENT_ROOT')) define('DOL_DOCUMENT_ROOT', '..'); +if (! defined('ADODB_DATE_VERSION')) include_once(DOL_DOCUMENT_ROOT."/includes/adodbtime/adodb-time.inc.php"); + + + +/** + \brief Renvoi vrai si l'email est syntaxiquement valide + \param address adresse email (Ex: "toto@titi.com", "John Do ") + \return boolean true si email valide, false sinon + */ +function ValidEmail($address) +{ + if (ereg( ".*<(.+)>", $address, $regs)) { + $address = $regs[1]; + } + if (ereg( "^[^@ ]+@([a-zA-Z0-9\-]+\.)+([a-zA-Z0-9\-]{2}|coop|aero|biz|com|edu|gov|info|int|mil|name|net|org)\$",$address)) + { + return true; + } + else + { + return false; + } +} + +/** + \brief Renvoi vrai si l'email a un nom de domaine qui r�soud via dns + \param mail adresse email (Ex: "toto@titi.com", "John Do ") + \return boolean true si email valide, false sinon + */ +function check_mail ($mail) +{ + list($user, $domain) = split("@", $mail, 2); + if (checkdnsrr($domain, "MX")) + { + return true; + } + else + { + return false; + } +} + +/** + \brief Nettoie chaine de caractere iso des accents + \param str Chaine a nettoyer + \return string Chaine nettoyee + */ +function unaccent_isostring($str) +{ + $translation = array( + "\xE0" => "a", + "\xE1" => "a", + "\xE2" => "a", + "\xE8" => "e", + "\xE9" => "e", + "\xEA" => "e", + "\xEB" => "e", + "\xEE" => "i", + "\xEF" => "i", + "\xF4" => "o", + "\xF6" => "o", + "\xFB" => "u", + "\xFC" => "u" + ); + + return str_replace(array_keys($translation), array_values($translation), $str); +} + +/** + * \brief Nettoie chaine de caractere de caracteres speciaux + * \remarks Fonction appelee par exemple pour definir un nom de fichier depuis un identifiant chaine libre + * \param str String to clean + * \param newstr String to replace bad chars by + * \return string String cleaned (a-zA-Z_) + */ +function sanitize_string($str,$newstr='_') +{ + $forbidden_chars_to_underscore=array(" ","'","/","\\",":","*","?","\"","<",">","|","[","]",",",";","="); + //$forbidden_chars_to_remove=array("(",")"); + $forbidden_chars_to_remove=array(); + + return str_replace($forbidden_chars_to_underscore,$newstr,str_replace($forbidden_chars_to_remove,"",$str)); +} + + +/** + * \brief Returns text escaped for inclusion in javascript code + * \param $stringtoescape String to escape + * \return string Escaped string + */ +function dol_escape_js($stringtoescape) +{ + // escape quotes and backslashes, newlines, etc. + return strtr($stringtoescape, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n',''<\/')); +} + + + + +/** + \brief Envoi des messages dolibarr dans un fichier ou dans syslog + Pour fichier: fichier defini par SYSLOG_FILE + Pour syslog: facility defini par SYSLOG_FACILITY + \param message Message a tracer. Ne doit pas etre traduit si level = LOG_ERR + \param level Niveau de l'erreur + \remarks Cette fonction n'a un effet que si le module syslog est activ�. + Warning, les fonctions syslog sont buggu�s sous Windows et g�n�rent des + fautes de protection m�moire. Pour r�soudre, utiliser le loggage fichier, + au lieu du loggage syslog (configuration du module). + Si SYSLOG_FILE_NO_ERROR d�fini, on ne g�re pas erreur ecriture log + \remarks On Windows LOG_ERR=4, LOG_WARNING=5, LOG_NOTICE=LOG_INFO=LOG_DEBUG=6 + On Linux LOG_ERR=3, LOG_WARNING=4, LOG_INFO=6, LOG_DEBUG=7 + */ +function dolibarr_syslog($message, $level=LOG_INFO) +{ + global $conf,$user,$langs; + + if (isset($conf->syslog->enabled) && $conf->syslog->enabled) + { + //print $level.' - '.$conf->global->SYSLOG_LEVEL.' - '.$conf->syslog->enabled." \n"; + if ($level > $conf->global->SYSLOG_LEVEL) return; + + // Traduction du message + if ($level == LOG_ERR) + { + $langs->load("errors"); + if ($message != $langs->trans($message)) $message = $langs->trans($message); + } + + // Ajout user a la log + $login='???'; + if (is_object($user) && $user->id) $login=$user->login; + $message=sprintf("%-8s",$login)." ".$message; + + if (defined("SYSLOG_FILE") && SYSLOG_FILE) + { + $filelog=SYSLOG_FILE; + $filelog=eregi_replace('DOL_DATA_ROOT',DOL_DATA_ROOT,$filelog); + if (defined("SYSLOG_FILE_NO_ERROR")) $file=@fopen($filelog,"a+"); + else $file=fopen($filelog,"a+"); + if ($file) + { + $ip='unknown_ip'; + if (! empty($_SERVER["REMOTE_ADDR"])) $ip=$_SERVER["REMOTE_ADDR"]; + + $liblevelarray=array(LOG_ERR=>'ERROR',LOG_WARNING=>'WARN',LOG_INFO=>'INFO',LOG_DEBUG=>'DEBUG'); + $liblevel=$liblevelarray[$level]; + if (! $liblevel) $liblevel='UNDEF'; + + $message=strftime("%Y-%m-%d %H:%M:%S",time())." ".sprintf("%-5s",$liblevel)." ".$ip." ".$message; + + fwrite($file,$message."\n"); + fclose($file); + + // If enable html log tag enabled and url parameter log defined, we show output log on HTML comments + if (! empty($conf->global->MAIN_ENABLE_LOG_HTML) && ! empty($_GET["log"])) + { + print "\n\n\n"; + } + } + elseif (! defined("SYSLOG_FILE_NO_ERROR")) + { + $langs->load("main"); + print $langs->trans("ErrorFailedToOpenFile",$filelog); + } + } + else + { + //define_syslog_variables(); d�ja d�finit dans master.inc.php + if (defined("MAIN_SYSLOG_FACILITY") && MAIN_SYSLOG_FACILITY) + { + $facility = MAIN_SYSLOG_FACILITY; + } + elseif (defined("SYSLOG_FACILITY") && SYSLOG_FACILITY && defined(SYSLOG_FACILITY)) + { + // Exemple: SYSLOG_FACILITY vaut LOG_USER qui vaut 8. On a besoin de 8 dans $facility. + $facility = constant(SYSLOG_FACILITY); + } + else + { + $facility = LOG_USER; + } + + openlog("dolibarr", LOG_PID | LOG_PERROR, $facility); + + if (! $level) + { + syslog(LOG_ERR, $message); + } + else + { + syslog($level, $message); + } + + closelog(); + } + } +} + +/** + \brief Affiche le header d'une fiche + \param links Tableau de titre d'onglets + \param active 0=onglet non actif, 1=onglet actif + \param title Titre tabelau ("" par defaut) + \param notab 0=Add tab header, 1=no tab header + */ +function dolibarr_fiche_head($links, $active='0', $title='', $notab=0) +{ + print "\n".'
'."\n"; + + // Affichage titre + if ($title) + { + $limittitle=30; + print ''; + print + ((!defined('MAIN_USE_SHORT_TITLE')) || (defined('MAIN_USE_SHORT_TITLE') && MAIN_USE_SHORT_TITLE)) + ? dolibarr_trunc($title,$limittitle) + : $title; + print ''; + } + + // Affichage onglets + for ($i = 0 ; $i < sizeof($links) ; $i++) + { + if ($links[$i][2] == 'image') + { + print ''.$links[$i][1].''."\n"; + } + else + { + //print "x $i $active ".$links[$i][2]." z"; + if ((is_numeric($active) && $i == $active) + || (! is_numeric($active) && $active == $links[$i][2])) + { + print ''.$links[$i][1].''."\n"; + } + else + { + print ''.$links[$i][1].''."\n"; + } + } + } + + print "
\n"; + + if (! $notab) print '
'."\n\n"; +} + + +/** + \brief Sauvegarde parametrage personnel + \param db Handler d'acc�s base + \param user Objet utilisateur + \param url Si defini, on sauve parametre du tableau tab dont cl� = (url avec sortfield, sortorder, begin et page) + Si non defini on sauve tous parametres du tableau tab + \param tab Tableau (cl�=>valeur) des param�tres a sauvegarder + \return int <0 si ko, >0 si ok + */ +function dolibarr_set_user_page_param($db, &$user, $url='', $tab) +{ + // Verification parametres + if (sizeof($tab) < 1) return -1; + + $db->begin(); + + // On efface anciens param�tres pour toutes les cl� dans $tab + $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param"; + $sql.= " WHERE fk_user = ".$user->id; + if ($url) $sql.=" AND page='".$url."'"; + else $sql.=" AND page=''"; // Page ne peut etre null + $sql.= " AND param in ("; + $i=0; + foreach ($tab as $key => $value) + { + if ($i > 0) $sql.=','; + $sql.="'".$key."'"; + $i++; + } + $sql.= ")"; + dolibarr_syslog("functions.lib.php::dolibarr_set_user_page_param $sql"); + + $resql=$db->query($sql); + if (! $resql) + { + dolibarr_print_error($db); + $db->rollback(); + exit; + } + + foreach ($tab as $key => $value) + { + // On positionne nouveaux param�tres + if ($value && (! $url || in_array($key,array('sortfield','sortorder','begin','page')))) + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,page,param,value)"; + $sql.= " VALUES (".$user->id.","; + if ($url) $sql.= " '".urlencode($url)."',"; + else $sql.= " '',"; + $sql.= " '".$key."','".addslashes($value)."');"; + dolibarr_syslog("functions.lib.php::dolibarr_set_user_page_param $sql"); + + $result=$db->query($sql); + if (! $result) + { + dolibarr_print_error($db); + $db->rollback(); + exit; + } + + $user->page_param[$key] = $value; + } + } + + $db->commit(); + return 1; +} + + +/** + \brief Formattage des nombres + \param ca valeur a formater + \return int valeur format�e + */ +function dolibarr_print_ca($ca) +{ + global $langs,$conf; + + if ($ca > 1000) + { + $cat = round(($ca / 1000),2); + $cat = "$cat K".$langs->trans("Currency".$conf->monnaie); + } + else + { + $cat = round($ca,2); + $cat = "$cat ".$langs->trans("Currency".$conf->monnaie); + } + + if ($ca > 1000000) + { + $cat = round(($ca / 1000000),2); + $cat = "$cat M".$langs->trans("Currency".$conf->monnaie); + } + + return $cat; +} + + +/** + \brief Effectue un d�calage de date par rapport a une dur�e + \param time Date timestamp ou au format YYYY-MM-DD + \param duration_value Valeur de la dur�e a ajouter + \param duration_unit Unit� de la dur�e a ajouter (d, m, y) + \return int Nouveau timestamp + */ +function dolibarr_time_plus_duree($time,$duration_value,$duration_unit) +{ + if ($duration_value == 0) return $time; + if ($duration_value > 0) $deltastring="+".abs($duration_value); + if ($duration_value < 0) $deltastring="-".abs($duration_value); + if ($duration_unit == 'd') { $deltastring.=" day"; } + if ($duration_unit == 'm') { $deltastring.=" month"; } + if ($duration_unit == 'y') { $deltastring.=" year"; } + return strtotime($deltastring,$time); +} + + +/** + * \brief Formattage de la date en fonction de la langue $conf->langage + * \param time Date 'timestamp' ou format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' + * \param format Format d'affichage de la date + * "%d %b %Y", + * "%d/%m/%Y %H:%M", + * "%d/%m/%Y %H:%M:%S", + * "day", "daytext", "dayhour", "dayhourldap", "dayhourtext" + * \return string Date formatee ou '' si time null + */ +function dolibarr_print_date($time,$format='',$to_gmt=false) +{ + global $conf; + + // Si format non defini, on prend $conf->format_date_text_short sinon %Y-%m-%d %H:%M:%S + if (! $format) $format=(isset($conf->format_date_text_short) ? $conf->format_date_text_short : '%Y-%m-%d %H:%M:%S'); + + if ($format == 'day') $format=$conf->format_date_short; + if ($format == 'hour') $format=$conf->format_hour_short; + if ($format == 'daytext') $format=$conf->format_date_text_short; + if ($format == 'dayhour') $format=$conf->format_date_hour_short; + if ($format == 'dayhourtext') $format=$conf->format_date_hour_text_short; + if ($format == 'dayhourldap') $format='%Y%m%d%H%M%SZ'; + if ($format == 'dayhourxcard') $format='%Y%m%dT%H%M%SZ'; + + // Si date non definie, on renvoie '' + if ($time == '') return ''; // $time=0 permis car signifie 01/01/1970 00:00:00 + + // Analyse de la date + if (eregi('^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$time,$reg)) + { + // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' + $syear = $reg[1]; + $smonth = $reg[2]; + $sday = $reg[3]; + $shour = $reg[4]; + $smin = $reg[5]; + $ssec = $reg[6]; + + return adodb_strftime($format,dolibarr_mktime($shour,$smin,$ssec,$smonth,$sday,$syear),$to_gmt); + } + else + { + // Date est un timestamps + return adodb_strftime($format,$time,$to_gmt); + } +} + + +/** + * \brief Convert a string date into a TMS date + * \param string Date in a string + * YYYYMMDD + * YYYYMMDDHHMMSS + * DD/MM/YY ou DD/MM/YYYY + * DD/MM/YY HH:MM:SS ou DD/MM/YYYY HH:MM:SS + * \return date Date + */ +function dolibarr_stringtotime($string) +{ + if (eregi('^([0-9]+)\/([0-9]+)\/([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?',$string,$reg)) + { + // Date est au format 'DD/MM/YY' ou 'DD/MM/YY HH:MM:SS' + // Date est au format 'DD/MM/YYYY' ou 'DD/MM/YYYY HH:MM:SS' + $sday = $reg[1]; + $smonth = $reg[2]; + $syear = $reg[3]; + $shour = $reg[4]; + $smin = $reg[5]; + $ssec = $reg[6]; + if ($syear < 50) $syear+=1900; + if ($syear >= 50 && $syear < 100) $syear+=2000; + $string=sprintf("%04d%02d%02d%02d%02d%02d",$syear,$smonth,$sday,$shour,$smin,$ssec); + } + + $string=eregi_replace('[^0-9]','',$string); + $tmp=$string.'000000'; + $date=dolibarr_mktime(substr($tmp,8,2),substr($tmp,10,2),substr($tmp,12,2),substr($tmp,4,2),substr($tmp,6,2),substr($tmp,0,4)); + return $date; +} + + +/** + \brief Return an array with date info + \param timestamp Timestamp + \param fast Fast mode + \return array Array of informations + If no fast mode: + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'wday' => $dow, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'weekday' => gmdate('l',$_day_power*(3+$dow)), + 'month' => gmdate('F',mktime(0,0,0,$month,2,1971)), + 0 => $origd + If fast mode: + 'seconds' => $secs, + 'minutes' => $min, + 'hours' => $hour, + 'mday' => $day, + 'mon' => $month, + 'year' => $year, + 'yday' => floor($secsInYear/$_day_power), + 'leap' => $leaf, + 'ndays' => $ndays + \remarks PHP getdate is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows + */ +function dolibarr_getdate($timestamp,$fast=false) +{ + $usealternatemethod=false; + if ($timestamp <= 0) $usealternatemethod=true; // <= 1970 + if ($timestamp >= 2145913200) $usealternatemethod=true; // >= 2038 + + if ($usealternatemethod) + { + $arrayinfo=adodb_getdate($timestamp,$fast); + } + else + { + $arrayinfo=getdate($timestamp); + } + + return $arrayinfo; +} + +/** + \brief Retourne une date fabriquee depuis infos. + Remplace la fonction mktime non implementee sous Windows si annee < 1970 + \param hour Hour + \param minute Minute + \param second Second + \param month Month + \param day Day + \param year Year + \param gm Time gm + \param check No check on parameters (Can use day 32, etc...) + \return timestamp Date en timestamp, '' if error + \remarks PHP mktime is restricted to the years 1901-2038 on Unix and 1970-2038 on Windows + */ +function dolibarr_mktime($hour,$minute,$second,$month,$day,$year,$gm=0,$check=1) +{ + //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -"; + + // Check parameters + if ($check) + { + if (! $month || ! $day) return ''; + if ($day > 31) return ''; + if ($month > 12) return ''; + if ($min < 0 || $min > 60) return ''; + if ($hour < 0 || $hour > 24) return ''; + if ($min < 0 || $min > 60) return ''; + } + + $usealternatemethod=false; + if ($year <= 1970) $usealternatemethod=true; // <= 1970 + if ($year >= 2038) $usealternatemethod=true; // >= 2038 + + if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir + { + /* + // On peut utiliser strtotime pour obtenir la traduction. + // strtotime is ok for range: Vendredi 13 D�cembre 1901 20:45:54 GMT au Mardi 19 Janvier 2038 03:14:07 GMT. + $montharray=array(1=>'january',2=>'february',3=>'march',4=>'april',5=>'may',6=>'june', + 7=>'july',8=>'august',9=>'september',10=>'october',11=>'november',12=>'december'); + $string=$day." ".$montharray[0+$month]." ".$year." ".$hour.":".$minute.":".$second." GMT"; + $date=strtotime($string); + print "- ".$string." ".$date." -"; + */ + $date=adodb_mktime($hour,$minute,$second,$month,$day,$year,0,$gm); + } + else + { + $date=mktime($hour,$minute,$second,$month,$day,$year); + } + return $date; +} + + + +/** + \brief Returns formated date + \param fmt Format (Exemple: 'Y-m-d H:i:s') + \param timestamp Date. Exemple: Si timestamp=0 et gm=1, renvoi 01/01/1970 00:00:00 + \param gm 1 if timestamp was built with gmmktime, 0 if timestamp was build with mktime + \return string Formated date + */ +function dolibarr_date($fmt, $timestamp, $gm=0) +{ + $usealternatemethod=false; + if ($timestamp <= 0) $usealternatemethod=true; + if ($timestamp >= 2145913200) $usealternatemethod=true; + + if ($usealternatemethod || $gm) // Si time gm, seule adodb peut convertir + { + $string=adodb_date($fmt,$timestamp,$gm); + } + else + { + $string=date($fmt,$timestamp); + } + + return $string; +} + + +/** + \brief Affiche les informations d'un objet + \param object objet a afficher + */ +function dolibarr_print_object_info($object) +{ + global $langs; + $langs->load("other"); + + if (isset($object->user_creation) && $object->user_creation->fullname) + print $langs->trans("CreatedBy")." : " . $object->user_creation->fullname . '
'; + + if (isset($object->date_creation)) + print $langs->trans("DateCreation")." : " . dolibarr_print_date($object->date_creation,"dayhourtext") . '
'; + + if (isset($object->user_modification) && $object->user_modification->fullname) + print $langs->trans("ModifiedBy")." : " . $object->user_modification->fullname . '
'; + + if (isset($object->date_modification)) + print $langs->trans("DateLastModification")." : " . dolibarr_print_date($object->date_modification,"dayhourtext") . '
'; + + if (isset($object->user_validation) && $object->user_validation->fullname) + print $langs->trans("ValidatedBy")." : " . $object->user_validation->fullname . '
'; + + if (isset($object->date_validation)) + print $langs->trans("DateValidation")." : " . dolibarr_print_date($object->date_validation,"dayhourtext") . '
'; + + if (isset($object->user_cloture) && $object->user_cloture->fullname ) + print $langs->trans("ClosedBy")." : " . $object->user_cloture->fullname . '
'; + + if (isset($object->date_cloture)) + print $langs->trans("DateClosing")." : " . dolibarr_print_date($object->date_cloture,"dayhourtext") . '
'; + + if (isset($object->user_rappro) && $object->user_rappro->fullname ) + print $langs->trans("ConciliatedBy")." : " . $object->user_rappro->fullname . '
'; + + if (isset($object->date_rappro)) + print $langs->trans("DateConciliating")." : " . dolibarr_print_date($object->date_rappro,"dayhourtext") . '
'; +} + +/** + \brief Formatage des num�ros de telephone en fonction du format d'un pays + \param phone Num�ro de telephone a formater + \param country Pays selon lequel formatter + \return string Num�ro de t�l�phone format� + */ +function dolibarr_print_phone($phone,$country="FR") +{ + $phone=trim($phone); + if (! $phone) { return $phone; } + + if (strtoupper($country) == "FR") + { + // France + if (strlen($phone) == 10) { + return substr($phone,0,2)." ".substr($phone,2,2)." ".substr($phone,4,2)." ".substr($phone,6,2)." ".substr($phone,8,2); + } + elseif (strlen($phone) == 7) + { + + return substr($phone,0,3)." ".substr($phone,3,2)." ".substr($phone,5,2); + } + elseif (strlen($phone) == 9) + { + return substr($phone,0,2)." ".substr($phone,2,3)." ".substr($phone,5,2)." ".substr($phone,7,2); + } + elseif (strlen($phone) == 11) + { + return substr($phone,0,3)." ".substr($phone,3,2)." ".substr($phone,5,2)." ".substr($phone,7,2)." ".substr($phone,9,2); + } + elseif (strlen($phone) == 12) + { + return substr($phone,0,4)." ".substr($phone,4,2)." ".substr($phone,6,2)." ".substr($phone,8,2)." ".substr($phone,10,2); + } + } + + return $phone; +} + + +/** + * \brief Return string with formated size + * \param size Size to print + * \return string Link + */ +function dol_print_size($size) +{ + global $langs; + + return $size.' '.$langs->trans("Bytes"); +} + + +/** + * \brief Show click to dial link + * \param phone Phone to call + * \param option Type of picto + * \return string Link + */ +function dol_phone_link($phone,$option=0) +{ + global $conf,$user; + + $link=''; + //if (! empty($conf->global->CLICKTODIAL_URL)) + if ($conf->clicktodial->enabled) + { + $phone=trim($phone); + $url = $conf->global->CLICKTODIAL_URL; + $url.= "?login=".urlencode($user->clicktodial_login)."&password=".urlencode($user->clicktodial_password); + $url.= "&caller=".urlencode($user->clicktodial_poste)."&called=".urlencode(trim($phone)); + $link.=''.img_phone("default",0).''; + } + return $link; +} + +/** + \brief Truncate a string to a particular length adding '...' if string larger than length + \param string String to truncate + \param size Max string size. 0 for no limit. + \param trunc Where to trunc: right, left, middle + \return string Truncated string + \remarks USE_SHORT_TITLE=0 can disable all truncings + */ +function dolibarr_trunc($string,$size=40,$trunc='right') +{ + if ($size==0) return $string; + if (! defined('USE_SHORT_TITLE') || (defined('USE_SHORT_TITLE') && USE_SHORT_TITLE)) + { + // We go always here + if ($trunc == 'right') + { + if (strlen($string) > $size) + return substr($string,0,$size).'...'; + else + return $string; + } + if ($trunc == 'middle') + { + if (strlen($string) > 2 && strlen($string) > $size) + { + $size1=round($size/2); + $size2=round($size/2); + return substr($string,0,$size1).'...'.substr($string,strlen($string) - $size2,$size2); + } + else + return $string; + } + if ($trunc == 'left') + { + if (strlen($string) > $size) + return '...'.substr($string,strlen($string) - $size,$size); + else + return $string; + } + } + else + { + return $string; + } +} + +/** + \brief Compl�te une chaine a une taille donn�e par des espaces + \param string Chaine a compl�ter + \param size Longueur de la chaine. + \param side 0=Compl�tion a droite, 1=Compl�tion a gauche + \param char Chaine de compl�tion + \return string Chaine compl�t�e + */ +function dolibarr_pad($string,$size,$side,$char=' ') +{ + $taille=sizeof($string); + $i=0; + while($i < ($size - $taille)) + { + if ($side > 0) $string.=$char; + else $string=$char.$string; + $i++; + } + return $string; +} + +/** + \brief Affiche picto propre a une notion/module (fonction g�n�rique) + \param alt Texte sur le alt de l'image + \param object Objet pour lequel il faut afficher le logo (exemple: user, group, action, bill, contract, propal, product, ...) + \return string Retourne tag img + */ +function img_object($alt, $object) +{ + global $conf,$langs; + return ''.$alt.''; +} + +/** + \brief Affiche picto (fonction g�n�rique) + \param alt Texte sur le alt de l'image + \param picto Nom de l'image a afficher (Si pas d'extension, on met '.png') + \param options Attribut suppl�mentaire a la balise img + \param pictoisfullpath If 1, image path is a full path + \return string Retourne tag img + */ +function img_picto($alt, $picto, $options='', $pictoisfullpath=0) +{ + global $conf; + if (! eregi('(\.png|\.gif)$',$picto)) $picto.='.png'; + if ($pictoisfullpath) return ''.$alt.''; + return ''.$alt.''; +} + +/** + \brief Affiche logo action + \param alt Texte sur le alt de l'image + \param numaction Determine image action + \return string Retourne tag img + */ +function img_action($alt = "default", $numaction) +{ + global $conf,$langs; + if ($alt=="default") { + if ($numaction == -1) $alt=$langs->trans("ChangeDoNotContact"); + if ($numaction == 0) $alt=$langs->trans("ChangeNeverContacted"); + if ($numaction == 1) $alt=$langs->trans("ChangeToContact"); + if ($numaction == 2) $alt=$langs->trans("ChangeContactInProcess"); + if ($numaction == 3) $alt=$langs->trans("ChangeContactDone"); + } + return ''.$alt.''; +} + + +/** + \brief Affiche logo fichier + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_file($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Show"); + return ''.$alt.''; +} + +/** + \brief Affiche logo refresh + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_refresh($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Refresh"); + return ''.$alt.''; +} + +/** + \brief Affiche logo dossier + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_folder($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Dossier"); + return ''.$alt.''; +} + +/** + \brief Affiche logo nouveau fichier + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_file_new($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Show"); + return ''.$alt.''; +} + +/** + \brief Affiche logo pdf + \param alt Texte sur le alt de l'image + \param $size Taille de l'icone : 3 = 16x16px , 2 = 14x14px + \return string Retourne tag img + */ +function img_pdf($alt = "default",$size=3) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Show"); + return ''.$alt.''; +} + +/** + \brief Affiche logo vcard + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_vcard($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("VCard"); + return ''.$alt.''; +} + +/** + \brief Affiche logo + + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_edit_add($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Add"); + return ''.$alt.''; +} +/** + \brief Affiche logo - + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_edit_remove($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Remove"); + return ''.$alt.''; +} + +/** + \brief Affiche logo editer/modifier fiche + \param alt Texte sur le alt de l'image + \param float Si il faut y mettre le style "float: right" + \return string Retourne tag img + */ +function img_edit($alt = "default", $float=0, $other='') +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Modify"); + $img=''.$alt.'trans("Delete"); + return ''.$alt.''; +} + +/** + \brief Affiche logo d�sactiver + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_disable($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Disable"); + return ''.$alt.''; +} + + +/** + \brief Affiche logo help avec curseur "?" + \return string Retourne tag img + */ +function img_help($usehelpcursor=1,$usealttitle=1) +{ + global $conf,$langs; + $s ='theme.'/img/info.png" border="0"'; + if ($usealttitle) $s.=' alt="'.$langs->trans("Info").'" title="'.$langs->trans("Info").'"'; + $s.='>'; + return $s; +} + +/** + \brief Affiche picto calendrier "?" + \return string Retourne tag img + */ +function img_cal() +{ + global $conf,$langs; + return ''; +} + +/** + \brief Affiche logo info + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_info($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Informations"); + return ''.$alt.''; +} + +/** + \brief Affiche logo calculatrice + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_calc($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Calculate"); + return ''.$alt.''; +} + +/** + \brief Affiche logo warning + \param alt Texte sur le alt de l'image + \param float Si il faut afficher le style "float: right" + \return string Retourne tag img + */ +function img_warning($alt = "default",$float=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Warning"); + $img=''.$alt.'trans("Error"); + return ''.$alt.''; +} + +/** + \brief Affiche logo alerte + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_alerte($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Alert"); + return ''.$alt.''; +} + +/** + \brief Affiche logo t�l�phone + \param alt Texte sur le alt de l'image + \param option Choose of logo + \return string Retourne tag img + */ +function img_phone($alt = "default",$option=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Call"); + $img='call_out'; + if ($option == 1) $img='call'; + $img='object_commercial'; + return ''.$alt.''; +} + + +/** + \brief Affiche logo suivant + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_next($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") { + $alt=$langs->trans("Next"); + } + return ''.$alt.''; +} + +/** + \brief Affiche logo pr�c�dent + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_previous($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Previous"); + return ''.$alt.''; +} + +/** + \brief Affiche logo bas + \param alt Texte sur le alt de l'image + \param selected Affiche version "selected" du logo + \return string Retourne tag img + */ +function img_down($alt = "default", $selected=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Down"); + if ($selected) return ''.$alt.''; + else return ''.$alt.''; +} + +/** + \brief Affiche logo haut + \param alt Texte sur le alt de l'image + \param selected Affiche version "selected" du logo + \return string Retourne tag img + */ +function img_up($alt = "default", $selected=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Up"); + if ($selected) return ''.$alt.''; + else return ''.$alt.''; +} + +/** + \brief Affiche logo gauche + \param alt Texte sur le alt de l'image + \param selected Affiche version "selected" du logo + \return string Retourne tag img + */ +function img_left($alt = "default", $selected=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Left"); + if ($selected) return ''.$alt.''; + else return ''.$alt.''; +} + +/** + \brief Affiche logo droite + \param alt Texte sur le alt de l'image + \param selected Affiche version "selected" du logo + \return string Retourne tag img + */ +function img_right($alt = "default", $selected=0) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Right"); + if ($selected) return ''.$alt.''; + else return ''.$alt.''; +} + +/** + \brief Affiche logo tick + \param alt Texte sur le alt de l'image + \return string Retourne tag img + */ +function img_tick($alt = "default") +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Active"); + return ''.$alt.''; +} + +/** + \brief Affiche le logo tick si allow + \param allow Authorise ou non + \return string Retourne tag img + */ +function img_allow($allow) +{ + global $conf,$langs; + if ($alt=="default") $alt=$langs->trans("Active"); + + if ($allow == 1) + { + return ''.$alt.''; + } + else + { + return "-"; + } +} + + +/** + * \brief Show mime picto + * \param file Filename + * \param alt Alternate text + * \return string Return img tag + */ +function img_mime($file,$alt='') +{ + $mime='other'; + if (eregi('\.pdf',$file)) { $mime='pdf'; } + if (eregi('\.(html|htm)',$file)) { $mime='html'; } + if (eregi('\.txt',$file)) { $mime='other'; } + if (eregi('\.php',$file)) { $mime='php'; } + if (eregi('\.pl',$file)) { $mime='pl'; } + if (eregi('\.js',$file)) { $mime='jscript'; } + if (eregi('\.(png|bmp|jpg|jpeg|gif)',$file)) $mime='image'; + if (eregi('\.(mp3|ogg|au)',$file)) $mime='audio'; + if (eregi('\.(avi|mvw|divx|xvid)',$file)) $mime='video'; + if (eregi('\.(zip|rar|gz|tgz|z|cab|bz2)',$file)) $mime='archive'; + if (empty($alt)) $alt='Mime type: '.$mime; + + $mime.='.png'; + return ''.$alt.''; +} + + +/** + \brief Return if a filename is file name of a supported image format + \param file Filename + \return int -1=Not image filename, 0=Image filename but format not supported by PHP, 1=Image filename with format supported + */ +function image_format_supported($file) +{ + // Case filename is not a format image + if (! eregi('(\.gif|\.jpg|\.jpeg|\.png|\.bmp)$',$file,$reg)) return -1; + + // Case filename is a format image but not supported by this PHP + $imgfonction=''; + if (strtolower($reg[1]) == '.gif') $imgfonction = 'imagecreatefromgif'; + if (strtolower($reg[1]) == '.png') $imgfonction = 'imagecreatefrompng'; + if (strtolower($reg[1]) == '.jpg') $imgfonction = 'imagecreatefromjpeg'; + if (strtolower($reg[1]) == '.jpeg') $imgfonction = 'imagecreatefromjpeg'; + if (strtolower($reg[1]) == '.bmp') $imgfonction = 'imagecreatefromwbmp'; + if ($imgfonction) + { + if (! function_exists($imgfonction)) + { + // Fonctions de conversion non presente dans ce PHP + return 0; + } + } + + // Filename is a format image and supported by this PHP + return 1; +} + +/** + \brief Affiche info admin + \param text Text info + \param infoonimgalt Info is shown on alt of star picto + \return string String with info text + */ +function info_admin($texte,$infoonimgalt=0) +{ + global $conf,$langs; + $s=''; + if ($infoonimgalt) + { + $s.=img_picto($texte,'star'); + } + else + { + $s.='
'; + $s.=img_picto($langs->trans("InfoAdmin"),'star'); + $s.=' '; + $s.=$texte; + $s.='
'; + } + return $s; +} + + +/** + \brief Check permissions of a user to show a page and an object. + \param user User to check + \param feature Feature to check (in most cases, it's module name) + \param objectid Object ID if we want to check permission on on object (optionnal) + \param dbtable Table name where object is stored. Not used if objectid is null (optionnel) + \param feature Feature to check (second level of permission) + */ +function restrictedArea($user, $feature='societe', $objectid=0, $dbtablename='',$feature2='') +{ + global $db; + + //print "$user->id, $feature, $objectid, $dbtablename, $list ".$user->rights->societe->contact->lire; + + // Check read permission from module + // TODO Replace "feature" param by permission for reading + $readok=1; + if ($feature == 'societe') + { + if (! $user->rights->societe->lire && ! $user->rights->fournisseur->lire) $readok=0; + } + else if ($feature == 'contact') + { + if (! $user->rights->societe->contact->lire) $readok=0; + } + else if ($feature == 'prelevement') + { + if (! $user->rights->prelevement->bons->lire) $readok=0; + } + else if ($feature == 'commande_fournisseur') + { + if (! $user->rights->fournisseur->commande->lire) $readok=0; + } + else if ($feature == 'cheque') + { + if (! $user->rights->banque->cheque) $readok=0; + } + else if (! empty($feature2)) // This should be used for future changes + { + if (! $user->rights->$feature->$feature2->read) $readok=0; + } + else if (! empty($feature)) // This is for old permissions + { + if (! $user->rights->$feature->lire) $readok=0; + } + if (! $readok) accessforbidden(); + //print "Read access is ok"; + + // Check write permission from module + // TODO Add after "feature" a param for permission for writing + $createok=1; + if ($_GET["action"] == 'create' || $_POST["action"] == 'create') + { + if ($feature == 'societe') + { + if (! $user->rights->societe->creer && ! $user->rights->fournisseur->creer) $createok=0; + } + else if ($feature == 'contact') + { + if (! $user->rights->societe->contact->creer) $createok=0; + } + else if ($feature == 'prelevement') + { + if (! $user->rights->prelevement->bons->creer) $createok=0; + } + else if ($feature == 'commande_fournisseur') + { + if (! $user->rights->fournisseur->commande->creer) $createok=0; + } + else if ($feature == 'banque') + { + if (! $user->rights->banque->modifier) $createok=0; + } + else if ($feature == 'cheque') + { + if (! $user->rights->banque->cheque) $createok=0; + } + else + { + if (! $user->rights->$feature->creer) $createok=0; + } + if (! $createok) accessforbidden(); + //print "Write access is ok"; + } + + // If we have a particular object to check permissions on + if ($objectid) + { + $sql=''; + // Check permission for external users + if ($user->societe_id > 0) + { + if ($feature == 'societe') + { + if ($user->societe_id <> $objectid) accessforbidden(); + } + else + { + if (!$dbtablename) $dbtablename = $feature; // Si dbtable non d�fini, meme nom que le module + + $sql = "SELECT dbt.fk_soc"; + $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; + $sql.= " WHERE dbt.rowid = ".$objectid; + $sql.= " AND dbt.fk_soc = ".$user->societe_id; + } + } + // Check permission for internal users that are restricted on their objects + else if (! $user->rights->societe->client->voir) + { + if ($feature == 'societe') + { + $sql = "SELECT sc.fk_soc"; + $sql.= " FROM ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + $sql.= " WHERE sc.fk_soc = ".$objectid." AND sc.fk_user = ".$user->id; + } + else + { + if (!$dbtablename) $dbtablename = $feature; // Si dbtable non d�fini, meme nom que le module + + $sql = "SELECT sc.fk_soc"; + $sql.= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.fk_soc"; + $sql.= " WHERE dbt.rowid = ".$objectid; + $sql.= " AND IFNULL(sc.fk_user, ".$user->id.") = ".$user->id; + } + } + + //print $sql; + if ($sql) + { + $resql=$db->query($sql); + if ($resql) + { + if ($db->num_rows($resql) == 0) accessforbidden(); + } + else + { + dolibarr_syslog("functions.lib.php::restrictedArea sql=".$sql, LOG_ERR); + accessforbidden(); + } + } + } + + return 1; +} + + +/** + \brief Affiche message erreur de type acces interdit et arrete le programme + \param message Force error message + \param printheader Affiche avant le header + \remarks L'appel a cette fonction termine le code. + */ +function accessforbidden($message='',$printheader=1) +{ + global $user, $langs; + $langs->load("other"); + + if ($printheader && function_exists("llxHeader")) llxHeader(); + print '
'; + if (! $message) print $langs->trans("ErrorForbidden"); + else print $message; + print '
'; + print '
'; + if ($user->login) + { + print $langs->trans("CurrentLogin").': '.$user->login.'
'; + print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); + } + elseif (! empty($_SERVER["REMOTE_USER"])) + { + print $langs->trans("CurrentLogin").': '.$_SERVER["REMOTE_USER"]."
"; + print $langs->trans("ErrorForbidden2",$langs->trans("Home"),$langs->trans("Users")); + } + else + { + print $langs->trans("ErrorForbidden3"); + } + if (function_exists("llxFooter")) llxFooter(); + exit(0); +} + + +/** + * \brief Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remont�e des bugs. + * On doit appeler cette fonction quand une erreur technique bloquante est rencontree. + * Toutefois, il faut essayer de ne l'appeler qu'au sein de pages php, les classes devant + * renvoyer leur erreur par l'intermediaire de leur propriete "error". + * \param db Database handler + * \param error Chaine erreur ou tableau de chaines erreur complementaires a afficher + */ +function dolibarr_print_error($db='',$error='') +{ + global $conf,$langs,$argv; + $syslog = ''; + + // Si erreur intervenue avant chargement langue + if (! $langs) + { + require_once(DOL_DOCUMENT_ROOT ."/translate.class.php"); + $langs = new Translate("", $conf); + } + $langs->load("main"); + + if ($_SERVER['DOCUMENT_ROOT']) // Mode web + { + print $langs->trans("DolibarrHasDetectedError").".
\n"; + print $langs->trans("InformationToHelpDiagnose").":

\n"; + + print "".$langs->trans("Dolibarr").": ".DOL_VERSION."
\n";; + if (isset($conf->global->MAIN_FEATURES_LEVEL)) print "".$langs->trans("LevelOfFeature").": ".$conf->global->MAIN_FEATURES_LEVEL."
\n";; + print "".$langs->trans("Server").": ".$_SERVER["SERVER_SOFTWARE"]."
\n";; + print "".$langs->trans("RequestedUrl").": ".$_SERVER["REQUEST_URI"]."
\n";; + print "".$langs->trans("Referer").": ".$_SERVER["HTTP_REFERER"]."
\n";; + $syslog.="url=".$_SERVER["REQUEST_URI"]; + $syslog.=", query_string=".$_SERVER["QUERY_STRING"]; + } + else // Mode CLI + { + print '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n"; + $syslog.="pid=".getmypid(); + } + + if (is_object($db)) + { + if ($_SERVER['DOCUMENT_ROOT']) // Mode web + { + print "
\n"; + print "".$langs->trans("DatabaseTypeManager").": ".$db->type."
\n"; + print "".$langs->trans("RequestLastAccessInError").": ".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."
\n"; + print "".$langs->trans("ReturnCodeLastAccessInError").": ".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."
\n"; + print "".$langs->trans("InformationLastAccessInError").": ".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."
\n"; + } + else // Mode CLI + { + print '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n"; + print '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror()?$db->lastqueryerror():$langs->trans("ErrorNoRequestInError"))."\n"; + print '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno()?$db->lasterrno():$langs->trans("ErrorNoRequestInError"))."\n"; + print '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror()?$db->lasterror():$langs->trans("ErrorNoRequestInError"))."\n"; + + } + $syslog.=", sql=".$db->lastquery(); + $syslog.=", db_error=".$db->lasterror(); + } + + if ($error) + { + $langs->load("errors"); + + if (is_array($error)) $errors=$error; + else $errors=array($error); + + foreach($errors as $msg) + { + $msg=$langs->trans($msg); + if ($_SERVER['DOCUMENT_ROOT']) // Mode web + { + print "".$langs->trans("Message").": ".$msg."
\n" ; + } + else // Mode CLI + { + print '> '.$langs->transnoentities("Message").":\n".$msg."\n" ; + } + $syslog.=", msg=".$msg; + } + } + + dolibarr_syslog("Error ".$syslog, LOG_ERR); +} + + +/** + * \brief Deplacer les fichiers telecharg�s, apres quelques controles divers + * \param src_file Source filename + * \param dest_file Target filename + * \param allowoverwrite Overwrite if exists + * \return int >0 if OK, <0 if KO, Name of virus if virus found + */ +function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite) +{ + global $conf; + + $file_name = $dest_file; + + // If we need to make a virus scan + if ($conf->global->MAIN_USE_AVSCAN) + { + $malware = dol_avscan_file($src_file); + if ($malware) return $malware; + } + + // Security: + // On renomme les fichiers avec extention script web car si on a mis le rep + // documents dans un rep de la racine web (pas bien), cela permet d'executer + // du code a la demande. + if (eregi('\.htm|\.html|\.php|\.pl|\.cgi$',$file_name)) + { + $file_name.= '.noexe'; + } + + // Security: + // On interdit les remont�es de repertoire ainsi que les pipes dans + // les noms de fichiers. + if (eregi('\.\.',$src_file) || eregi('[<>|]',$src_file)) + { + dolibarr_syslog("Refused to deliver file ".$src_file); + return -1; + } + + // Security: + // On interdit les remont�es de repertoire ainsi que les pipe dans + // les noms de fichiers. + if (eregi('\.\.',$dest_file) || eregi('[<>|]',$dest_file)) + { + dolibarr_syslog("Refused to deliver file ".$dest_file); + return -1; + } + + // Check if destination file already exists + if (! $allowoverwrite) + { + if (file_exists($file_name)) + { + dolibarr_syslog("Functions.lib::dol_move_uploaded_file File ".$file_name." already exists", LOG_WARNING); + return -2; + } + } + + // Move file + $return=move_uploaded_file($src_file, $file_name); + if ($return) + { + dolibarr_syslog("Functions.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name, LOG_DEBUG); + return 1; + } + else + { + dolibarr_syslog("Functions.lib::dol_move_uploaded_file Failed to move ".$src_file." to ".$file_name, LOG_ERR); + return -3; + } +} + + +/** + \brief Show title line of an array + \param name libelle champ + \param file url pour clic sur tri + \param field champ de tri + \param begin ("" par defaut) + \param options ("" par defaut) + \param td options de l'attribut td ("" par defaut) + \param sortfield nom du champ sur lequel est effectu� le tri du tableau + \param sortorder ordre du tri + */ +function print_liste_field_titre($name, $file, $field, $begin="", $options="", $td="", $sortfield="", $sortorder="") +{ + global $conf; + //print "$name, $file, $field, $begin, $options, $td, $sortfield, $sortorder
\n"; + + // Le champ de tri est mis en �vidence. + // Exemple si (sortfield,field)=("nom","xxx.nom") ou (sortfield,field)=("nom","nom") + if ($sortfield == $field || $sortfield == ereg_replace("^[^\.]+\.","",$field)) + { + print ''; + } + else + { + print ''; + } + print $name; + + // If this is a sort field + if ($field) + { + //print " "; + print ''; + if (! $sortorder) + { + print ''.img_down("A-Z",0).''; + print ''.img_up("Z-A",0).''; + } + else + { + if ($field != $sortfield) + { + print ''.img_down("A-Z",0).''; + print ''.img_up("Z-A",0).''; + } + else { + $sortorder=strtoupper($sortorder); + if ($sortorder == 'DESC' ) { + print ''.img_down("A-Z",0).''; + print ''.img_up("Z-A",1).''; + } + if ($sortorder == 'ASC' ) { + print ''.img_down("A-Z",1).''; + print ''.img_up("Z-A",0).''; + } + } + } + } + print ""; +} + +/** + \brief Affichage d'un titre + \param titre Le titre a afficher + */ +function print_titre($titre) +{ + print '
'.$titre.'
'; +} + +/** + \brief Affichage d'un titre d'une fiche, align� a gauche + \param titre Le titre a afficher + \param mesg Message supl�mentaire a afficher a droite + \param picto Picto pour ligne de titre + \param pictoisfullpath 1=Picto is a full absolute url of image + */ +function print_fiche_titre($titre, $mesg='', $picto='', $pictoisfullpath=0) +{ + print "\n"; + print ''; + if ($picto) print ''; + print ''; + if (strlen($mesg)) + { + print ''; + } + print '
'.img_picto('',$picto, '', $pictoisfullpath).''; + print '
'.$titre.'
'; + print '
'.$mesg.'
'."\n"; +} + +/** + \brief Effacement d'un fichier + \param file Fichier a effacer ou masque de fichier a effacer + \param boolean true if file deleted, false if error + */ +function dol_delete_file($file) +{ + $ok=true; + foreach (glob($file) as $filename) + { + $ok=unlink($filename); + if ($ok) dolibarr_syslog("Removed file $filename",LOG_DEBUG); + else dolibarr_syslog("Failed to remove file $filename",LOG_ERR); + } + return $ok; +} + +/** + \brief Effacement d'un r�pertoire + \param file R�pertoire a effacer + */ +function dol_delete_dir($dir) +{ + return rmdir($dir); +} + +/** + \brief Effacement d'un r�pertoire $dir et de son arborescence + \param file R�pertoire a effacer + \param count Compteur pour comptage nb elements supprim�s + \return int Nombre de fichier+rep�rtoires supprim�s + */ +function dol_delete_dir_recursive($dir,$count=0) +{ + if ($handle = opendir("$dir")) + { + while (false !== ($item = readdir($handle))) + { + if ($item != "." && $item != "..") + { + if (is_dir("$dir/$item")) + { + $count=dol_delete_dir_recursive("$dir/$item",$count); + } + else + { + unlink("$dir/$item"); + $count++; + //echo " removing $dir/$item
\n"; + } + } + } + closedir($handle); + rmdir($dir); + $count++; + //echo "removing $dir
\n"; + } + + //echo "return=".$count; + return $count; +} + +/** + \brief Scan les fichiers avec un anti-virus + \param file Fichier a scanner + \return malware Nom du virus si infect� sinon retourne "null" + */ +function dol_avscan_file($file) +{ + $malware = ''; + + // Clamav + if (function_exists("cl_scanfile")) + { + $maxreclevel = 5 ; // maximal recursion level + $maxfiles = 1000; // maximal number of files to be scanned within archive + $maxratio = 200; // maximal compression ratio + $archivememlim = 0; // limit memory usage for bzip2 (0/1) + $maxfilesize = 10485760; // archived files larger than this value (in bytes) will not be scanned + + cl_setlimits($maxreclevel, $maxfiles, $maxratio, $archivememlim, $maxfilesize); + $malware = cl_scanfile($file); + } + + return $malware; +} + +/** + \brief Fonction print_barre_liste + \param titre Titre de la page + \param page num�ro de la page + \param file lien + \param options parametres complementaires lien ('' par defaut) + \param sortfield champ de tri ('' par defaut) + \param sortorder ordre de tri ('' par defaut) + \param center chaine du centre ('' par defaut) + \param num number of records found by select with limit+1 + \param totalnboflines Total number of records/lines for all pages (if known) + */ +function print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $center='', $num=-1, $totalnboflines=0) +{ + global $conf,$langs; + + if ($num > $conf->liste_limit or $num == -1) + { + $nextpage = 1; + } + else + { + $nextpage = 0; + } + + print ''; + + $pagelist = ''; + + if ($page > 0 || $num > $conf->liste_limit) + { + if ($totalnboflines) + { + print ''; + + $maxnbofpage=10; + + $nbpages=ceil($totalnboflines/$conf->liste_limit); + $cpt=($page-$maxnbofpage); + if ($cpt < 0) { $cpt=0; } + $pagelist.=$langs->trans('Page'); + if ($cpt>=1) + { + $pagelist.=' 1'; + if ($cpt >= 2) $pagelist.=' ...'; + } + do + { + if($cpt==$page) + { + $pagelist.= ' '.($page+1).''; + } + else + { + $pagelist.= ' '.($cpt+1).''; + } + $cpt++; + } + while ($cpt < $nbpages && $cpt<=$page+$maxnbofpage); + if ($cpt<$nbpages) + { + if ($cpt<$nbpages-1) $pagelist.= ' ...'; + $pagelist.= ' '.$nbpages.''; + } + } + else + { + print ''; + } + } + else + { + print ''; + } + + if ($center) + { + print ''; + } + + print '
'; + print '
'.$titre.'
'; + print '
'; + print '
'.$titre.'
'; + $pagelist.= $langs->trans('Page').' '.($page+1); + print '
'.$titre.'
'.$center.''; + + if ($sortfield) $options .= "&sortfield=".$sortfield; + if ($sortorder) $options .= "&sortorder=".$sortorder; + + // Affichage des fleches de navigation + print_fleche_navigation($page,$file,$options,$nextpage,$pagelist); + + print '
'; +} + +/** + \brief Fonction servant a afficher les fleches de navigation dans les pages de listes + \param page Num�ro de la page + \param file Lien + \param options Autres parametres d'url a propager dans les liens ("" par defaut) + \param nextpage Faut-il une page suivante + \param betweenarraows HTML Content to show between arrows + */ +function print_fleche_navigation($page,$file,$options='',$nextpage,$betweenarrows='') +{ + global $conf, $langs; + if ($page > 0) + { + print ''.img_previous($langs->trans("Previous")).''; + } + if ($betweenarrows) print ($page > 0?' ':'').$betweenarrows.($nextpage>0?' ':''); + if ($nextpage > 0) + { + print ''.img_next($langs->trans("Next")).''; + } +} + + +/** + * \brief Fonction qui retourne un taux de tva format� pour visualisation + * \remarks Fonction utilis�e dans les pdf et les pages html + * \param rate Rate value to format (19.6 19,6 19.6% 19,6%,...) + * \param foundpercent Add a percent % sign in output + * \param info_bits Miscellanous information on vat + * \return string Chaine avec montant format� (19,6 ou 19,6% ou 8.5% *) + */ +function vatrate($rate,$addpercent=false,$info_bits=0) +{ + // Test for compatibility + if (eregi('%',$rate)) + { + $rate=eregi_replace('%','',$rate); + $addpercent=true; + } + if (eregi('\*',$rate) || eregi(MAIN_LABEL_MENTION_NPR,$rate)) + { + $rate=eregi_replace('\*','',$rate); + $info_bits |= 1; + } + + $ret=price($rate,0,'',0,0).($addpercent?'%':''); + if ($info_bits & 1) $ret.=' '.MAIN_LABEL_MENTION_NPR; + return $ret; +} + + +/** + * \brief Fonction qui retourne un montant mon�taire format� pour visualisation + * \remarks Fonction utilis�e dans les pdf et les pages html + * \param amount Montant a formater + * \param html Formatage html ou pas (0 par defaut) + * \param outlangs Objet langs pour formatage text + * \param trunc 1=Tronque affichage si trop de d�cimales,0=Force le non troncage + * \param nbdecimal Nbre decimals minimum. + * \return string Chaine avec montant format� + * \seealso price2num Fonction inverse de price + */ +function price($amount, $html=0, $outlangs='', $trunc=1, $nbdecimal=2) +{ + global $langs,$conf; + + // Separateurs par defaut + $dec='.'; $thousand=' '; + + // Si $outlangs non force, on prend langue utilisateur + if (! is_object($outlangs)) $outlangs=$langs; + + if ($outlangs->trans("SeparatorDecimal") != "SeparatorDecimal") $dec=$outlangs->trans("SeparatorDecimal"); + if ($outlangs->trans("SeparatorThousand")!= "SeparatorThousand") $thousand=$outlangs->trans("SeparatorThousand"); + //print "amount=".$amount." html=".$html." trunc=".$trunc." nbdecimal=".$nbdecimal." dec=".$dec." thousand=".$thousand; + + //print "amount=".$amount."-"; + $amount = ereg_replace(',','.',$amount); + //print $amount."-"; + $datas = split('\.',$amount); + $decpart = $datas[1]; + $decpart = eregi_replace('0+$','',$decpart); // Supprime les 0 de fin de partie d�cimale + //print "decpart=".$decpart."
"; + $end=''; + + // On augmente au besoin si il y a plus de 2 d�cimales + if (strlen($decpart) > $nbdecimal) $nbdecimal=strlen($decpart); + // Si on depasse max + if ($trunc && $nbdecimal > $conf->global->MAIN_MAX_DECIMALS_SHOWN) + { + $nbdecimal=$conf->global->MAIN_MAX_DECIMALS_SHOWN; + if (eregi('\.\.\.',$conf->global->MAIN_MAX_DECIMALS_SHOWN)) + { + // Si un affichage est tronqu�, on montre des ... + $end='...'; + } + } + + // Formate nombre + if ($html) + { + $output=ereg_replace(' ',' ',number_format($amount, $nbdecimal, $dec, $thousand)); + } + else + { + $output=number_format($amount, $nbdecimal, $dec, $thousand); + } + $output.=$end; + + return $output; +} + +/** + * \brief Fonction qui retourne un numerique conforme PHP et SQL, depuis un montant au + * format utilisateur. + * \remarks Fonction a appeler sur montants saisis avant un insert en base + * \param amount Montant a formater + * \param rounding 'MU'=Round to Max unit price (MAIN_MAX_DECIMALS_UNIT) + * 'MT'=Round to Max with Tax (MAIN_MAX_DECIMALS_TOT) + * 'MS'=Round to Max Shown (MAIN_MAX_DECIMALS_SHOWN) + * ''=No rounding + * \return string Montant au format num�rique PHP et SQL (Exemple: '99.99999') + * \seealso price Fonction inverse de price2num + */ +function price2num($amount,$rounding='') +{ + global $conf; + + // Round PHP function does not allow number like '1,234.5'. + // Numbers must be '1234.5' + // \TODO If there is already a ".", we remove ",", otherwise replace by "." + $amount=ereg_replace(',','.',$amount); + $amount=ereg_replace(' ','',$amount); + if ($rounding) + { + if ($rounding == 'MU') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_UNIT); + elseif ($rounding == 'MT') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_TOT); + elseif ($rounding == 'MS') $amount = round($amount,$conf->global->MAIN_MAX_DECIMALS_SHOWN); + else $amount='ErrorBadParameterProvidedToFunction'; + $amount=ereg_replace(',','.',$amount); + $amount=ereg_replace(' ','',$amount); + } + return $amount; +} + + +/** + * \brief Return vat rate of a product in a particular selling country + */ +function get_product_vat_for_country($idprod, $countrycode) +{ + global $db; + + $product=new Product($db); + $product->fetch($idprod); + + // \TODO Read rate according to countrycode + // For the moment only one rate supported + + return $product->tva_tx; +} + + +/** + \brief Fonction qui renvoie la tva d'une ligne (en fonction du vendeur, acheteur et taux du produit) + \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. + Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle. + Sinon TVA propos�e par d�faut=0. Fin de r�gle. + \param societe_vendeuse Objet soci�t� vendeuse + \param societe_acheteuse Objet soci�t� acheteuse + \param taux_produit Taux par defaut du produit vendu (old way to get product vat rate) + \param idprod Id product (new way to get product vat rate) + \return float Taux de tva a appliquer, -1 si ne peut etre d�termin� + */ +function get_default_tva($societe_vendeuse, $societe_acheteuse, $taux_produit, $idprod=0) +{ + if (!is_object($societe_vendeuse)) return -1; + if (!is_object($societe_acheteuse)) return -1; + + dolibarr_syslog("get_default_tva vendeur_assujeti=".$societe_vendeuse->tva_assuj." pays_vendeur=".$societe_vendeuse->pays_code.", seller in cee=".$societe_vendeuse->isInEEC().", pays_acheteur=".$societe_acheteuse->pays_code.", buyer in cee=".$societe_acheteuse->isInEEC().", taux_produit(deprecated)=".$taux_produit.", idprod=".$idprod); + + // Si vendeur non assujeti a TVA (tva_assuj vaut 0/1 ou franchise/reel) + if (is_numeric($societe_vendeuse->tva_assuj) && ! $societe_vendeuse->tva_assuj) return 0; + if (! is_numeric($societe_vendeuse->tva_assuj) && $societe_vendeuse->tva_assuj=='franchise') return 0; + + // Si le (pays vendeur = pays acheteur) alors la TVA par d�faut=TVA du produit vendu. Fin de r�gle. + //if (is_object($societe_acheteuse) && ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) && ($societe_acheteuse->tva_assuj == 1 || $societe_acheteuse->tva_assuj == 'reel')) + // Le test ci-dessus ne devrait pas etre necessaire. Me signaler l'exemple du cas juridique concercn� si le test suivant n'est pas suffisant. + if ($societe_vendeuse->pays_id == $societe_acheteuse->pays_id) + { + if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); + if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva + return $taux_produit; + } + + // Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par l'acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. + // Non g�r� + + // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. + if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && ! $societe_acheteuse->tva_intra) + { + if ($idprod) return get_product_vat_for_country($idprod,$societe_vendeuse->pays_code); + if (strlen($taux_produit) == 0) return -1; // Si taux produit = '', on ne peut d�terminer taux tva + return $taux_produit; + } + + // Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA intra) alors TVA par d�faut=0. Fin de r�gle. + if (($societe_vendeuse->isInEEC() && $societe_acheteuse->isInEEC()) && $societe_acheteuse->tva_intra) + { + return 0; + } + + // Sinon la TVA propos�e par d�faut=0. Fin de r�gle. + // Rem: Cela signifie qu'au moins un des 2 est hors Communaut� europ�enne et que le pays diff�re + return 0; +} + + +/** + \brief Fonction qui renvoie si tva doit etre tva percue r�cup�rable + \remarks Si vendeur non assujeti a TVA, TVA par d�faut=0. Fin de r�gle. + Si le (pays vendeur = pays acheteur) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (bien vendu = moyen de transports neuf comme auto, bateau, avion) alors TVA par d�faut=0 (La TVA doit �tre pay� par acheteur au centre d'impots de son pays et non au vendeur). Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = particulier ou entreprise sans num TVA intra) alors TVA par d�faut=TVA du produit vendu. Fin de r�gle. + Si (vendeur et acheteur dans Communaut� europ�enne) et (acheteur = entreprise avec num TVA) intra alors TVA par d�faut=0. Fin de r�gle. + Sinon TVA propos�e par d�faut=0. Fin de r�gle. + \param societe_vendeuse Objet soci�t� vendeuse + \param societe_acheteuse Objet soci�t� acheteuse + \param taux_produit Taux par defaut du produit vendu + \return float 0 or 1 + */ +function get_default_npr($societe_vendeuse, $societe_acheteuse, $taux_produit) +{ + + return 0; +} + + +/** + \brief Renvoie oui ou non dans la langue choisie + \param yesno Variable pour test si oui ou non + \param case 1=Yes/No, 0=yes/no + \param color 0=texte only, 1=Text is format with a color font style + */ +function yn($yesno, $case=1, $color=0) +{ + global $langs; + $result='unknown'; + if ($yesno == 1 || strtolower($yesno) == 'yes' || strtolower($yesno) == 'true') // A mettre avant test sur no a cause du == 0 + { + $result=($case?$langs->trans("Yes"):$langs->trans("yes")); + $class='ok'; + } + elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') + { + $result=($case?$langs->trans("No"):$langs->trans("no")); + $class='error'; + } + if ($color) return ''.$result.''; + return $result; +} + + +/** + \brief Fonction pour qui retourne le rowid d'un departement par son code + \param db handler d'acc�s base + \param code Code r�gion + \param pays_id Id du pays + */ +function departement_rowid($db,$code, $pays_id) +{ + $sql = "SELECT c.rowid FROM ".MAIN_DB_PREFIX."c_departements as c,".MAIN_DB_PREFIX."c_regions as r"; + $sql .= " WHERE c.code_departement=". $code; + $sql .= " AND c.fk_region = r.code_region"; + $sql .= " AND r.fk_pays =".$pays_id; + + if ($db->query($sql)) + { + $num = $db->num_rows(); + if ($num) + { + $obj = $db->fetch_object(); + return $obj->rowid; + } + else + { + return 0; + } + $db->free(); + } + else + { + return 0; + } +} + +/** + \brief Renvoi un chemin de classement r�pertoire en fonction d'un id + \remarks Examples: 1->"0/0/1/", 15->"0/1/5/" + \param $num Id a d�composer + \param $level Niveau de decoupage (1, 2 ou 3 niveaux) + */ +function get_exdir($num,$level=3) +{ + $num = eregi_replace('[^0-9]','',$num); + $num = substr("000".$num, -$level); + if ($level == 1) return substr($num,0,1).'/'; + if ($level == 2) return substr($num,1,1).'/'.substr($num,0,1).'/'; + if ($level == 3) return substr($num,2,1).'/'.substr($num,1,1).'/'.substr($num,0,1).'/'; + return ''; +} + +/** + \brief Cr�ation de r�pertoire recursive + \param $dir R�pertoire a cr�er + \return int < 0 si erreur, >= 0 si succ�s + */ +function create_exdir($dir) +{ + dolibarr_syslog("functions.lib.php::create_exdir: dir=$dir",LOG_INFO); + + if (@is_dir($dir)) return 0; + + $nberr=0; + $nbcreated=0; + + $ccdir = ''; + $cdir = explode("/",$dir); + for ($i = 0 ; $i < sizeof($cdir) ; $i++) + { + if ($i > 0) $ccdir .= '/'.$cdir[$i]; + else $ccdir = $cdir[$i]; + if (eregi("^.:$",$ccdir,$regs)) continue; // Si chemin Windows incomplet, on poursuit par rep suivant + + // Attention, le is_dir() peut �chouer bien que le rep existe. + // (ex selon config de open_basedir) + if ($ccdir) + { + if (! @is_dir($ccdir)) + { + dolibarr_syslog("functions.lib.php::create_exdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.",LOG_DEBUG); + + umask(0); + if (! @mkdir($ccdir, 0755)) + { + // Si le is_dir a renvoy� une fausse info, alors on passe ici. + dolibarr_syslog("functions.lib.php::create_exdir: Fails to create directory '".$ccdir."' or directory already exists.",LOG_WARNING); + $nberr++; + } + else + { + dolibarr_syslog("functions.lib.php::create_exdir: Directory '".$ccdir."' created",LOG_DEBUG); + $nberr=0; // On remet a z�ro car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s + $nbcreated++; + } + } + else + { + $nberr=0; // On remet a z�ro car si on arrive ici, cela veut dire que les �checs pr�c�dents peuvent etre ignor�s + } + } + } + return ($nberr ? -$nberr : $nbcreated); +} + + + + +/** + \brief Retourne le num�ro de la semaine par rapport a une date + \param time Date au format 'timestamp' + \return int Num�ro de semaine + */ +function numero_semaine($time) +{ + $stime = strftime( '%Y-%m-%d',$time); + + if (eregi('^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?',$stime,$reg)) + { + // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS' + $annee = $reg[1]; + $mois = $reg[2]; + $jour = $reg[3]; + } + + /* + * Norme ISO-8601: + * - La semaine 1 de toute ann�e est celle qui contient le 4 janvier ou que la semaine 1 de toute ann�e est celle qui contient le 1er jeudi de janvier. + * - La majorit� des ann�es ont 52 semaines mais les ann�es qui commence un jeudi et les ann�es bissextiles commen�ant un mercredi en poss�de 53. + * - Le 1er jour de la semaine est le Lundi + */ + + // D�finition du Jeudi de la semaine + if (date("w",mktime(12,0,0,$mois,$jour,$annee))==0) // Dimanche + $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-3*24*60*60; + else if (date("w",mktime(12,0,0,$mois,$jour,$annee))<4) // du Lundi au Mercredi + $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)+(4-date("w",mktime(12,0,0,$mois,$jour,$annee)))*24*60*60; + else if (date("w",mktime(12,0,0,$mois,$jour,$annee))>4) // du Vendredi au Samedi + $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee)-(date("w",mktime(12,0,0,$mois,$jour,$annee))-4)*24*60*60; + else // Jeudi + $jeudiSemaine = mktime(12,0,0,$mois,$jour,$annee); + + // D�finition du premier Jeudi de l'ann�e + if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==0) // Dimanche + { + $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+4*24*60*60; + } + else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))<4) // du Lundi au Mercredi + { + $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(4-date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine))))*24*60*60; + } + else if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))>4) // du Vendredi au Samedi + { + $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine))+(7-(date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))-4))*24*60*60; + } + else // Jeudi + { + $premierJeudiAnnee = mktime(12,0,0,1,1,date("Y",$jeudiSemaine)); + } + + // D�finition du num�ro de semaine: nb de jours entre "premier Jeudi de l'ann�e" et "Jeudi de la semaine"; + $numeroSemaine = ( + ( + date("z",mktime(12,0,0,date("m",$jeudiSemaine),date("d",$jeudiSemaine),date("Y",$jeudiSemaine))) + - + date("z",mktime(12,0,0,date("m",$premierJeudiAnnee),date("d",$premierJeudiAnnee),date("Y",$premierJeudiAnnee))) + ) / 7 + ) + 1; + + // Cas particulier de la semaine 53 + if ($numeroSemaine==53) + { + // Les ann�es qui commence un Jeudi et les ann�es bissextiles commen�ant un Mercredi en poss�de 53 + if (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==4 || (date("w",mktime(12,0,0,1,1,date("Y",$jeudiSemaine)))==3 && date("z",mktime(12,0,0,12,31,date("Y",$jeudiSemaine)))==365)) + { + $numeroSemaine = 53; + } + else + { + $numeroSemaine = 1; + } + } + + //echo $jour."-".$mois."-".$annee." (".date("d-m-Y",$premierJeudiAnnee)." - ".date("d-m-Y",$jeudiSemaine).") -> ".$numeroSemaine."
"; + + return sprintf("%02d",$numeroSemaine); +} + + +/** + \brief Retourne le picto champ obligatoire + \return string Chaine avec picto obligatoire + */ +function picto_required() +{ + return '*'; +} +/** + \brief Convertit une masse d'une unite vers une autre unite + \param weight float Masse a convertir + \param from_unit int Unite originale en puissance de 10 + \param to_unit int Nouvelle unite en puissance de 10 + \return float Masse convertie + */ +function weight_convert($weight,&$from_unit,$to_unit) +{ + /* Pour convertire 320 gr en Kg appeler + * $f = -3 + * weigh_convert(320, $f, 0) retournera 0.32 + * + */ + while ($from_unit <> $to_unit) + { + if ($from_unit > $to_unit) + { + $weight = $weight * 10; + $from_unit = $from_unit - 1; + $weight = weight_convert($weight,$from_unit, $to_unit); + } + if ($from_unit < $to_unit) + { + $weight = $weight / 10; + $from_unit = $from_unit + 1; + $weight = weight_convert($weight,$from_unit, $to_unit); + } + } + + return $weight; +} + +/** + \brief Renvoi le texte d'une unite + \param int Unit + \param measuring_style Le style de mesure : weight, volume,... + \return string Unite + \todo gerer les autres unit�s de mesure comme la livre, le gallon, le litre, ... + */ +function measuring_units_string($unit,$measuring_style='') +{ + /* Note Rodo aux dev :) + * Ne pas ins�rer dans la base de donn�es ces valeurs + * cela surchagerait inutilement d'une requete suppl�mentaire + * pour quelque chose qui est somme toute peu variable + */ + + global $langs; + + if ($measuring_style == 'weight') + { + $measuring_units[3] = $langs->trans("WeightUnitton"); + $measuring_units[0] = $langs->trans("WeightUnitkg"); + $measuring_units[-3] = $langs->trans("WeightUnitg"); + $measuring_units[-6] = $langs->trans("WeightUnitmg"); + } + else if ($measuring_style == 'volume') + { + $measuring_units[0] = $langs->trans("VolumeUnitm3"); + $measuring_units[-3] = $langs->trans("VolumeUnitdm3"); + $measuring_units[-6] = $langs->trans("VolumeUnitcm3"); + $measuring_units[-9] = $langs->trans("VolumeUnitmm3"); + } + + return $measuring_units[$unit]; +} + +/** + \brief Clean an url + \param url Url + \param http 1: keep http, 0: remove also http + \return string CleanUrl + */ +function clean_url($url,$http=1) +{ + if (eregi('^(https?:[\\\/]+)?([0-9A-Z\-\.]+\.[A-Z]{2,4})(:[0-9]+)?',$url,$regs)) + { + $proto=$regs[1]; + $domain=$regs[2]; + $port=$regs[3]; + //print $url." -> ".$proto." - ".$domain." - ".$port; + $url = unaccent_isostring(trim($url)); + + // Si http: defini on supprime le http (Si https on ne supprime pas) + if ($http==0) + { + if (eregi('^http:[\\\/]+',$url)) + { + $url = eregi_replace('^http:[\\\/]+','',$url); + $proto = ''; + } + } + + // On passe le nom de domaine en minuscule + $url = eregi_replace('^(https?:[\\\/]+)?'.$domain,$proto.strtolower($domain),$url); + + return $url; + } +} + + + +/** + \brief Clean a string from all html tags + \param StringHtml String to clean + \param removelinefeed Replace also all lines feeds by a space + \return string String cleaned + */ +function clean_html($StringHtml,$removelinefeed=1) +{ + $pattern = "<[^>]+>"; + $temp = dol_entity_decode($StringHtml); + $temp = ereg_replace($pattern,"",$temp); + + // Supprime aussi les retours + if ($removelinefeed) $temp=str_replace("\n"," ",$temp); + + // et les espaces doubles + while(STRPOS($temp," ")) + { + $temp = STR_REPLACE(" "," ",$temp); + } + $CleanString = $temp; + return $CleanString; +} + +/** + \brief Convert a binaray data to string that represent hexadecimal value + \param bin Value to convert + \param pad Add 0 + \param upper Convert to tupper + \return string x + */ +function binhex($bin, $pad=false, $upper=false){ + $last = strlen($bin)-1; + for($i=0; $i<=$last; $i++){ $x += $bin[$last-$i] * pow(2,$i); } + $x = dechex($x); + if($pad){ while(strlen($x) < intval(strlen($bin))/4){ $x = "0$x"; } } + if($upper){ $x = strtoupper($x); } + return $x; +} + +/** + \brief Convertir de l'h�xad�cimal en binaire + \param string hexa + \return string bin + */ +function hexbin($hexa){ + $bin=''; + for($i=0;$i",$ret); + return $ret; + } +} + +/** + * \brief This function is called to encode a string into a HTML string + * \param stringtoencode String to encode + * \param nl2brmode 0=Adding br before \n, 1=Replacing \n by br (for use with FPDF writeHTMLCell function for example) + * \remarks For PDF usage, you can show text by 2 ways: + * - writeHTMLCell -> param must be encoded into HTML. + * - MultiCell -> param must not be encoded into HTML. + * Because writeHTMLCell convert also \n into
, if function + * is used to build PDF, nl2brmode must be 1. + */ +function dol_htmlentitiesbr($stringtoencode,$nl2brmode=0) +{ + if (dol_textishtml($stringtoencode)) + { + // Replace "
" by "
". It's same and avoid pb with FPDF. + $stringtoencode=eregi_replace('",$ret); + $ret=eregi_replace(''; + if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) { $ok=0; break; } + if ($ordchar > 126 && $ordchar < 160) { $ok=0; break; } + } + return $ok; +} + + +/** + * \brief Return nb of lines of a text + * \param s String to check + * \param maxchar Not yet used + * \return int 0 if bad iso, 1 if good iso + */ +function dol_nboflines($s,$maxchar=0) +{ + $arraystring=split("\n",$s); + $nb=sizeof($arraystring); + + return $nb; +} + + +/** + \brief Fonction retournant le nombre de jour fieries samedis et dimanches entre 2 dates entrees en timestamp + \remarks SERVANT AU CALCUL DES JOURS OUVRABLES + \param timestampStart Timestamp de debut + \param timestampEnd Timestamp de fin + \return nbFerie Nombre de jours feries + */ +function num_public_holiday($timestampStart, $timestampEnd, $countrycode='FR') +{ + $nbFerie = 0; + + while ($timestampStart != $timestampEnd) + { + $ferie=false; + $countryfound=0; + + $jour = date("d", $timestampStart); + $mois = date("m", $timestampStart); + $annee = date("Y", $timestampStart); + + if ($countrycode == 'FR') + { + $countryfound=1; + + // Definition des dates feriees fixes + if($jour == 1 && $mois == 1) $ferie=true; // 1er janvier + if($jour == 1 && $mois == 5) $ferie=true; // 1er mai + if($jour == 8 && $mois == 5) $ferie=true; // 5 mai + if($jour == 14 && $mois == 7) $ferie=true; // 14 juillet + if($jour == 15 && $mois == 8) $ferie=true; // 15 aout + if($jour == 1 && $mois == 11) $ferie=true; // 1 novembre + if($jour == 11 && $mois == 11) $ferie=true; // 11 novembre + if($jour == 25 && $mois == 12) $ferie=true; // 25 decembre + + // Calcul du jour de paques + $date_paques = easter_date($annee); + $jour_paques = date("d", $date_paques); + $mois_paques = date("m", $date_paques); + if($jour_paques == $jour && $mois_paques == $mois) $ferie=true; + // Paques + + // Calcul du jour de l ascension (38 jours apres Paques) + $date_ascension = mktime(date("H", $date_paques), + date("i", $date_paques), + date("s", $date_paques), + date("m", $date_paques), + date("d", $date_paques) + 38, + date("Y", $date_paques) + ); + $jour_ascension = date("d", $date_ascension); + $mois_ascension = date("m", $date_ascension); + if($jour_ascension == $jour && $mois_ascension == $mois) $ferie=true; + //Ascension + + // Calcul de Pentecote (11 jours apres Paques) + $date_pentecote = mktime(date("H", $date_ascension), + date("i", $date_ascension), + date("s", $date_ascension), + date("m", $date_ascension), + date("d", $date_ascension) + 11, + date("Y", $date_ascension) + ); + $jour_pentecote = date("d", $date_pentecote); + $mois_pentecote = date("m", $date_pentecote); + if($jour_pentecote == $jour && $mois_pentecote == $mois) $ferie=true; + //Pentecote + + // Calul des samedis et dimanches + $jour_julien = unixtojd($timestampStart); + $jour_semaine = jddayofweek($jour_julien, 0); + if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true; + //Samedi (6) et dimanche (0) + } + + // Mettre ici cas des autres pays + + + // Cas pays non defini + if (! $countryfound) + { + // Calul des samedis et dimanches + $jour_julien = unixtojd($timestampStart); + $jour_semaine = jddayofweek($jour_julien, 0); + if($jour_semaine == 0 || $jour_semaine == 6) $ferie=true; + //Samedi (6) et dimanche (0) + } + + // On incremente compteur + if ($ferie) $nbFerie++; + + // Incrementation du nombre de jour (on avance dans la boucle) + $jour++; + $timestampStart=mktime(0,0,0,$mois,$jour,$annee); + } + + return $nbFerie; +} + +/** + \brief Fonction retournant le nombre de jour entre deux dates + \param timestampStart Timestamp de d�but + \param timestampEnd Timestamp de fin + \param lastday On prend en compte le dernier jour, 0: non, 1:oui + \return nbjours Nombre de jours + */ +function num_between_day($timestampStart, $timestampEnd, $lastday=0) +{ + if ($timestampStart < $timestampEnd) + { + if ($lastday == 1) + { + $bit = 0; + } + else + { + $bit = 1; + } + $nbjours = round(($timestampEnd - $timestampStart)/(60*60*24)-$bit); + } + return $nbjours; +} + +/** + \brief Fonction retournant le nombre de jour entre deux dates sans les jours f�ri�s (jours ouvr�s) + \param timestampStart Timestamp de d�but + \param timestampEnd Timestamp de fin + \param inhour 0: sort le nombre de jour , 1: sort le nombre d'heure (72 max) + \param lastday On prend en compte le dernier jour, 0: non, 1:oui + \return nbjours Nombre de jours ou d'heures + */ +function num_open_day($timestampStart, $timestampEnd,$inhour=0,$lastday=0) +{ + global $langs; + + if ($timestampStart < $timestampEnd) + { + $bit = 0; + if ($lastday == 1) $bit = 1; + $nbOpenDay = num_between_day($timestampStart, $timestampEnd, $bit) - num_public_holiday($timestampStart, $timestampEnd); + $nbOpenDay.= " ".$langs->trans("Days"); + if ($inhour == 1 && $nbOpenDay <= 3) $nbOpenDay = $nbOpenDay*24 . $langs->trans("HourShort"); + return $nbOpenDay; + } + else + { + return $langs->trans("Error"); + } +} + +/** + \brief Fonction retournant le nombre de lignes dans un texte format� + \param texte Texte + \return nblines Nombre de lignes + */ +function num_lines($texte,$maxlinesize=0) +{ + $repTable = array("\t" => " ", "\n" => "
", "\r" => " ", "\0" => " ", "\x0B" => " "); + $texte = strtr($texte, $repTable); + $pattern = '/(<[^>]+>)/Uu'; + $a = preg_split($pattern, $texte, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $nblines = ((count($a)+1)/2); + // count possible auto line breaks + if($maxlinesize) + { + foreach ($a as $line) + { + if (strlen($line)>$maxlinesize) + { + //$line_dec = html_entity_decode(strip_tags($line)); + $line_dec = html_entity_decode($line); + if(strlen($line_dec)>$maxlinesize) + { + $line_dec=wordwrap($line_dec,$maxlinesize,'\n',true); + $nblines+=substr_count($line_dec,'\n'); + } + } + } + } + return $nblines; +} + +/** + * \brief Fonction simple identique a microtime de PHP 5 mais compatible PHP 4 + * \return float Time en millisecondes avec decimal pour microsecondes + */ +function dol_microtime_float() +{ + list($usec, $sec) = explode(" ", microtime()); + return ((float)$usec + (float)$sec); +} + +/* + * \brief Return if a text is a html content + * \param msg Content to check + * \param option 0=Full detection, 1=Fast check + * \return boolean true/false + */ +function dol_textishtml($msg,$option=0) +{ + if ($option == 1) + { + if (eregi('',$msg)) return true; + elseif (eregi('',$msg)) return true; + elseif (eregi('&[A-Z0-9]{1,6};',$msg)) return true; + return false; + } +} + +/* + * \brief Effectue les substitutions des mots cl�s par les donn�es en fonction du tableau + * \param chaine Chaine dans laquelle faire les substitutions + * \param substitutionarray Tableau cl� substitution => valeur a mettre + * \return string Chaine avec les substitutions effectu�es + */ +function make_substitutions($chaine,$substitutionarray) +{ + foreach ($substitutionarray as $key => $value) + { + $chaine=ereg_replace($key,$value,$chaine); + } + return $chaine; +} + + +/* + * \brief Formate l'affichage de date de d�but et de fin + * \param date_start date de d�but + * \param date_end date de fin + */ +function print_date_range($date_start,$date_end) +{ + global $langs; + + if ($date_start && $date_end) + { + print ' ('.$langs->trans('DateFromTo',dolibarr_print_date($date_start),dolibarr_print_date($date_end)).')'; + } + if ($date_start && ! $date_end) + { + print ' ('.$langs->trans('DateFrom',dolibarr_print_date($date_start)).')'; + } + if (! $date_start && $date_end) + { + print ' ('.$langs->trans('DateUntil',dolibarr_print_date($date_end)).')'; + } +} + + +/* + * + */ +function make_alpha_from_numbers($number) +{ + $numeric = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if($numberload("main"); + + $month = array (1 => $langs->trans("January"), + 2 => $langs->trans("February"), + 3 => $langs->trans("March"), + 4 => $langs->trans("April"), + 5 => $langs->trans("May"), + 6 => $langs->trans("June"), + 7 => $langs->trans("July"), + 8 => $langs->trans("August"), + 9 => $langs->trans("September"), + 10 => $langs->trans("October"), + 11 => $langs->trans("November"), + 12 => $langs->trans("December") + ); + + if ($selected >=0) + { + $return=''; + foreach ($month as $key => $val) + { + if ($selected == $key) + { + $return = $val; + } + } + return $return; + } + else + { + return $month; + } +} + +/** + \brief Returns formated reduction + \param reduction Reduction percentage + \return string Formated reduction + */ +function dolibarr_print_reduction($reduction=0) +{ + global $langs; + $langs->load("main"); + + $string = ''; + + if ($reduction == 100) + { + $string = $langs->trans("Offered"); + } + else + { + $string = $reduction.'%'; + } + + return $string; +} + + +/** + \brief Returns formated reduction + \param reduction Reduction percentage + \return int Return number of error messages shown + */ +function dol_htmloutput_errors($mesgstring='',$mesgarray='') +{ + global $langs; + + $ret = 0; + $langs->load("errors"); + + if (is_array($mesgarray) && sizeof($mesgarray)) + { + print '
'; + foreach($mesgarray as $message) + { + $ret++; + print $langs->trans($message)."
\n"; + } + print '
'; + } + if ($mesgstring) + { + $ret++; + print '
'; + print $mesgstring; + print '
'; + } + + return $ret; +} + + +/** + * \brief This function output memory used by PHP and exit everything. Used for debugging purpose. + */ +function stopwithmem() +{ + print memory_get_usage(); + llxFooter(); + exit; +} + + +/** + * \brief Advanced sort array by second index function, which produces + * ascending (default) or descending output and uses optionally + * natural case insensitive sorting (which can be optionally case + * sensitive as well). + */ +function dol_sort_array($array, $index, $order='asc', $natsort, $case_sensitive) +{ + // Clean parameters + $order=strtolower($order); + + if (is_array($array) && count($array)>0) + { + foreach(array_keys($array) as $key) $temp[$key]=$array[$key][$index]; + if (!$natsort) ($order=='asc') ? asort($temp) : arsort($temp); + else + { + ($case_sensitive) ? natsort($temp) : natcasesort($temp); + if($order!='asc') $temp=array_reverse($temp,TRUE); + } + foreach(array_keys($temp) as $key) (is_numeric($key))? $sorted[]=$array[$key] : $sorted[$key]=$array[$key]; + return $sorted; + } + return $array; +} + +?>