diff --git a/ChangeLog b/ChangeLog index 0b6341ffbc1..89978452254 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,7 +21,11 @@ For users: - New: Can define a default choice for choice "More action when recording a subscription" (foundation module). - New: Add link to check professional id for india. - +- New: [ task #731 ] Uniformize ref generation +- New: [ task #748 ] Add a link "Dolibarr" into left menu +- New: Script email_unpaid_invoices_to_representative accepts now a parameter test + and a delay. + For translators: - Update language files. diff --git a/dev/skeletons/modMyModule.class.php b/dev/skeletons/modMyModule.class.php index 7abeeb913b1..2ac35dbd340 100644 --- a/dev/skeletons/modMyModule.class.php +++ b/dev/skeletons/modMyModule.class.php @@ -228,6 +228,7 @@ class modMyModule extends DolibarrModules // $this->export_sql_end[$r] =' FROM ('.MAIN_DB_PREFIX.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)'; // $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)'; // $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture'; + // $this->export_sql_order[$r] .=' ORDER BY s.nom'; // $r++; } diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 57193dfdb71..35768104e39 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -28,11 +28,13 @@ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; $langs->load("admin"); $langs->load("errors"); $langs->load('other'); +$langs->load('bills'); if (! $user->admin) accessforbidden(); @@ -304,6 +306,8 @@ $linkback=''.$langs->trans("BackToM print_fiche_titre($langs->trans("BillsSetup"),$linkback,'setup'); print '
'; +$head = invoice_admin_prepare_head(null); +dol_fiche_head($head, 'general', $langs->trans("Invoices"), 0, 'invoice'); /* * Numbering module diff --git a/htdocs/admin/prelevement.php b/htdocs/admin/prelevement.php index bbbc307e420..f5dfb2bc8fb 100644 --- a/htdocs/admin/prelevement.php +++ b/htdocs/admin/prelevement.php @@ -181,7 +181,7 @@ if (! empty($conf->global->MAIN_MODULE_NOTIFICATION)) $var=!$var; if (!$obj->fk_societe) { - $username= $obj->firstname.' '.$obj->lastname; + $username=dolGetFirstLastname($obj->firstname,$obj->lastname); $internalusers[$obj->rowid] = $username; } @@ -254,7 +254,7 @@ if ($resql) $var=!$var; print ""; - print ''.$obj->firstname." ".$obj->lastname.''; + print ''.dolGetFirstLastname($obj->firstname,$obj->lastname).''; $label=($langs->trans("Notify_".$obj->code)!="Notify_".$obj->code?$langs->trans("Notify_".$obj->code):$obj->label); print ''.$label.''; print '
rowid.'">'.img_delete().''; diff --git a/htdocs/admin/propal.php b/htdocs/admin/propal.php index 04f429f50bb..6c18da0e240 100644 --- a/htdocs/admin/propal.php +++ b/htdocs/admin/propal.php @@ -31,7 +31,7 @@ require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; - +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; $langs->load("admin"); $langs->load("errors"); $langs->load('other'); @@ -214,6 +214,7 @@ else if ($action == 'setmod') $dirmodels=array_merge(array('/'),(array) $conf->modules_parts['models']); + llxHeader('',$langs->trans("PropalSetup")); $form=new Form($db); @@ -223,6 +224,10 @@ $form=new Form($db); $linkback=''.$langs->trans("BackToModuleList").''; print_fiche_titre($langs->trans("PropalSetup"),$linkback,'setup'); +$head = propal_admin_prepare_head(null); + +dol_fiche_head($head, 'general', $langs->trans("Propales"), 0, 'propal'); + /* * Module numerotation */ diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 48307e19905..a6199580353 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -948,7 +948,7 @@ class ActionComm extends CommonObject $event['startdate']=$datestart; $event['duration']=$duration; // Not required with type 'journal' $event['enddate']=$dateend; // Not required with type 'journal' - $event['author']=$obj->firstname.($obj->lastname?" ".$obj->lastname:""); + $event['author']=dolGetFirstLastname($obj->firstname, $obj->lastname); $event['priority']=$obj->priority; $event['fulldayevent']=$obj->fulldayevent; $event['location']=$obj->location; diff --git a/htdocs/comm/action/index.php b/htdocs/comm/action/index.php index f16579051e1..0b182c7645f 100644 --- a/htdocs/comm/action/index.php +++ b/htdocs/comm/action/index.php @@ -486,7 +486,7 @@ if ($showbirthday) $event->datep=dol_mktime(0,0,0,$datearray['mon'],$datearray['mday'],$year,true); // For full day events, date are also GMT but they wont but converted during output $event->datef=$event->datep; $event->type_code='BIRTHDAY'; - $event->libelle=$langs->trans("Birthday").' '.$obj->firstname.' '.$obj->lastname; + $event->libelle=$langs->trans("Birthday").' '.dolGetFirstLastname($obj->firstname,$obj->lastname); $event->percentage=100; $event->fulldayevent=true; diff --git a/htdocs/comm/admin/propal_extrafields.php b/htdocs/comm/admin/propal_extrafields.php new file mode 100755 index 00000000000..9993019775e --- /dev/null +++ b/htdocs/comm/admin/propal_extrafields.php @@ -0,0 +1,159 @@ + + * Copyright (C) 2003 Jean-Louis Bergamo + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2012 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 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/societe/admin/societe_extrafields.php + * \ingroup societe + * \brief Page to setup extra fields of third party + */ + +require '../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +$langs->load("companies"); +$langs->load("admin"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=getStaticMember(get_class($extrafields),'type2label'); +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='propal'; + +if (!$user->admin) accessforbidden(); + + +/* + * Actions + */ + +require DOL_DOCUMENT_ROOT.'/core/admin_extrafields.inc.php'; + + + +/* + * View + */ + +$textobject=$langs->transnoentitiesnoconv("Propales"); + + +llxHeader('',$langs->trans("PropalSetup")); + + +$linkback=''.$langs->trans("BackToModuleList").''; +print_fiche_titre($langs->trans("PropalSetup"),$linkback,'setup'); + + +$head = propal_admin_prepare_head(null); + +dol_fiche_head($head, 'attributes', $langs->trans("Propal"), 0, 'propal'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'
'."\n"; +print '
'; + +dol_htmloutput_errors($mesg); + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print ""; + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print ""; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print '\n"; + print '\n"; + print '\n"; + print '\n"; + print ""; + // $i++; +} + +print "
'.$langs->trans("Position").''.$langs->trans("Label").''.$langs->trans("AttributeCode").''.$langs->trans("Type").''.$langs->trans("Size").''.$langs->trans("Unique").''.$langs->trans("Required").' 
".$extrafields->attribute_pos[$key]."".$extrafields->attribute_label[$key]."".$key."".$type2label[$extrafields->attribute_type[$key]]."'.$extrafields->attribute_size[$key]."'.yn($extrafields->attribute_unique[$key])."'.yn($extrafields->attribute_required[$key])."'.img_edit().''; + print "  ".img_delete()."
"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel + /* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); +?> diff --git a/htdocs/comm/mailing/fiche.php b/htdocs/comm/mailing/fiche.php index ef2655ad80c..4b886f2d24f 100644 --- a/htdocs/comm/mailing/fiche.php +++ b/htdocs/comm/mailing/fiche.php @@ -209,7 +209,7 @@ if ($action == 'sendallconfirmed' && $confirm == 'yes') $obj = $db->fetch_object($resql); // sendto en RFC2822 - $sendto = str_replace(',',' ',$obj->firstname." ".$obj->lastname)." <".$obj->email.">"; + $sendto = str_replace(',',' ',dolGetFirstLastname($obj->firstname, $obj->lastname))." <".$obj->email.">"; // Make substitutions on topic and body. From (AA=YY;BB=CC;...) we keep YY, CC, ... $other=explode(';',$obj->other); diff --git a/htdocs/comm/propal.php b/htdocs/comm/propal.php index 9b75519236e..e17940379bf 100644 --- a/htdocs/comm/propal.php +++ b/htdocs/comm/propal.php @@ -38,6 +38,7 @@ require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/modules/propale/modules_propale.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/propal.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; if (! empty($conf->projet->enabled)) { require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php'; @@ -78,6 +79,7 @@ if (! empty($user->societe_id)) $socid=$user->societe_id; $result = restrictedArea($user, 'propal', $id); $object = new Propal($db); +$extrafields = new ExtraFields($db); // Load object if ($id > 0 || ! empty($ref)) @@ -336,6 +338,15 @@ else if ($action == 'add' && $user->rights->propal->creer) } } + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } + $id = $object->create($user); } @@ -913,7 +924,7 @@ else if ($action == 'updateligne' && $user->rights->propal->creer && GETPOST('sa GETPOST('fk_parent_line'), 0, $fournprice, - $buying_price, + $buyingprice, $label, $type ); @@ -1094,6 +1105,35 @@ else if ($action == 'down' && $user->rights->propal->creer) header('Location: '.$_SERVER["PHP_SELF"].'?id='.$id.'#'.GETPOST('rowid')); exit; } +else if ($action == 'update_extras') +{ + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=$_POST[$key]; + } + } + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('propaldao')); + $parameters=array('id'=>$object->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + +} if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->propal->creer) { @@ -1168,6 +1208,9 @@ $formfile = new FormFile($db); $formpropal = new FormPropal($db); $companystatic=new Societe($db); +// fetch optionals attributes and labels +$extralabels=$extrafields->fetch_name_optionals_label('propal'); + $now=dol_now(); // Add new proposal @@ -1793,19 +1836,56 @@ else } // Other attributes + $res=$object->fetch_optionals($object->id,$extralabels); $parameters=array('colspan' => ' colspan="3"'); $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook if (empty($reshook) && ! empty($extrafields->attribute_label)) { + + if ($action == 'edit_extras') + { + print '
'; + print ''; + print ''; + print ''; + } + + foreach($extrafields->attribute_label as $key=>$label) { $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); print 'attribute_required[$key])) print ' class="fieldrequired"'; print '>'.$label.''; - print $extrafields->showInputField($key,$value); + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + print ''."\n"; } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print ''; + print ''; + print ''; + print ''; + + } + else { + if ($object->statut == 0 && $user->rights->propal->creer) + { + print ''.img_picto('','edit').' '.$langs->trans('Modify').''; + } + } + } } // Amount HT diff --git a/htdocs/comm/propal/class/propal.class.php b/htdocs/comm/propal/class/propal.class.php index 4b3686db511..66f6bb3874d 100644 --- a/htdocs/comm/propal/class/propal.class.php +++ b/htdocs/comm/propal/class/propal.class.php @@ -622,7 +622,7 @@ class Propal extends CommonObject */ function create($user='', $notrigger=0) { - global $langs,$conf,$mysoc; + global $langs,$conf,$mysoc,$hookmanager; $error=0; $now=dol_now(); @@ -802,6 +802,24 @@ class Propal extends CommonObject $resql=$this->update_price(1); if ($resql) { + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('propaldao')); + $parameters=array('socid'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + if (! $notrigger) { // Appel des triggers @@ -1149,6 +1167,20 @@ class Propal extends CommonObject return -1; } + // Retreive all extrafield for propal + // fetch optionals attributes and labels + if(!class_exists('Extrafields')) + require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label('propal',true); + //$this->fetch_optionals($this->id,$extralabels); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } return 1; } @@ -1162,6 +1194,44 @@ class Propal extends CommonObject return -1; } } + + /** + * Update value of extrafields on the proposal + * + * @param User $user Object user that modify + * @param double $remise Amount discount + * @return int <0 if ko, >0 if ok + */ + function update_extrafields($user) + { + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('propaldao')); + $parameters=array('id'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + + if (!$error) + { + return 1; + } + else + { + return -1; + } + + } /** * Set status to validated diff --git a/htdocs/compta/facture.php b/htdocs/compta/facture.php index 7585b71cf68..17947e6e3ed 100644 --- a/htdocs/compta/facture.php +++ b/htdocs/compta/facture.php @@ -7,6 +7,7 @@ * Copyright (C) 2006 Andre Cianfarani * Copyright (C) 2010-2013 Juanjo Menent * Copyright (C) 2012 Christophe Battarel + * Copyright (C) 2013 Jean-Francois FERRY * * 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 @@ -38,6 +39,7 @@ require DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; require DOL_DOCUMENT_ROOT . '/core/lib/invoice.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/functions2.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; +require DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php'; if (! empty($conf->commande->enabled)) { require DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php'; @@ -87,6 +89,7 @@ $NBLINES=4; $usehm=(! empty($conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE)?$conf->global->MAIN_USE_HOURMIN_IN_DATE_RANGE:0); $object=new Facture($db); +$extrafields = new ExtraFields($db); // Load object if ($id > 0 || ! empty($ref)) @@ -614,6 +617,15 @@ else if ($action == 'add' && $user->rights->facture->creer) $db->begin(); $error=0; + + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=GETPOST($key); + } + } // Replacement invoice if ($_POST['type'] == 1) @@ -1722,6 +1734,36 @@ if (! empty($conf->global->MAIN_DISABLE_CONTACTS_TAB) && $user->rights->facture- } } +if ($action == 'update_extras') +{ + // Get extra fields + foreach($_POST as $key => $value) + { + if (preg_match("/^options_/",$key)) + { + $object->array_options[$key]=$_POST[$key]; + } + } + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('invoicedao')); + $parameters=array('id'=>$object->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$object->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + +} + /* * View @@ -1744,6 +1786,7 @@ $now=dol_now(); if ($action == 'create') { $facturestatic=new Facture($db); + $extralabels=$extrafields->fetch_name_optionals_label('facture'); print_fiche_titre($langs->trans('NewBill')); @@ -2221,6 +2264,10 @@ else if ($id > 0 || ! empty($ref)) */ $result=$object->fetch($id,$ref); + + // fetch optionals attributes and labels + $extralabels=$extrafields->fetch_name_optionals_label('facture'); + if ($result > 0) { if ($user->societe_id>0 && $user->societe_id!=$object->socid) accessforbidden('',0); @@ -3029,21 +3076,58 @@ else if ($id > 0 || ! empty($ref)) print ''; print ''; } - + // Other attributes - $parameters=array('colspan' => ' colspan="3"'); - $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook + $res=$object->fetch_optionals($object->id,$extralabels); + $parameters=array('colspan' => ' colspan="2"'); + $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook if (empty($reshook) && ! empty($extrafields->attribute_label)) { - foreach($extrafields->attribute_label as $key=>$label) - { - $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); - print 'attribute_required[$key])) print ' class="fieldrequired"'; - print '>'.$label.''; - print $extrafields->showInputField($key,$value); - print ''."\n"; - } + + if ($action == 'edit_extras') + { + print '
'; + print ''; + print ''; + print ''; + } + + + foreach($extrafields->attribute_label as $key=>$label) + { + $value=(isset($_POST["options_".$key])?$_POST["options_".$key]:$object->array_options["options_".$key]); + print 'attribute_required[$key])) print ' class="fieldrequired"'; + print '>'.$label.''; + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print $extrafields->showInputField($key,$value); + } + else + { + print $extrafields->showOutputField($key,$value); + } + + print ''."\n"; + } + + if(count($extrafields->attribute_label) > 0) { + + if ($action == 'edit_extras' && $user->rights->propal->creer) + { + print ''; + print ''; + print ''; + print ''; + + } + else { + if ($object->statut == 0 && $user->rights->propal->creer) + { + print ''.img_picto('','edit').' '.$langs->trans('Modify').''; + } + } + } } print '
'; diff --git a/htdocs/compta/facture/admin/facture_cust_extrafields.php b/htdocs/compta/facture/admin/facture_cust_extrafields.php new file mode 100644 index 00000000000..d08d5fe0ba8 --- /dev/null +++ b/htdocs/compta/facture/admin/facture_cust_extrafields.php @@ -0,0 +1,160 @@ + +* Copyright (C) 2003 Jean-Louis Bergamo +* Copyright (C) 2004-2011 Laurent Destailleur +* Copyright (C) 2012 Regis Houssin +* Copyright (C) 2013 Jean-Francois FERRY +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +*/ + +/** +* \file htdocs/compta/facture/admin/facture_cust_extrafields.php +* \ingroup invoice +* \brief Page to setup extra fields of customer invoice +*/ + +require '../../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/invoice.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + +$langs->load("companies"); +$langs->load("admin"); +$langs->load("bills"); + +$extrafields = new ExtraFields($db); +$form = new Form($db); + +// List of supported format +$tmptype2label=getStaticMember(get_class($extrafields),'type2label'); +$type2label=array(''); +foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->trans($val); + +$action=GETPOST('action', 'alpha'); +$attrname=GETPOST('attrname', 'alpha'); +$elementtype='facture'; + +if (!$user->admin) accessforbidden(); + + +/* +* Actions +*/ + +require DOL_DOCUMENT_ROOT.'/core/admin_extrafields.inc.php'; + + + +/* +* View +*/ + +$textobject=strtolower($langs->transnoentitiesnoconv("BillsCustomers")); + + +llxHeader('',$langs->trans("BillsSetup")); + + +$linkback=''.$langs->trans("BackToModuleList").''; +print_fiche_titre($langs->trans("BillsSetup"),$linkback,'setup'); +print '
'; + +$head = invoice_admin_prepare_head(null); + +dol_fiche_head($head, 'attributes', $langs->trans("Invoices"), 0, 'invoice'); + + +print $langs->trans("DefineHereComplementaryAttributes",$textobject).'
'."\n"; + +dol_htmloutput_errors($mesg); + +// Load attribute_label +$extrafields->fetch_name_optionals_label($elementtype); + +print ""; + +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +$var=True; +foreach($extrafields->attribute_type as $key => $value) +{ + $var=!$var; + print ""; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + print '\n"; + print '\n"; + print '\n"; + print '\n"; + print ""; + // $i++; +} + +print "
'.$langs->trans("Position").''.$langs->trans("Label").''.$langs->trans("AttributeCode").''.$langs->trans("Type").''.$langs->trans("Size").''.$langs->trans("Unique").''.$langs->trans("Required").' 
".$extrafields->attribute_pos[$key]."".$extrafields->attribute_label[$key]."".$key."".$type2label[$extrafields->attribute_type[$key]]."'.$extrafields->attribute_size[$key]."'.yn($extrafields->attribute_unique[$key])."'.yn($extrafields->attribute_required[$key])."'.img_edit().''; + print "  ".img_delete()."
"; + +dol_fiche_end(); + + +// Buttons +if ($action != 'create' && $action != 'edit') +{ + print '
'; + print "".$langs->trans("NewAttribute").""; + print "
"; +} + + +/* ************************************************************************** */ +/* */ +/* Creation d'un champ optionnel +/* */ +/* ************************************************************************** */ + +if ($action == 'create') +{ + print "
"; + print_titre($langs->trans('NewAttribute')); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php'; +} + +/* ************************************************************************** */ +/* */ +/* Edition d'un champ optionnel */ +/* */ +/* ************************************************************************** */ +if ($action == 'edit' && ! empty($attrname)) +{ + print "
"; + print_titre($langs->trans("FieldEdition", $attrname)); + + require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php'; +} + +llxFooter(); + +$db->close(); +?> \ No newline at end of file diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index aba862202bf..ace5e15312c 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -136,7 +136,7 @@ class Facture extends CommonInvoice */ function create($user,$notrigger=0,$forceduedate=0) { - global $langs,$conf,$mysoc; + global $langs,$conf,$mysoc,$hookmanager; $error=0; // Clean parameters @@ -438,6 +438,24 @@ class Facture extends CommonInvoice $result=$this->update_price(1); if ($result > 0) { + // Actions on extra fields (by external module or standard code) + // FIXME le hook fait double emploi avec le trigger !! + $hookmanager->initHooks(array('invoicedao')); + $parameters=array('invoiceid'=>$this->id); + $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks + if (empty($reshook)) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result=$this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } + else if ($reshook < 0) $error++; + // Appel des triggers include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; $interface=new Interfaces($this->db); @@ -848,6 +866,20 @@ class Facture extends CommonInvoice $this->extraparams = (array) json_decode($obj->extraparams, true); if ($this->statut == 0) $this->brouillon = 1; + + // Retreive all extrafield for invoice + // fetch optionals attributes and labels + if(!class_exists('Extrafields')) + require_once(DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'); + $extrafields=new ExtraFields($this->db); + $extralabels=$extrafields->fetch_name_optionals_label('facture',true); + if (count($extralabels)>0) { + $this->array_options = array(); + } + foreach($extrafields->attribute_label as $key=>$label) + { + $this->array_options['options_'.$key]=$label; + } /* * Lines diff --git a/htdocs/compta/facture/class/facturestats.class.php b/htdocs/compta/facture/class/facturestats.class.php index abc01288373..f99b8f3bb27 100644 --- a/htdocs/compta/facture/class/facturestats.class.php +++ b/htdocs/compta/facture/class/facturestats.class.php @@ -56,7 +56,7 @@ class FactureStats extends Stats global $conf; $this->db = $db; - $this->socid = $socid; + $this->socid = ($socid > 0 ? $socid : 0); $this->userid = $userid; if ($mode == 'customer') diff --git a/htdocs/compta/facture/stats/index.php b/htdocs/compta/facture/stats/index.php index 968be79feb7..7fc43f1edfe 100644 --- a/htdocs/compta/facture/stats/index.php +++ b/htdocs/compta/facture/stats/index.php @@ -34,8 +34,8 @@ $mode=GETPOST("mode")?GETPOST("mode"):'customer'; if ($mode == 'customer' && ! $user->rights->facture->lire) accessforbidden(); if ($mode == 'supplier' && ! $user->rights->fournisseur->facture->lire) accessforbidden(); -$userid=GETPOST('userid','int'); if ($userid < 0) $userid=0; -$socid=GETPOST('socid','int'); if ($socid < 0) $socid=0; +$userid=GETPOST('userid','int'); +$socid=GETPOST('socid','int'); // Security check if ($user->societe_id > 0) { diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 0c0c55ebf57..4c044314c63 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -540,7 +540,7 @@ class BonPrelevement extends CommonObject $this->method_trans = $method; $langs->load('withdrawals'); $subject = $langs->trans("InfoTransSubject", $this->ref); - $message = $langs->trans("InfoTransMessage", $this->ref, $user->firstname, $user->lastname); + $message = $langs->trans("InfoTransMessage", $this->ref, dolGetFirstLastname($user->firstname, $user->lastname)); $message .=$langs->trans("InfoTransData", price($this->amount), $this->methodes_trans[$this->method_trans], dol_print_date($date,'day')); // TODO Call trigger to create a notification using notification module diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 4f0a029993f..faccaa31545 100755 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -161,18 +161,18 @@ abstract class CommonDocGenerator 'company_idprof4'=>$object->idprof4, 'company_idprof5'=>$object->idprof5, 'company_idprof6'=>$object->idprof6, - 'company_note'=>$object->note + 'company_note'=>$object->note ); // Retrieve extrafields if(is_array($object->array_options) && count($object->array_options)) { - if(!class_exists('Extrafields')) + if(!class_exists('Extrafields')) require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; $extrafields = new ExtraFields($this->db); $extralabels = $extrafields->fetch_name_optionals_label('company',true); $object->fetch_optionals($object->id,$extralabels); - + foreach($extrafields->attribute_label as $key=>$label) { if($extrafields->attribute_type[$key] == 'price') @@ -180,7 +180,7 @@ abstract class CommonDocGenerator $object->array_options['options_'.$key] = price($object->array_options['options_'.$key]).' '.$outputlangs->getCurrencySymbol($conf->currency); } else if($extrafields->attribute_type[$key] == 'select') - { + { $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; } $array_thirdparty=array_merge($array_thirdparty,array('company_options_'.$key => $object->array_options['options_'.$key])); @@ -189,6 +189,134 @@ abstract class CommonDocGenerator return $array_thirdparty; } + + /** + * Define array with couple substitution key => substitution value + * + * @param Object $object Main object to use as data source + * @param Translate $outputlangs Lang object to use for output + * @param array_key $array_key Name of the key for return array + * @return array Array of substitution + */ + function get_substitutionarray_propal($object,$outputlangs,$array_key='object') + { + global $conf; + + $array_propal=array( + $array_key.'_id'=>$object->id, + $array_key.'_ref'=>$object->ref, + $array_key.'_ref_ext'=>$object->ref_ext, + $array_key.'_ref_customer'=>$object->ref_client, + $array_key.'_date'=>dol_print_date($object->date,'day'), + $array_key.'_date_end'=>dol_print_date($object->fin_validite,'day'), + $array_key.'_date_creation'=>dol_print_date($object->date_creation,'day'), + $array_key.'_date_modification'=>dol_print_date($object->date_modification,'day'), + $array_key.'_date_validation'=>dol_print_date($object->date_validation,'dayhour'), + $array_key.'_payment_mode_code'=>$object->mode_reglement_code, + $array_key.'_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), + $array_key.'_payment_term_code'=>$object->cond_reglement_code, + $array_key.'_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), + $array_key.'_total_ht'=>price2num($object->total_ht2,2), + $array_key.'_total_vat'=>price2num($object->total_tva,2), + $array_key.'_total_ttc'=>price2num($object->total_ttc,2), + $array_key.'_total_discount_ht' => price2num($object->getTotalDiscount(),2), + $array_key.'_vatrate'=>vatrate($object->tva), + $array_key.'_note_private'=>$object->note, + $array_key.'_note'=>$object->note_public, + ); + + // Add vat by rates + foreach ($object->lines as $line) + { + if (empty($array_propal[$array_key.'_total_vat_'.$line->tva_tx])) $array_propal[$array_key.'_total_vat_'.$line->tva_tx]=0; + $array_propal[$array_key.'_total_vat_'.$line->tva_tx]+=$line->total_tva; + } + + // Retrieve extrafields + if(is_array($object->array_options) && count($object->array_options)) + { + if(!class_exists('Extrafields')) + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label('propal',true); + $object->fetch_optionals($object->id,$extralabels); + + $array_propal = $this->fill_substitutionarray_with_extrafields($object,$array_propal,$extrafields,$array_key,$outputlangs); + } + return $array_propal; + } + + + /** + * Define array with couple substitution key => substitution value + * + * @param array $line Array of lines + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + function get_substitutionarray_propal_lines($line,$outputlangs) + { + global $conf; + + return array( + 'line_fulldesc'=>doc_getlinedesc($line,$outputlangs), + 'line_product_ref'=>$line->product_ref, + 'line_product_label'=>$line->product_label, + 'line_desc'=>$line->desc, + 'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits), + 'line_up'=>price2num($line->subprice, 2), + 'line_qty'=>$line->qty, + 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), + 'line_price_ht'=>price2num($line->total_ht,2), + 'line_price_ttc'=>price2num($line->total_ttc,2), + 'line_price_vat'=>price2num($line->total_tva,2), + 'line_date_start'=>$line->date_start, + 'line_date_end'=>$line->date_end + ); + } + + /** + * Fill array with couple extrafield key => extrafield value + * + * @param Object $object Object with extrafields (must have $object->array_options filled) + * @param array $array_to_fill Substitution array + * @param Extrafields $extrafields Extrafields object + * @param array_key $array_key Name of the key for return array + * @param Translate $outputlangs Lang object to use for output + * @return array Substitution array + */ + function fill_substitutionarray_with_extrafields($object,$array_to_fill,$extrafields,$array_key,$outputlangs) + { + global $conf; + foreach($extrafields->attribute_label as $key=>$label) + { + if($extrafields->attribute_type[$key] == 'price') + { + $object->array_options['options_'.$key] = price2num($object->array_options['options_'.$key],2); + $object->array_options['options_'.$key.'_currency'] = $object->array_options['options_'.$key].' '.$outputlangs->getCurrencySymbol($conf->currency); + //Add value to store price with currency + $array_to_fill=array_merge($array_to_fill,array($array_key.'_options_'.$key.'_currency' => $object->array_options['options_'.$key.'_currency'])); + } + else if($extrafields->attribute_type[$key] == 'select') + { + $object->array_options['options_'.$key] = $extrafields->attribute_param[$key]['options'][$object->array_options['options_'.$key]]; + } + else if($extrafields->attribute_type[$key] == 'date') + { + $object->array_options['options_'.$key] = (strlen($object->array_options['options_'.$key])>0?dol_print_date($object->array_options['options_'.$key],'day'):''); + } + else if($extrafields->attribute_type[$key] == 'datetime') + { + $object->array_options['options_'.$key] = ($object->array_options['options_'.$key]!="0000-00-00 00:00:00"?dol_print_date($object->array_options['options_'.$key],'dayhour'):''); + } + $array_to_fill=array_merge($array_to_fill,array($array_key.'_options_'.$key => $object->array_options['options_'.$key])); + } + + return $array_to_fill; + + } + + /** * Rect pdf * diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 58655666755..50bd564e8d9 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -73,21 +73,8 @@ abstract class CommonObject else $ret.=$this->civilite_id.' '; } - // If order not defined, we use the setup - if ($nameorder < 0) $nameorder=(empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)); + $ret.=dolGetFirstLastname($firstname, $lastname, $nameorder); - if ($nameorder) - { - $ret.=$firstname; - if ($firstname && $lastname) $ret.=' '; - $ret.=$lastname; - } - else - { - $ret.=$lastname; - if ($firstname && $lastname) $ret.=' '; - $ret.=$firstname; - } return dol_trunc($ret,$maxlen); } diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index f72ddc8d6e2..de828e8a237 100755 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -651,9 +651,11 @@ class ExtraFields elseif ($type == 'select') { $out=''; } diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index eb34a3913ce..9e8a47812fd 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -194,7 +194,7 @@ class FormFile * @param boolean $printer Printer Icon * @return string Output string with HTML array of documents (might be empty string) */ - function showdocuments($modulepart,$filename,$filedir,$urlsource,$genallowed,$delallowed=0,$modelselected='',$allowgenifempty=1,$forcenomultilang=0,$iconPDF=0,$maxfilenamelength=28,$noform=0,$param='',$title='',$buttonlabel='',$codelang='',$printer) + function showdocuments($modulepart,$filename,$filedir,$urlsource,$genallowed,$delallowed=0,$modelselected='',$allowgenifempty=1,$forcenomultilang=0,$iconPDF=0,$maxfilenamelength=28,$noform=0,$param='',$title='',$buttonlabel='',$codelang='',$printer=false) { // filedir = conf->...dir_ouput."/".get_exdir(id) include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 817396f97fc..3acf7983fe3 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -3643,13 +3643,29 @@ function get_date_range($date_start,$date_end,$format = '',$outputlangs='') * * @param string $firstname Firstname * @param string $lastname Lastname + * @param int $nameorder -1=Auto, 0=Lastname+Firstname, 1=Firstname+Lastname * @return string Firstname + lastname or Lastname + firstname */ -function dolGetFirstLastname($firstname,$lastname) +function dolGetFirstLastname($firstname,$lastname,$nameorder=-1) { global $conf; - if (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)) return $firstname.' '.$lastname; - else return $lastname.' '.$firstname; + + $ret=''; + // If order not defined, we use the setup + if ($nameorder < 0) $nameorder=(empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION)); + if ($nameorder) + { + $ret.=$firstname; + if ($firstname && $lastname) $ret.=' '; + $ret.=$lastname; + } + else + { + $ret.=$lastname; + if ($firstname && $lastname) $ret.=' '; + $ret.=$firstname; + } + return $ret; } diff --git a/htdocs/core/lib/invoice.lib.php b/htdocs/core/lib/invoice.lib.php index e70f215df2d..03b8fa7240d 100644 --- a/htdocs/core/lib/invoice.lib.php +++ b/htdocs/core/lib/invoice.lib.php @@ -98,4 +98,42 @@ function facture_prepare_head($object) return $head; } +/** + * Return array head with list of tabs to view object informations. + * + * @param Object $object Invoice + * @return array head array with tabs + */ +function invoice_admin_prepare_head($object) +{ + global $langs, $conf, $user; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/admin/facture.php'; + $head[$h][1] = $langs->trans("Miscellanous"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf,$langs,$object,$head,$h,'invoice_admin'); + + $head[$h][0] = DOL_URL_ROOT.'/compta/facture/admin/facture_cust_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFieldsCustomerInvoices"); + $head[$h][2] = 'attributes'; + $h++; + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'invoice_admin','remove'); + + return $head; +} + + + ?> \ No newline at end of file diff --git a/htdocs/core/lib/propal.lib.php b/htdocs/core/lib/propal.lib.php index 92eb5e27459..d6348bdcb0e 100644 --- a/htdocs/core/lib/propal.lib.php +++ b/htdocs/core/lib/propal.lib.php @@ -103,5 +103,41 @@ function propal_prepare_head($object) return $head; } +/** + * Return array head with list of tabs to view object informations. + * + * @param Object $object Propal + * @return array head array with tabs + */ +function propal_admin_prepare_head($object) +{ + global $langs, $conf, $user; + + $h = 0; + $head = array(); + + $head[$h][0] = DOL_URL_ROOT.'/admin/propal.php'; + $head[$h][1] = $langs->trans("Miscellanous"); + $head[$h][2] = 'general'; + $h++; + + // Show more tabs from modules + // Entries must be declared in modules descriptor with line + // $this->tabs = array('entity:+tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to add new tab + // $this->tabs = array('entity:-tabname:Title:@mymodule:/mymodule/mypage.php?id=__ID__'); to remove a tab + complete_head_from_modules($conf,$langs,$object,$head,$h,'propal_admin'); + + $head[$h][0] = DOL_URL_ROOT.'/comm/admin/propal_extrafields.php'; + $head[$h][1] = $langs->trans("ExtraFields"); + $head[$h][2] = 'attributes'; + $h++; + + + + complete_head_from_modules($conf,$langs,$object,$head,$h,'propal_admin','remove'); + + return $head; +} + ?> \ No newline at end of file diff --git a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php index dc00f4370fa..957b5d85428 100644 --- a/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php +++ b/htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php @@ -121,16 +121,16 @@ class doc_generic_invoice_odt extends ModelePDFFactures 'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement), 'object_payment_term_code'=>$object->cond_reglement_code, 'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement), - 'object_total_ht'=>price($object->total_ht,0,$outputlangs), - 'object_total_vat'=>price($object->total_tva,0,$outputlangs), - 'object_total_ttc'=>price($object->total_ttc,0,$outputlangs), - 'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs), + 'object_total_ht'=>price2num($object->total_ht,2), + 'object_total_vat'=>price2num($object->total_tva,2), + 'object_total_ttc'=>price2num($object->total_ttc,2), + 'object_total_discount_ht' => price2num($object->getTotalDiscount(), 0, $outputlangs), 'object_vatrate'=>(isset($object->tva)?vatrate($object->tva):''), 'object_note_private'=>$object->note, 'object_note'=>$object->note_public, // Payments 'object_already_payed'=>$alreadypayed, - 'object_remain_to_pay'=>price($object->total_ttc - $sumpayed,0,$outputlangs) + 'object_remain_to_pay'=>price2num($object->total_ttc - $sumpayed,2) ); // Add vat by rates @@ -140,6 +140,17 @@ class doc_generic_invoice_odt extends ModelePDFFactures $resarray['object_total_vat_'.$line->tva_tx]+=$line->total_tva; } + // Retrieve extrafields + if(is_array($object->array_options) && count($object->array_options)) + { + if(!class_exists('Extrafields')) + require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; + $extrafields = new ExtraFields($this->db); + $extralabels = $extrafields->fetch_name_optionals_label('facture',true); + $object->fetch_optionals($object->id,$extralabels); + + $resarray = $this->fill_substitutionarray_with_extrafields($object,$resarray,$extrafields,$array_key='object',$outputlangs); + } return $resarray; } @@ -163,9 +174,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures 'line_up'=>price($line->subprice, 0, $outputlangs), 'line_qty'=>$line->qty, 'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''), - 'line_price_ht'=>price($line->total_ht, 0, $outputlangs), - 'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs), - 'line_price_vat'=>price($line->total_tva, 0, $outputlangs), + 'line_price_ht'=>price2num($line->total_ht, 2), + 'line_price_ttc'=>price2num($line->total_ttc, 2), + 'line_price_vat'=>price2num($line->total_tva, 2), 'line_date_start'=>dol_print_date($line->date_start, 'day', false, $outputlangs), 'line_date_end'=>dol_print_date($line->date_end, 'day', false, $outputlangs), ); @@ -347,7 +358,14 @@ class doc_generic_invoice_odt extends ModelePDFFactures { $socobject=$object->client; } + + // Fetch info for linked propal + $linked_propal = $object->fetchObjectLinked('','','',''); + print '
';
+                //print_r($object->linkedObjects['propal']); exit;
 
+                $propal_object = $object->linkedObjects['propal'][0];
+                
                 // Make substitution
                 $substitutionarray=array(
                     '__FROM_NAME__' => $this->emetteur->nom,
@@ -397,8 +415,9 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 				$array_soc=$this->get_substitutionarray_mysoc($mysoc,$outputlangs);
 				$array_thirdparty=$this->get_substitutionarray_thirdparty($socobject,$outputlangs);
 				$array_objet=$this->get_substitutionarray_object($object,$outputlangs);
+				$array_propal=$this->get_substitutionarray_propal($propal_object,$outputlangs,'propal');
 
-				$tmparray = array_merge($array_user,$array_soc,$array_thirdparty,$array_objet);
+				$tmparray = array_merge($array_user,$array_soc,$array_thirdparty,$array_objet,$array_propal);
 				complete_substitutions_array($tmparray, $outputlangs, $object);
 
                 //var_dump($tmparray); exit;
diff --git a/htdocs/core/modules/modBanque.class.php b/htdocs/core/modules/modBanque.class.php
index ba00c90faca..1bae9f61129 100644
--- a/htdocs/core/modules/modBanque.class.php
+++ b/htdocs/core/modules/modBanque.class.php
@@ -159,7 +159,7 @@ class modBanque extends DolibarrModules
 		$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON bu.url_id = s.rowid';
 		$this->export_sql_end[$r] .=' WHERE ba.rowid = b.fk_account';
 		$this->export_sql_end[$r] .=' AND ba.entity = '.$conf->entity;
-		$this->export_sql_end[$r] .=' ORDER BY b.datev, b.num_releve';
+		$this->export_sql_order[$r] .=' ORDER BY b.datev, b.num_releve';
 	}
 
 
diff --git a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php
index e6103f5a802..0f9e64c1fe2 100644
--- a/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php
+++ b/htdocs/core/modules/propale/doc/doc_generic_proposal_odt.modules.php
@@ -86,78 +86,6 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 	}
 
 
-    /**
-     * Define array with couple substitution key => substitution value
-     *
-     * @param   Object			$object             Main object to use as data source
-     * @param   Translate		$outputlangs        Lang object to use for output
-     * @return	array								Array of substitution
-     */
-    function get_substitutionarray_object($object,$outputlangs)
-    {
-        global $conf;
-
-        $resarray=array(
-            'object_id'=>$object->id,
-            'object_ref'=>$object->ref,
-            'object_ref_ext'=>$object->ref_ext,
-        	'object_ref_customer'=>$object->ref_client,
-        	'object_date'=>dol_print_date($object->date,'day'),
-        	'object_date_end'=>dol_print_date($object->fin_validite,'day'),
-        	'object_date_creation'=>dol_print_date($object->date_creation,'day'),
-            'object_date_modification'=>dol_print_date($object->date_modification,'day'),
-            'object_date_validation'=>dol_print_date($object->date_validation,'dayhour'),
-            'object_payment_mode_code'=>$object->mode_reglement_code,
-        	'object_payment_mode'=>($outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code)!='PaymentType'.$object->mode_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentType'.$object->mode_reglement_code):$object->mode_reglement),
-        	'object_payment_term_code'=>$object->cond_reglement_code,
-        	'object_payment_term'=>($outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code)!='PaymentCondition'.$object->cond_reglement_code?$outputlangs->transnoentitiesnoconv('PaymentCondition'.$object->cond_reglement_code):$object->cond_reglement),
-        	'object_total_ht'=>price($object->total_ht,0,$outputlangs),
-            'object_total_vat'=>price($object->total_tva,0,$outputlangs),
-            'object_total_ttc'=>price($object->total_ttc,0,$outputlangs),
-            'object_total_discount_ht' => price($object->getTotalDiscount(), 0, $outputlangs),
-            'object_vatrate'=>vatrate($object->tva),
-            'object_note_private'=>$object->note,
-            'object_note'=>$object->note_public,
-        );
-        
-        // Add vat by rates
-        foreach ($object->lines as $line)
-        {
-        	if (empty($resarray['object_total_vat_'.$line->tva_tx])) $resarray['object_total_vat_'.$line->tva_tx]=0;
-        	$resarray['object_total_vat_'.$line->tva_tx]+=$line->total_tva;
-        }
-        
-        return $resarray;
-    }
-
-    /**
-     *	Define array with couple substitution key => substitution value
-     *
-     *	@param  array			$line				Array of lines
-     *	@param  Translate		$outputlangs        Lang object to use for output
-     *	@return	array								Substitution array
-     */
-    function get_substitutionarray_lines($line,$outputlangs)
-    {
-        global $conf;
-
-        return array(
-            'line_fulldesc'=>doc_getlinedesc($line,$outputlangs),
-            'line_product_ref'=>$line->product_ref,
-            'line_product_label'=>$line->product_label,
-            'line_desc'=>$line->desc,
-            'line_vatrate'=>vatrate($line->tva_tx,true,$line->info_bits),
-            'line_up'=>price($line->subprice, 0, $outputlangs),
-            'line_qty'=>$line->qty,
-            'line_discount_percent'=>($line->remise_percent?$line->remise_percent.'%':''),
-            'line_price_ht'=>price($line->total_ht, 0, $outputlangs),
-            'line_price_ttc'=>price($line->total_ttc, 0, $outputlangs),
-            'line_price_vat'=>price($line->total_tva, 0, $outputlangs),
-            'line_date_start'=>$line->date_start,
-            'line_date_end'=>$line->date_end
-        );
-    }
-
 	/**
 	 *	Return description of a module
 	 *
@@ -441,7 +369,8 @@ class doc_generic_proposal_odt extends ModelePDFPropales
 					}
 				}
 				// Replace tags of object + external modules
-			    $tmparray=$this->get_substitutionarray_object($object,$outputlangs);
+			    $tmparray=$this->get_substitutionarray_propal($object,$outputlangs);
+			    //print_r($tmparray); exit;
 			    complete_substitutions_array($tmparray, $outputlangs, $object);
                 foreach($tmparray as $key=>$value)
                 {
@@ -466,7 +395,7 @@ class doc_generic_proposal_odt extends ModelePDFPropales
                     $listlines = $odfHandler->setSegment('lines');
                     foreach ($object->lines as $line)
                     {
-                        $tmparray=$this->get_substitutionarray_lines($line,$outputlangs);
+                        $tmparray=$this->get_substitutionarray_propal_lines($line,$outputlangs);
                         complete_substitutions_array($tmparray, $outputlangs, $object, $line, "completesubstitutionarray_lines");
                         foreach($tmparray as $key => $val)
                         {
diff --git a/htdocs/exports/class/export.class.php b/htdocs/exports/class/export.class.php
index 6a51380e8a1..f850c20d07f 100644
--- a/htdocs/exports/class/export.class.php
+++ b/htdocs/exports/class/export.class.php
@@ -34,7 +34,9 @@ class Export
 	var $array_export_code=array();             // Tableau de "idmodule_numlot"
 	var $array_export_module=array();           // Tableau de "nom de modules"
 	var $array_export_label=array();            // Tableau de "libelle de lots"
-	var $array_export_sql=array();              // Tableau des "requetes sql"
+	var $array_export_sql_start=array();        // Tableau des "requetes sql"
+	var $array_export_sql_end=array();          // Tableau des "requetes sql"
+	var $array_export_sql_order=array();        // Tableau des "requetes sql"
 	var $array_export_fields=array();           // Tableau des listes de champ+libelle a exporter
 	var $array_export_TypeFields=array();		// Tableau des listes de champ+Type de filtre
 	var $array_export_FilterValue=array();		// Tableau des listes de champ+Valeur a filtrer
@@ -177,6 +179,7 @@ class Export
 									// Requete sql du dataset
 									$this->array_export_sql_start[$i]=$module->export_sql_start[$r];
 									$this->array_export_sql_end[$i]=$module->export_sql_end[$r];
+									$this->array_export_sql_order[$i]=$module->export_sql_order[$r];
 									//$this->array_export_sql[$i]=$module->export_sql[$r];
 
 									dol_syslog(get_class($this)."::load_arrays loaded for module ".$modulename." with index ".$i.", dataset=".$module->export_code[$r].", nb of fields=".(! empty($module->export_fields_code[$r])?count($module->export_fields_code[$r]):''));
@@ -234,7 +237,8 @@ class Export
 			}
 			$sql.=$sqlWhere;
 		}
-
+		$sql.=$this->array_export_sql_order[$indice];
+		
 		return $sql;
 	}
 
diff --git a/htdocs/holiday/fiche.php b/htdocs/holiday/fiche.php
index 8602163b583..518a83908c4 100644
--- a/htdocs/holiday/fiche.php
+++ b/htdocs/holiday/fiche.php
@@ -319,7 +319,7 @@ if ($action == 'confirm_send')
             }
 
             $message.= "\n";
-            $message.= "- ".$langs->transnoentitiesnoconv("Name")." : ".$expediteur->firstname." ".$expediteur->lastname."\n";
+            $message.= "- ".$langs->transnoentitiesnoconv("Name")." : ".dolGetFirstLastname($expediteur->firstname, $expediteur->lastname)."\n";
             $message.= "- ".$langs->transnoentitiesnoconv("Period")." : ".dol_print_date($cp->date_debut,'day')." ".$langs->transnoentitiesnoconv("To")." ".dol_print_date($cp->date_fin,'day')."\n";
             $message.= "- ".$langs->transnoentitiesnoconv("Link")." : ".$dolibarr_main_url_root."/holiday/fiche.php?id=".$cp->rowid."\n\n";
             $message.= "\n";
@@ -400,7 +400,7 @@ if($action == 'confirm_valid')
             $message = $langs->transnoentitiesnoconv("Hello")." ".$destinataire->firstname.",\n";
             $message.= "\n";
             $message.= "Votre demande de congés payés du ".dol_print_date($cp->date_debut,'day')." au ".dol_print_date($cp->date_fin,'day')." vient d'être validée!\n";
-            $message.= "- ".$langs->transnoentitiesnoconv("ValidatedBy")." : ".$expediteur->firstname." ".$expediteur->lastname."\n";
+            $message.= "- ".$langs->transnoentitiesnoconv("ValidatedBy")." : ".dolGetFirstLastname($expediteur->firstname, $expediteur->lastname)."\n";
             $message.= "- ".$langs->transnoentitiesnoconv("Link")." : ".$dolibarr_main_url_root."/holiday/fiche.php?id=".$cp->rowid."\n\n";
             $message.= "\n";
 
@@ -469,7 +469,7 @@ if ($action == 'confirm_refuse')
 	            $message.= "\n";
                 $message.= "Votre demande de congés payés ".dol_print_date($cp->date_debut,'day')." ".$langs->transnoentitiesnoconv("To")." ".dol_print_date($cp->date_fin,'day')." vient d'être refusée pour le motif suivant :\n";
                 $message.= $_POST['detail_refuse']."\n\n";
-	            $message.= "- ".$langs->transnoentitiesnoconv("ModifiedBy")." : ".$expediteur->firstname." ".$expediteur->lastname."\n";
+	            $message.= "- ".$langs->transnoentitiesnoconv("ModifiedBy")." : ".dolGetFirstLastname($expediteur->firstname, $expediteur->lastname)."\n";
     	        $message.= "- ".$langs->transnoentitiesnoconv("Link")." : ".$dolibarr_main_url_root."/holiday/fiche.php?id=".$cp->rowid."\n\n";
                 $message.= "\n";
 
@@ -539,7 +539,7 @@ if ($action == 'confirm_cancel' && $_GET['confirm'] == 'yes')
            	$message = $langs->transnoentitiesnoconv("Hello")." ".$destinataire->firstname.",\n";
             $message.= "\n";
             $message.= "Votre demande de congés ".dol_print_date($cp->date_debut,'day')." ".$langs->transnoentitiesnoconv("To")." ".dol_print_date($cp->date_fin,'day')." va été annulée.\n";
-            $message.= "- ".$langs->transnoentitiesnoconv("ModifiedBy")." : ".$expediteur->firstname." ".$expediteur->lastname."\n";
+            $message.= "- ".$langs->transnoentitiesnoconv("ModifiedBy")." : ".dolGetFirstLastname($expediteur->firstname, $expediteur->lastname)."\n";
    	        $message.= "- ".$langs->transnoentitiesnoconv("Link")." : ".$dolibarr_main_url_root."/holiday/fiche.php?id=".$cp->rowid."\n\n";
             $message.= "\n";
 
diff --git a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql
index 1e5cb707753..df178f1ccab 100755
--- a/htdocs/install/mysql/migration/3.3.0-3.4.0.sql
+++ b/htdocs/install/mysql/migration/3.3.0-3.4.0.sql
@@ -89,6 +89,23 @@ ALTER TABLE llx_c_shipment_mode CHANGE COLUMN rowid rowid INTEGER NOT NULL;
 
 ALTER TABLE llx_stock_mouvement MODIFY COLUMN value real;
 
+create table llx_propal_extrafields
+(
+  rowid                     integer AUTO_INCREMENT PRIMARY KEY,
+  tms                       timestamp,
+  fk_object                 integer NOT NULL,
+  import_key                varchar(14)                          		-- import key
+) ENGINE=innodb;
+ALTER TABLE llx_propal_extrafields ADD INDEX idx_propal_extrafields (fk_object);
+
+create table llx_facture_extrafields
+(
+  rowid integer AUTO_INCREMENT PRIMARY KEY,
+  tms timestamp,
+  fk_object integer NOT NULL,
+  import_key varchar(14) -- import key
+) ENGINE=innodb;
+ALTER TABLE llx_facture_extrafields ADD INDEX idx_facture_extrafields (fk_object);
 ALTER TABLE llx_facture ADD COLUMN revenuestamp double(24,8) DEFAULT 0 AFTER localtax2;
 
 CREATE TABLE llx_c_revenuestamp
diff --git a/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql b/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql
new file mode 100755
index 00000000000..e44905ccc2e
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_facture_extrafields.key.sql
@@ -0,0 +1,20 @@
+-- ===================================================================
+-- Copyright (C) 2013 Jean-Francois FERRY	
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ===================================================================
+
+
+ALTER TABLE llx_facture_extrafields ADD INDEX idx_facture_extrafields (fk_object);
diff --git a/htdocs/install/mysql/tables/llx_facture_extrafields.sql b/htdocs/install/mysql/tables/llx_facture_extrafields.sql
new file mode 100755
index 00000000000..9ef15f4e012
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_facture_extrafields.sql
@@ -0,0 +1,26 @@
+-- ========================================================================
+-- Copyright (C) 2013 Jean-Francois FERRY	
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ========================================================================
+
+create table llx_facture_extrafields
+(
+  rowid                     integer AUTO_INCREMENT PRIMARY KEY,
+  tms                       timestamp,
+  fk_object                 integer NOT NULL,
+  import_key                varchar(14)                          		-- import key
+) ENGINE=innodb;
+
diff --git a/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql b/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql
new file mode 100755
index 00000000000..5c9cc922667
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_propal_extrafields.key.sql
@@ -0,0 +1,20 @@
+-- ===================================================================
+-- Copyright (C) 2011 Laurent Destailleur	
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ===================================================================
+
+
+ALTER TABLE llx_propal_extrafields ADD INDEX idx_propal_extrafields (fk_object);
diff --git a/htdocs/install/mysql/tables/llx_propal_extrafields.sql b/htdocs/install/mysql/tables/llx_propal_extrafields.sql
new file mode 100755
index 00000000000..c285df56dd7
--- /dev/null
+++ b/htdocs/install/mysql/tables/llx_propal_extrafields.sql
@@ -0,0 +1,26 @@
+-- ========================================================================
+-- Copyright (C) 2011 Laurent Destailleur  
+--
+-- This program is free software; you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation; either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program. If not, see .
+--
+-- ========================================================================
+
+create table llx_propal_extrafields
+(
+  rowid                     integer AUTO_INCREMENT PRIMARY KEY,
+  tms                       timestamp,
+  fk_object                 integer NOT NULL,
+  import_key                varchar(14)                          		-- import key
+) ENGINE=innodb;
+
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index e2048918de6..382db000796 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -931,7 +931,7 @@ MAIN_PROXY_HOST=Name/Address of proxy server
 MAIN_PROXY_PORT=Port of proxy server
 MAIN_PROXY_USER=Login to use the proxy server
 MAIN_PROXY_PASS=Password to use the proxy server
-DefineHereComplementaryAttributes=Define here all atributes, not already available by default, and that you want to be supported for %s.
+DefineHereComplementaryAttributes=Define here all attributes, not already available by default, and that you want to be supported for %s.
 ExtraFields=Complementary attributes
 ExtraFieldsThirdParties=Complementary attributes (thirdparty)
 ExtraFieldsContacts=Complementary attributes (contact/address)
@@ -977,7 +977,7 @@ NotificationsDesc=EMails notifications feature allows you to silently send autom
 ModelModules=Documents templates
 DocumentModelOdt=Generate documents from OpenDocuments templates (.ODT files for OpenOffice, KOffice, TextEdit,...)
 WatermarkOnDraft=Watermark on draft document
-CompanyIdProfChecker=Rules ono Professional Ids
+CompanyIdProfChecker=Rules on Professional Ids
 MustBeUnique=Must be unique ?
 MustBeMandatory=Must be mandatory to create thirds?
 MustBeInvoiceMandatory=Must be mandatory to validate invoices?
@@ -1199,7 +1199,7 @@ LDAPDescUsers=This page allows you to define LDAP attributes name in LDAP tree f
 LDAPDescGroups=This page allows you to define LDAP attributes name in LDAP tree for each data found on Dolibarr groups.
 LDAPDescMembers=This page allows you to define LDAP attributes name in LDAP tree for each data found on Dolibarr members module.
 LDAPDescValues=Example values are designed for OpenLDAP with following loaded schemas: core.schema, cosine.schema, inetorgperson.schema). If you use thoose values and OpenLDAP, modify your LDAP config file slapd.conf to have all thoose schemas loaded.
-ForANonAnonymousAccess=For an authenticated acces (for a write access for example)
+ForANonAnonymousAccess=For an authenticated access (for a write access for example)
 ##### Products #####
 ProductSetup=Products module setup
 ServiceSetup=Services module setup
@@ -1209,7 +1209,7 @@ ConfirmDeleteProductLineAbility=Confirmation when removing product lines in form
 ModifyProductDescAbility=Personalization of product descriptions in forms
 ViewProductDescInFormAbility=Visualization of product descriptions in the forms (otherwise as popup tooltip)
 ViewProductDescInThirdpartyLanguageAbility=Visualization of products descriptions in the thirdparty language
-UseSearchToSelectProduct=Use a search form to choose a product (instead of using a list box).
Also if you have a large number of product (> 100 000), you can increase speed by setting constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 in Setup->Other. Search will then be limited to start of string. +UseSearchToSelectProduct=Use a search form to choose a product (rather than a drop-down list).
Also if you have a large number of product (> 100 000), you can increase speed by setting constant PRODUCT_DONOTSEARCH_ANYWHERE to 1 in Setup->Other. Search will then be limited to start of string. UseEcoTaxeAbility=Support Eco-Taxe (WEEE) SetDefaultBarcodeTypeProducts=Default barcode type to use for products SetDefaultBarcodeTypeThirdParties=Default barcode type to use for third parties diff --git a/htdocs/langs/fr_FR/admin.lang b/htdocs/langs/fr_FR/admin.lang index 288d769282e..d71f04ac698 100644 --- a/htdocs/langs/fr_FR/admin.lang +++ b/htdocs/langs/fr_FR/admin.lang @@ -939,6 +939,7 @@ ExtraFieldsThirdParties=Attributs supplémentaires (tiers) ExtraFieldsContacts=Attributs supplémentaires (contacts/adresses) ExtraFieldsMember=Attributs supplémentaires (adhérents) ExtraFieldsMemberType=Attributs supplémentaires (type d'adhérents) +ExtraFieldsCustomerInvoices=Attributs supplémentaires (factures clients) ExtraFieldHasWrongValue=L'attribut %s a une valeur incorrecte. AlphaNumOnlyCharsAndNoSpace=uniquement caractères alphanumériques sans espace SendingMailSetup=Configuration de l'envoi par mail diff --git a/htdocs/mailmanspip/class/mailmanspip.class.php b/htdocs/mailmanspip/class/mailmanspip.class.php index 845069327b0..9e10c315dfa 100644 --- a/htdocs/mailmanspip/class/mailmanspip.class.php +++ b/htdocs/mailmanspip/class/mailmanspip.class.php @@ -176,7 +176,7 @@ class MailmanSpip require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; $mdpass=dol_hash($object->pass); $htpass=crypt($object->pass,makesalt()); - $query = "INSERT INTO spip_auteurs (nom, email, login, pass, htpass, alea_futur, statut) VALUES(\"".$object->firstname." ".$object->lastname."\",\"".$object->email."\",\"".$object->login."\",\"$mdpass\",\"$htpass\",FLOOR(32000*RAND()),\"1comite\")"; + $query = "INSERT INTO spip_auteurs (nom, email, login, pass, htpass, alea_futur, statut) VALUES(\"".dolGetFirstLastname($object->firstname,$object->lastname)."\",\"".$object->email."\",\"".$object->login."\",\"$mdpass\",\"$htpass\",FLOOR(32000*RAND()),\"1comite\")"; $result = $mydb->query($query); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index a8b2f307e70..ca97aebb849 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1566,13 +1566,15 @@ function left_menu($menu_array_before, $helppagename='', $moresearchform='', $me //Dolibarr version $doliurl='http://www.dolibarr.org'; - $appli='Dolibarr'; - if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE; - + if (! empty($conf->global->MAIN_APPLICATION_TITLE)) { $appli=$conf->global->MAIN_APPLICATION_TITLE; $doliurl=''; } $appli.=" ".DOL_VERSION; - print ''; + print '
'; + if ($doliurl) print ''; + print $appli; + if ($doliurlx) print ''; + print '
'; print "\n"; print "\n"; diff --git a/htdocs/public/donations/donateurs_code.php b/htdocs/public/donations/donateurs_code.php index f354cffe8a1..972ba6a657d 100644 --- a/htdocs/public/donations/donateurs_code.php +++ b/htdocs/public/donations/donateurs_code.php @@ -81,10 +81,10 @@ if ($resql) $objp = $db->fetch_object($resql); $var=!$var; - print ""; + print ""; if ($objp->public) { - print "".$objp->firstname." ".$objp->lastname." ".$objp->societe."\n"; + print "".dolGetFirstLastname($objp->firstname, $objp->lastname)." ".$objp->societe."\n"; } else { diff --git a/htdocs/public/members/public_list.php b/htdocs/public/members/public_list.php index 6f32d9e4715..de4044e3574 100644 --- a/htdocs/public/members/public_list.php +++ b/htdocs/public/members/public_list.php @@ -140,7 +140,7 @@ if ($result) $objp = $db->fetch_object($result); $var=!$var; print ""; - print ''.$objp->firstname.' '.$objp->lastname.($objp->societe?' / '.$objp->societe:'').''."\n"; + print ''.dolGetFirstLastname($obj->firstname, $obj->lastname).($objp->societe?' / '.$objp->societe:'').''."\n"; //print "$objp->naiss\n"; // est-ce nécessaire ?? print ''.$objp->email.''."\n"; print ''.$objp->zip.''."\n"; diff --git a/htdocs/societe/admin/societe_extrafields.php b/htdocs/societe/admin/societe_extrafields.php index 66957c0314a..4ad507dc468 100755 --- a/htdocs/societe/admin/societe_extrafields.php +++ b/htdocs/societe/admin/societe_extrafields.php @@ -30,6 +30,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php'; $langs->load("companies"); $langs->load("admin"); +$langs->load("members"); $extrafields = new ExtraFields($db); $form = new Form($db); diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 2a25314b5d4..c87a6ef11f4 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -1616,7 +1616,7 @@ class Societe extends CommonObject $obj = $this->db->fetch_object($resql); if ($mode == 'email') $property=$obj->email; else if ($mode == 'mobile') $property=$obj->phone_mobile; - $contact_property[$obj->rowid] = trim($obj->firstname." ".$obj->lastname)." <".$property.">"; + $contact_property[$obj->rowid] = trim(dolGetFirstLastname($obj->firstname,$obj->lastname))." <".$property.">"; $i++; } } @@ -1649,7 +1649,7 @@ class Societe extends CommonObject while ($i < $nump) { $obj = $this->db->fetch_object($resql); - $contacts[$obj->rowid] = $obj->firstname." ".$obj->lastname; + $contacts[$obj->rowid] = dolGetFirstLastname($obj->firstname,$obj->lastname); $i++; } } @@ -1685,7 +1685,7 @@ class Societe extends CommonObject { $obj = $this->db->fetch_object($resql); - if ($mode == 'email') $contact_property = "$obj->firstname $obj->lastname <$obj->email>"; + if ($mode == 'email') $contact_property = dolGetFirstLastname($obj->firstname, $obj->lastname)." <".$obj->email.">"; else if ($mode == 'mobile') $contact_property = $obj->phone_mobile; } return $contact_property; diff --git a/htdocs/societe/commerciaux.php b/htdocs/societe/commerciaux.php index 0fa9f78353b..a4f1dee5a7b 100644 --- a/htdocs/societe/commerciaux.php +++ b/htdocs/societe/commerciaux.php @@ -188,7 +188,7 @@ if ($_GET["socid"]) print ''; print img_object($langs->trans("ShowUser"),"user").' '; - print $obj->firstname." " .$obj->lastname."\n"; + print dolGetFirstLastname($obj->firstname, $obj->lastname)."\n"; print ' '; if ($user->rights->societe->creer) { @@ -254,7 +254,7 @@ if ($_GET["socid"]) print ""; print ''; print img_object($langs->trans("ShowUser"),"user").' '; - print $obj->firstname." " .$obj->lastname."\n"; + print dolGetFirstLastname($obj->firstname, $obj->lastname)."\n"; print ''; print ''.$obj->login.''; print ''.$langs->trans("Add").''; diff --git a/htdocs/societe/notify/index.php b/htdocs/societe/notify/index.php index 9a1fc344a53..943d55669bf 100644 --- a/htdocs/societe/notify/index.php +++ b/htdocs/societe/notify/index.php @@ -93,9 +93,9 @@ if ($result) $var=!$var; - print ""; - print "socid."\">$obj->nom\n"; - print "".$obj->firstname." ".$obj->lastname."\n"; + print ""; + print "socid."\">".$obj->nom."\n"; + print "".dolGetFirstLastname($obj->firstname, $obj->lastname)."\n"; print "".$obj->titre."\n"; print "\n"; $i++; @@ -108,7 +108,7 @@ else dol_print_error($db); } -$db->close(); llxFooter(); +$db->close(); ?> diff --git a/htdocs/societe/tpl/linesalesrepresentative.tpl.php b/htdocs/societe/tpl/linesalesrepresentative.tpl.php index 63892395df7..9b2867cacff 100644 --- a/htdocs/societe/tpl/linesalesrepresentative.tpl.php +++ b/htdocs/societe/tpl/linesalesrepresentative.tpl.php @@ -27,7 +27,7 @@ foreach($listsalesrepresentatives as $val) { $userstatic->id=$val['id']; - $userstatic->lastname=$val['name']; + $userstatic->lastname=$val['lastname']; $userstatic->firstname=$val['firstname']; print $userstatic->getNomUrl(1); $i++; diff --git a/htdocs/user/fiche.php b/htdocs/user/fiche.php index 79e77debffa..5c4ddac9718 100644 --- a/htdocs/user/fiche.php +++ b/htdocs/user/fiche.php @@ -1076,7 +1076,7 @@ else // Lastname print ''.$langs->trans("Lastname").''; - print ''.$object->nom.''; + print ''.$object->lastname.''; // Photo print ''; diff --git a/scripts/emailings/cron-mailing-send.php b/scripts/emailings/cron-mailing-send.php index 658d899a677..e1290f4f769 100644 --- a/scripts/emailings/cron-mailing-send.php +++ b/scripts/emailings/cron-mailing-send.php @@ -120,7 +120,7 @@ if ($resql) $obj2 = $db->fetch_object($resql); // sendto en RFC2822 - $sendto = str_replace(',',' ',$obj2->firstname." ".$obj2->lastname) ." <".$obj2->email.">"; + $sendto = str_replace(',',' ',dolGetFirstLastname($obj2->firstname, $obj2->lastname)) ." <".$obj2->email.">"; // Make subtsitutions on topic and body $other=explode(';',$obj2->other); diff --git a/scripts/emailings/mailing-send.php b/scripts/emailings/mailing-send.php index 953c967bcb2..6db9eb00c2a 100644 --- a/scripts/emailings/mailing-send.php +++ b/scripts/emailings/mailing-send.php @@ -127,7 +127,7 @@ if ($resql) $obj = $db->fetch_object($resql); // sendto en RFC2822 - $sendto = str_replace(',',' ',$obj->firstname." ".$obj->lastname) ." <".$obj->email.">"; + $sendto = str_replace(',',' ',dolGetFirstLastname($obj->firstname, $obj->lastname) ." <".$obj->email.">"; // Make subtsitutions on topic and body $other=explode(';',$obj->other); diff --git a/scripts/invoices/email_unpaid_invoices_to_representatives.php b/scripts/invoices/email_unpaid_invoices_to_representatives.php index 2d3bd6f6c75..6abb260acf1 100755 --- a/scripts/invoices/email_unpaid_invoices_to_representatives.php +++ b/scripts/invoices/email_unpaid_invoices_to_representatives.php @@ -2,7 +2,7 @@ - * Copyright (C) 2005-2009 Laurent Destailleur + * Copyright (C) 2005-2013 Laurent Destailleur * * 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 @@ -35,67 +35,95 @@ if (substr($sapi_type, 0, 3) == 'cgi') { exit; } -if (! isset($argv[1]) || ! $argv[1]) { - print "Usage: $script_file now\n"; +if (! isset($argv[1]) || ! $argv[1] || ! in_array($argv[1],array('test','confirm'))) +{ + print "Usage: $script_file [test|confirm] [delay]\n"; + print "\n"; + print "Send an email to users to remind all unpaid invoices of customers they are sale representative for.\n"; + print "If you choose 'test' mode, no emails are sent.\n"; + print "If you add a delay (nb of days), only invoice with due date < today + delay are included.\n"; exit; } +$mode=$argv[1]; require($path."../../htdocs/master.inc.php"); require_once (DOL_DOCUMENT_ROOT."/core/class/CMailFile.class.php"); -$error = 0; +/* + * Main + */ -$sql = "SELECT f.facnumber, f.total_ttc, s.nom as name, u.lastname, u.firstname, u.email"; +$now=dol_now('tzserver'); +$duration_value=$argv[2]; + +$error = 0; +print $script_file." launched with mode ".$mode.($duration_value?" delay=".$duration_value:"")."\n"; + +$sql = "SELECT f.facnumber, f.total_ttc, s.nom as name, u.rowid as uid, u.lastname, u.firstname, u.email, u.lang"; $sql .= " FROM ".MAIN_DB_PREFIX."facture as f"; $sql .= " , ".MAIN_DB_PREFIX."societe as s"; $sql .= " , ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql .= " , ".MAIN_DB_PREFIX."user as u"; -$sql .= " WHERE f.paye = 0"; +$sql .= " WHERE f.fk_statut != 0 AND f.paye = 0"; $sql .= " AND f.fk_soc = s.rowid"; +if ($duration_value) $sql .= " AND f.date_lim_reglement < '".$db->idate(dol_time_plus_duree($now, $duration_value, "d"))."'"; $sql .= " AND sc.fk_soc = s.rowid"; $sql .= " AND sc.fk_user = u.rowid"; -$sql .= " ORDER BY u.email ASC, s.rowid ASC"; +$sql .= " ORDER BY u.email ASC, s.rowid ASC"; // Order by email to allow one message per email +//print $sql; $resql=$db->query($sql); if ($resql) { $num = $db->num_rows($resql); $i = 0; - $oldemail = ''; - $message = ''; - $total = ''; - dol_syslog("email_unpaid_invoices_to_representatives.php"); - + $oldemail = 'none'; $olduid = 0; $oldlang=''; + $total = 0; + print "We found ".$num." couples (unpayed validated invoice/sale representative) qualified\n"; + dol_syslog("We found ".$num." couples (unpayed validated invoice/sale representative) qualified"); + $message=''; + if ($num) { while ($i < $num) { $obj = $db->fetch_object($resql); - if ($obj->email <> $oldemail) + if (($obj->email <> $oldemail || $obj->uid <> $olduid) || $oldemail == 'none') { - if (dol_strlen($oldemail)) + // Break onto sales representative (new email or uid) + if (dol_strlen($oldemail) && $oldemail != 'none') { - envoi_mail($oldemail,$message,$total); + envoi_mail($mode,$oldemail,$message,$total,$oldlang); } $oldemail = $obj->email; + $olduid = $obj->uid; + $oldlang = $obj->lang; $message = ''; $total = 0; + if (empty($obj->email)) print "Warning: Sal representative ".dolGetFirstLastname($obj->firstname, $obj->lastname)." has no email. Notice disabled.\n"; } - $message .= $langs->trans("Invoice")." ".$obj->facnumber." : ".price($obj->total_ttc)." : ".$obj->name."\n"; - $total += $obj->total_ttc; + if (dol_strlen($oldemail)) + { + $message .= $langs->trans("Invoice")." ".$obj->facnumber." : ".price($obj->total_ttc)." : ".$obj->name."\n"; + print "Invoice ".$obj->facnumber.", price ".price2num($obj->total_ttc).", linked to company ".$obj->name." with sale representative ".dolGetFirstLastname($obj->firstname, $obj->lastname)." qualified.\n"; + dol_syslog("email_unpaid_invoices_to_representatives.php: ".$obj->email); + } - dol_syslog("email_unpaid_invoices_to_representatives.php: ".$obj->email); + $total += $obj->total_ttc; $i++; } // Si il reste des envois en buffer if ($total) { - envoi_mail($oldemail,$message,$total); + if (dol_strlen($oldemail) && $oldemail != 'none') // Break onto email (new email) + { + envoi_mail($mode,$oldemail,$message,$total,$oldlang); + } } } else @@ -109,6 +137,7 @@ else dol_syslog("email_unpaid_invoices_to_representatives.php: Error"); } + /** * Send email * @@ -117,25 +146,29 @@ else * @param string $total Total amount of unpayed invoices * @return int <0 if KO, >0 if OK */ -function envoi_mail($oldemail,$message,$total) +function envoi_mail($mode,$oldemail,$message,$total,$userlang) { global $conf,$langs; + global $db; - $subject = "[Dolibarr] List of unpaid invoices"; + $newlangs=new Translate($db,$conf); + $newlangs->setDefaultLang($userlang); + + $subject = "[".($conf->global->MAIN_APPLICATION_TITLE)."] ".$newlangs->trans("ListOfYourUnpaidInvoices"); $sendto = $oldemail; $from = $conf->global->MAIN_EMAIL_FROM; $errorsto = $conf->global->MAIN_MAIL_ERRORS_TO; $msgishtml = 0; - print "Envoi mail pour $oldemail, total: $total\n"; - dol_syslog("email_unpaid_invoices_to_representatives.php: send mail to $oldemail"); + print "Send email for ".$oldemail.", total: ".$total."\n"; + dol_syslog("email_unpaid_invoices_to_representatives.php: send mail to ".$oldemail); $allmessage = "List of unpaid invoices\n"; - $allmessage .= "This list contains only invoices for third parties you are linked to as a sales representative.\n"; - $allmessage .= "\n"; - $allmessage .= $message; - $allmessage .= "\n"; - $allmessage .= $langs->trans("Total")." = ".price($total)."\n"; + $allmessage.= "This list contains only invoices for third parties you are linked to as a sales representative.\n"; + $allmessage.= "\n"; + $allmessage.= $message; + $allmessage.= "\n"; + $allmessage.= $langs->trans("Total")." = ".price($total)."\n"; $mail = new CMailFile( $subject, @@ -153,7 +186,12 @@ function envoi_mail($oldemail,$message,$total) $mail->errors_to = $errorsto; - $result=$mail->sendfile(); + if ($mode == 'confirm') + { + $result=$mail->sendfile(); + } + else $result=1; + if ($result) { return 1;