Explorar o código

Merge remote-tracking branch 'uptream/develop' into 6.0-grh

Alexandre SPANGARO %!s(int64=8) %!d(string=hai) anos
pai
achega
1da0959a3a
Modificáronse 51 ficheiros con 2258 adicións e 938 borrados
  1. 1 0
      htdocs/admin/agenda_other.php
  2. 20 9
      htdocs/admin/dict.php
  3. 2 2
      htdocs/admin/mails.php
  4. 7 3
      htdocs/comm/action/card.php
  5. 10 1
      htdocs/comm/action/index.php
  6. 17 1
      htdocs/comm/action/listactions.php
  7. 1 1
      htdocs/comm/propal/card.php
  8. 5 18
      htdocs/commande/card.php
  9. 0 1
      htdocs/compta/facture/card.php
  10. 0 1
      htdocs/contrat/card.php
  11. 4 4
      htdocs/core/actions_massactions.inc.php
  12. 26 17
      htdocs/core/actions_sendmails.inc.php
  13. 6 0
      htdocs/core/class/conf.class.php
  14. 1 1
      htdocs/core/class/html.formmail.class.php
  15. 23 26
      htdocs/core/lib/functions.lib.php
  16. 4 3
      htdocs/core/lib/usergroups.lib.php
  17. 1 1
      htdocs/core/modules/modHRM.class.php
  18. 1 1
      htdocs/core/modules/modSalaries.class.php
  19. 3 55
      htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php
  20. 16 1
      htdocs/expedition/card.php
  21. 2 0
      htdocs/expedition/class/expedition.class.php
  22. 1 0
      htdocs/expedition/shipment.php
  23. 0 2
      htdocs/fichinter/card.php
  24. 0 1
      htdocs/fourn/commande/card.php
  25. 0 1
      htdocs/fourn/facture/card.php
  26. 2 2
      htdocs/hrm/admin/admin_establishment.php
  27. 1 1
      htdocs/hrm/admin/admin_hrm.php
  28. 23 6
      htdocs/hrm/class/establishment.class.php
  29. 88 82
      htdocs/hrm/establishment/card.php
  30. 1 1
      htdocs/hrm/establishment/info.php
  31. 6 6
      htdocs/install/mysql/data/llx_c_actioncomm.sql
  32. 3 2
      htdocs/install/mysql/migration/5.0.0-6.0.0.sql
  33. 1 0
      htdocs/install/mysql/tables/llx_expedition.sql
  34. 5 3
      htdocs/langs/en_US/admin.lang
  35. 2 0
      htdocs/langs/en_US/main.lang
  36. 1 0
      htdocs/langs/en_US/projects.lang
  37. 2 0
      htdocs/langs/fr_FR/admin.lang
  38. 1 0
      htdocs/langs/fr_FR/projects.lang
  39. 197 0
      htdocs/langs/fr_NC/projects.lang
  40. 71 0
      htdocs/langs/fr_NC/sendings.lang
  41. 277 24
      htdocs/modulebuilder/skeletons/skeleton_card.php
  42. 132 89
      htdocs/product/inventory/listview.class.php
  43. 702 0
      htdocs/product/list-with-listview.php
  44. 12 0
      htdocs/projet/element.php
  45. 3 3
      htdocs/societe/ajax/company.php
  46. 0 1
      htdocs/societe/card.php
  47. 0 1
      htdocs/supplier_proposal/card.php
  48. 1 0
      htdocs/theme/eldy/style.css.php
  49. 2 1
      htdocs/theme/md/style.css.php
  50. 22 9
      htdocs/user/bank.php
  51. 552 557
      htdocs/user/card.php

+ 1 - 0
htdocs/admin/agenda_other.php

@@ -4,6 +4,7 @@
  * Copyright (C) 2011-2017  Juanjo Menent           <jmenent@2byte.es>
  * Copyright (C) 2015		Jean-François Ferry	    <jfefe@aternatik.fr>
  * Copyright (C) 2016		Charlie Benke		    <charlie@patas-monkey.com>
+ * Copyright (C) 2017       Open-DSI                <support@open-dsi.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by

+ 20 - 9
htdocs/admin/dict.php

@@ -431,7 +431,7 @@ $tabhelp[2]  = array('code'=>$langs->trans("EnterAnyCode"));
 $tabhelp[3]  = array('code'=>$langs->trans("EnterAnyCode"));
 $tabhelp[4]  = array('code'=>$langs->trans("EnterAnyCode"));
 $tabhelp[5]  = array('code'=>$langs->trans("EnterAnyCode"));
-$tabhelp[6]  = array('code'=>$langs->trans("EnterAnyCode"), 'position'=>$langs->trans("PositionIntoComboList"));
+$tabhelp[6]  = array('code'=>$langs->trans("EnterAnyCode"), 'color'=>$langs->trans("ColorFormat"), 'position'=>$langs->trans("PositionIntoComboList"));
 $tabhelp[7]  = array('code'=>$langs->trans("EnterAnyCode"));
 $tabhelp[8]  = array('code'=>$langs->trans("EnterAnyCode"), 'position'=>$langs->trans("PositionIntoComboList"));
 $tabhelp[9]  = array('code'=>$langs->trans("EnterAnyCode"), 'unicode'=>$langs->trans("UnicodeCurrency"));
@@ -619,7 +619,7 @@ if (GETPOST('actionadd') || GETPOST('actionmodify'))
         }
     }
     // Other checks
-    if ($tabname[$id] == MAIN_DB_PREFIX."c_actioncomm" && isset($_POST["type"]) && in_array($_POST["type"],array('system','systemauto'))) {
+    if (GETPOST('actionadd') && $tabname[$id] == MAIN_DB_PREFIX."c_actioncomm" && isset($_POST["type"]) && in_array($_POST["type"],array('system','systemauto'))) {
         $ok=0;
         setEventMessages($langs->transnoentities('ErrorReservedTypeSystemSystemAuto'), null, 'errors');
     }
@@ -1104,7 +1104,7 @@ if ($id)
 
         if (empty($reshook))
         {
-       		fieldList($fieldlist,$obj,$tabname[$id],'add');
+       		fieldList($fieldlist, $obj, $tabname[$id], 'add');
         }
 
         if ($id == 4) print '<td></td>';
@@ -1228,6 +1228,7 @@ if ($id)
             if ($fieldlist[$field]=='lang')            { $valuetoshow=$langs->trans("Language"); }
             if ($fieldlist[$field]=='type')            { $valuetoshow=$langs->trans("Type"); }
             if ($fieldlist[$field]=='code')            { $valuetoshow=$langs->trans("Code"); }
+            if ($fieldlist[$field]=='position')        { $align='right'; }
             if ($fieldlist[$field]=='libelle' || $fieldlist[$field]=='label')
             {
                 //if ($id != 25) $valuetoshow=$form->textwithtooltip($langs->trans("Label"), $langs->trans("LabelUsedByDefault"),2,1,img_help(1,''));
@@ -1304,7 +1305,7 @@ if ($id)
                     $error=$hookmanager->error; $errors=$hookmanager->errors;
 
                     // Show fields
-                    if (empty($reshook)) fieldList($fieldlist,$obj,$tabname[$id],'edit');
+                    if (empty($reshook)) fieldList($fieldlist, $obj, $tabname[$id], 'edit');
 
                     print '<td colspan="3" align="center">';
                     print '<div name="'.(! empty($obj->rowid)?$obj->rowid:$obj->code).'"></div>';
@@ -1494,6 +1495,7 @@ if ($id)
                             $class='tddict';
                             if ($fieldlist[$field] == 'tracking') $class.=' tdoverflowauto';
                             if ($fieldlist[$field] == 'code') $class.=' width100';
+                            if ($fieldlist[$field] == 'position') $class.=' right';
                             // Show value for field
 							if ($showfield) print '<!-- '.$fieldlist[$field].' --><td align="'.$align.'" class="'.$class.'">'.$valuetoshow.'</td>';
                         }
@@ -1512,6 +1514,7 @@ if ($id)
                     if (in_array($obj->code, array('AC_OTH','AC_OTH_AUTO')) || in_array($obj->type, array('systemauto'))) { $canbedisabled=0; $canbedisabled = 0; }
                     $canbemodified=$iserasable;
                     if ($obj->code == 'RECEP') $canbemodified=1;
+                    if ($tabname[$id] == MAIN_DB_PREFIX."c_actioncomm") $canbemodified=1;
 
                     // Url 
                     $rowidcol=$tabrowid[$id];
@@ -1643,10 +1646,10 @@ $db->close();
 /**
  *	Show fields in insert/edit mode
  *
- * 	@param		array	$fieldlist		Array of fields
- * 	@param		Object	$obj			If we show a particular record, obj is filled with record fields
- *  @param		string	$tabname		Name of SQL table
- *  @param		string	$context		'add'=Output field for the "add form", 'edit'=Output field for the "edit form", 'hide'=Output field for the "add form" but we dont want it to be rendered
+ * 	@param		array		$fieldlist		Array of fields
+ * 	@param		Object		$obj			If we show a particular record, obj is filled with record fields
+ *  @param		string		$tabname		Name of SQL table
+ *  @param		string		$context		'add'=Output field for the "add form", 'edit'=Output field for the "edit form", 'hide'=Output field for the "add form" but we dont want it to be rendered
  *	@return		void
  */
 function fieldList($fieldlist, $obj='', $tabname='', $context='')
@@ -1663,7 +1666,15 @@ function fieldList($fieldlist, $obj='', $tabname='', $context='')
 
 	foreach ($fieldlist as $field => $value)
 	{
-		if ($fieldlist[$field] == 'country')
+	    if (in_array($fieldlist[$field], array('code', 'libelle', 'type')) && $tabname == MAIN_DB_PREFIX."c_actioncomm" && in_array($obj->type, array('system','systemauto')))
+        {
+            $hidden = (! empty($obj->{$fieldlist[$field]})?$obj->{$fieldlist[$field]}:'');
+            print '<td>';
+            print '<input type="hidden" name="'.$fieldlist[$field].'" value="'.$hidden.'">';
+            print $langs->trans($hidden);
+            print '</td>';
+        }
+	    elseif ($fieldlist[$field] == 'country')
 		{
 			if (in_array('region_id',$fieldlist))
 			{

+ 2 - 2
htdocs/admin/mails.php

@@ -86,8 +86,8 @@ if ($action == 'update' && empty($_POST["cancel"]))
 
 // Actions to send emails
 $id=0;
-$actiontypecode='';
-$trigger_name='';
+$actiontypecode='';     // Not an event for agenda
+$trigger_name='';       // Disable triggers
 $paramname='id';
 $mode='emailfortest';
 $trackid=(($action == 'testhtml')?"testhtml":"test");

+ 7 - 3
htdocs/comm/action/card.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2001-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
- * Copyright (C) 2004-2016 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2004-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2005      Simon TOSSER         <simon@kornog-computing.com>
  * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@capnetworks.com>
  * Copyright (C) 2010-2013 Juanjo Menent        <jmenent@2byte.es>
@@ -1114,7 +1114,7 @@ if ($id > 0)
 			$events[]=array('method' => 'getContacts', 'url' => dol_buildpath('/core/ajax/contacts.php?showempty=1',1), 'htmlname' => 'contactid', 'params' => array('add-customer-contact' => 'disabled'));
 			// TODO Refresh also list of project if $conf->global->PROJECT_ALLOW_TO_LINK_FROM_OTHER_COMPANY not defined with list linked to socid ?
 			// FIXME If we change company, we may get a project that does not match
-			print $form->select_company($object->socid, 'socid', '', 'SelectThirdParty', 1, 0, $events, 0);
+			print $form->select_company($object->socid, 'socid', '', 'SelectThirdParty', 1, 0, $events, 0, 'minwidth200');
 			print '</div>';
 			print '</td></tr>';
 
@@ -1396,7 +1396,11 @@ if ($id > 0)
 		{
 			include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 			print '<tr><td>'.$langs->trans("LinkedObject").'</td>';
-			print '<td colspan="3">'.dolGetElementUrl($object->fk_element,$object->elementtype,1).'</td></tr>';
+			$link=dolGetElementUrl($object->fk_element,$object->elementtype,1);
+			print '<td colspan="3">';
+			if (empty($link)) print '<span class="opacitymedium">'.$langs->trans("ObjectDeleted").'</span>';
+			else print $link;
+			print '</td></tr>';
 		}
 
 		// Description

+ 10 - 1
htdocs/comm/action/index.php

@@ -6,6 +6,7 @@
  * Copyright (C) 2011      Juanjo Menent        <jmenent@2byte.es>
  * Copyright (C) 2014      Cedric GROSS         <c.gross@kreiz-it.fr>
  * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
+ * Copyright (C) 2017      Open-DSI             <support@open-dsi.fr>
  *
  * 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
@@ -159,7 +160,6 @@ if ($action =='delete_action')
 }
 
 
-
 /*
  * View
  */
@@ -446,6 +446,7 @@ $sql.= ' a.percent,';
 $sql.= ' a.fk_user_author,a.fk_user_action,';
 $sql.= ' a.transparency, a.priority, a.fulldayevent, a.location,';
 $sql.= ' a.fk_soc, a.fk_contact,';
+$sql.= ' a.fk_element, a.elementtype,';
 $sql.= ' ca.code as type_code, ca.libelle as type_label, ca.color as type_color';
 $sql.= ' FROM '.MAIN_DB_PREFIX.'c_actioncomm as ca, '.MAIN_DB_PREFIX."actioncomm as a";
 if (! $user->rights->societe->client->voir && ! $socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON a.fk_soc = sc.fk_soc";
@@ -570,6 +571,8 @@ if ($resql)
         $event->fulldayevent=$obj->fulldayevent;
         $event->location=$obj->location;
         $event->transparency=$obj->transparency;
+        $event->fk_element=$obj->fk_element;
+        $event->elementtype=$obj->elementtype;
 
         $event->societe->id=$obj->fk_soc;
         $event->contact->id=$obj->fk_contact;
@@ -1478,6 +1481,12 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                             if ($linerelatedto) $linerelatedto.=' / ';
                             if (! empty($contact->id)) $linerelatedto.=$contact->getNomUrl(1,'',0);
                         }
+                        if (! empty($event->fk_element) && $event->fk_element > 0 && ! empty($event->elementtype) && ! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT))
+                        {
+                            include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+                            if ($linerelatedto) $linerelatedto.=' / ';
+                            $linerelatedto.=dolGetElementUrl($event->fk_element,$event->elementtype,1);
+                        }
                         if ($linerelatedto) print '<br>'.$linerelatedto;
                     }
 

+ 17 - 1
htdocs/comm/action/listactions.php

@@ -3,6 +3,7 @@
  * Copyright (C) 2003      Eric Seigne          <erics@rycks.com>
  * Copyright (C) 2004-2016 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@capnetworks.com>
+ * Copyright (C) 2017      Open-DSI             <support@open-dsi.fr>
  *
  * 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
@@ -183,6 +184,7 @@ $sql.= " s.nom as societe, s.rowid as socid, s.client,";
 $sql.= " a.id, a.label, a.datep as dp, a.datep2 as dp2,";
 $sql.= ' a.fk_user_author,a.fk_user_action,';
 $sql.= " a.fk_contact, a.note, a.percent as percent,";
+$sql.= " a.fk_element, a.elementtype,";
 $sql.= " c.code as type_code, c.libelle as type_label,";
 $sql.= " sp.lastname, sp.firstname";
 $sql.= " FROM ".MAIN_DB_PREFIX."c_actioncomm as c, ".MAIN_DB_PREFIX."actioncomm as a";
@@ -355,6 +357,7 @@ if ($resql)
 	print '</td>';
 	print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"></td>';
+    if (! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT)) print '<td class="liste_titre"></td>';
 	print '<td class="liste_titre"></td>';
     print '<td class="liste_titre center">';
     print $formactions->form_select_status_action('formaction',$status,1,'status',1,2);
@@ -375,7 +378,8 @@ if ($resql)
 	print_liste_field_titre($langs->trans("DateEnd"),$_SERVER["PHP_SELF"],"a.datep2",$param,'','align="center"',$sortfield,$sortorder);
 	print_liste_field_titre($langs->trans("ThirdParty"),$_SERVER["PHP_SELF"],"s.nom",$param,"","",$sortfield,$sortorder);
 	print_liste_field_titre($langs->trans("Contact"),$_SERVER["PHP_SELF"],"a.fk_contact",$param,"","",$sortfield,$sortorder);
-	print_liste_field_titre($langs->trans("ActionsOwnedByShort"),$_SERVER["PHP_SELF"],"",$param,"","",$sortfield,$sortorder);
+    if (! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT)) print_liste_field_titre($langs->trans("LinkedObject"),$_SERVER["PHP_SELF"],"a.fk_element",$param,"","",$sortfield,$sortorder);
+    print_liste_field_titre($langs->trans("ActionsOwnedByShort"),$_SERVER["PHP_SELF"],"",$param,"","",$sortfield,$sortorder);
 	print_liste_field_titre($langs->trans("Status"),$_SERVER["PHP_SELF"],"a.percent",$param,"",'align="center"',$sortfield,$sortorder);
 	print_liste_field_titre("");
 	print "</tr>\n";
@@ -482,6 +486,18 @@ if ($resql)
 		}
 		print '</td>';
 
+        // Linked object
+        if (! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT)) {
+            print '<td>';
+            if ($obj->fk_element > 0 && ! empty($obj->elementtype)) {
+                include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+                print dolGetElementUrl($obj->fk_element,$obj->elementtype,1);
+            } else {
+                print "&nbsp;";
+            }
+            print '</td>';
+        }
+
 		// User to do
 		print '<td align="left">';
 		if ($obj->fk_user_action > 0)

+ 1 - 1
htdocs/comm/propal/card.php

@@ -644,7 +644,7 @@ if (empty($reshook))
 	 */
 
 	// Actions to send emails
-	$actiontypecode='AC_PROP';
+    $actiontypecode='AC_OTH_AUTO';
 	$trigger_name='PROPAL_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromproposal';

+ 5 - 18
htdocs/commande/card.php

@@ -1259,7 +1259,6 @@ if (empty($reshook))
 
 
 	// Actions to send emails
-	$actiontypecode='AC_COM';
 	$trigger_name='ORDER_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromorder';
@@ -1328,13 +1327,7 @@ $formorder = new FormOrder($db);
 $formmargin = new FormMargin($db);
 if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); }
 
-/**
- * *******************************************************************
- *
- * Mode creation
- *
- * *******************************************************************
- */
+// Mode creation
 if ($action == 'create' && $user->rights->commande->creer)
 {
 	print load_fiche_titre($langs->trans('CreateOrder'),'','title_commercial.png');
@@ -1502,9 +1495,7 @@ if ($action == 'create' && $user->rights->commande->creer)
 	}
 	print '</tr>' . "\n";
 
-	/*
-	 * Contact de la commande
-	 */
+	// Contact of order
 	if ($socid > 0) {
 		print "<tr><td>" . $langs->trans("DefaultContact") . '</td><td colspan="2">';
 		$form->select_contacts($soc->id, $setcontact, 'contactid', 1, $srccontactslist);
@@ -1749,11 +1740,7 @@ if ($action == 'create' && $user->rights->commande->creer)
 		print '</table>';
 	}
 } else {
-	/* *************************************************************************** */
-	/*                                                                             */
-	/* Mode vue et edition                                                         */
-	/*                                                                             */
-	/* *************************************************************************** */
+	// Mode view
 	$now = dol_now();
 
 	if ($object->id > 0) {
@@ -2448,8 +2435,8 @@ if ($action == 'create' && $user->rights->commande->creer)
 		dol_fiche_end();
 
 		/*
-		 * Boutons actions
-		*/
+		 * Buttons for actions
+		 */
 		if ($action != 'presend' && $action != 'editline') {
 			print '<div class="tabsAction">';
 

+ 0 - 1
htdocs/compta/facture/card.php

@@ -1911,7 +1911,6 @@ if (empty($reshook))
 
 	// Actions to send emails
 	if (empty($id)) $id=$facid;
-	$actiontypecode='AC_FAC';
 	$trigger_name='BILL_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfrominvoice';

+ 0 - 1
htdocs/contrat/card.php

@@ -953,7 +953,6 @@ if (empty($reshook))
 	 */
 
 	// Actions to send emails
-	$actiontypecode='AC_CONT';
 	$trigger_name='CONTRACT_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromcontract';

+ 4 - 4
htdocs/core/actions_massactions.inc.php

@@ -274,12 +274,12 @@ if (! $error && $massaction == 'confirm_presend')
                         // Insert logs into agenda
                         foreach($listofqualifiedinvoice as $invid => $object)
                         {
-                            if ($objectclass == 'Propale') $actiontypecode='AC_PROP';
+                            /*if ($objectclass == 'Propale') $actiontypecode='AC_PROP';
                             if ($objectclass == 'Commande') $actiontypecode='AC_COM';
                             if ($objectclass == 'Facture') $actiontypecode='AC_FAC';
                             if ($objectclass == 'Supplier_Proposal') $actiontypecode='AC_SUP_PRO';
                             if ($objectclass == 'CommandeFournisseur') $actiontypecode='AC_SUP_ORD';
-                            if ($objectclass == 'FactureFournisseur') $actiontypecode='AC_SUP_INV';
+                            if ($objectclass == 'FactureFournisseur') $actiontypecode='AC_SUP_INV';*/
                             
                             $actionmsg=$langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto;
                             if ($message)
@@ -289,10 +289,10 @@ if (! $error && $massaction == 'confirm_presend')
                                 $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('TextUsedInTheMessageBody') . ":");
                                 $actionmsg = dol_concatdesc($actionmsg, $message);
                             }
-
+                            $actionmsg2='';
+                            
                             // Initialisation donnees
                             $object->sendtoid		= 0;
-                            $object->actiontypecode	= $actiontypecode;
                             $object->actionmsg		= $actionmsg;  // Long text
                             $object->actionmsg2		= $actionmsg2; // Short text
                             $object->fk_element		= $invid;

+ 26 - 17
htdocs/core/actions_sendmails.inc.php

@@ -23,11 +23,11 @@
 
 // $mysoc must be defined
 // $id must be defined
-// $actiontypecode must be defined
 // $paramname must be defined
 // $mode must be defined
-// $object and $uobject may be defined.
-
+// $trigger_name must be set (can be '')
+// $actiontypecode can be set
+// $object and $uobject may be defined
 
 /*
  * Add file in email form
@@ -155,7 +155,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
 				}
 			}
 		}
-		else dol_print_error('','Use actions_sendmails.in.php for a type that is not supported');
+		else dol_print_error('','Use actions_sendmails.in.php for an element/object that is not supported');
 	}
 	else $thirdparty = $mysoc;
 
@@ -347,7 +347,7 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
 				{
 					$error=0;
 
-					// FIXME This must be moved into a trigger for action $trigger_name
+					// FIXME This must be moved into the trigger for action $trigger_name
 					if (! empty($conf->dolimail->enabled))
 					{
 						$mid = (GETPOST('mid','int') ? GETPOST('mid','int') : 0);	// Original mail id is set ?
@@ -370,21 +370,26 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
 					// Initialisation of datas
 					if (is_object($object))
 					{
-						$object->socid			= $sendtosocid;	// To link to a company
-						$object->sendtoid		= $sendtoid;	// To link to contacts/addresses. This is an array.
-						$object->actiontypecode	= $actiontypecode;
-						$object->actionmsg		= $actionmsg;  // Long text
-						$object->actionmsg2		= $actionmsg2; // Short text
+					    if (empty($actiontypecode)) $actiontypecode='AC_OTH_AUTO'; // Event insert into agenda automatically
+					    
+						$object->socid			= $sendtosocid;	   // To link to a company
+						$object->sendtoid		= $sendtoid;	   // To link to contacts/addresses. This is an array.
+						$object->actiontypecode	= $actiontypecode; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
+						$object->actionmsg		= $actionmsg;      // Long text
+						$object->actionmsg2		= $actionmsg2;     // Short text
 						$object->trackid        = $trackid;
 						$object->fk_element		= $object->id;
 						$object->elementtype	= $object->element;
 
 						// Call of triggers
-						include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
-						$interface=new Interfaces($db);
-						$result=$interface->run_triggers($trigger_name,$object,$user,$langs,$conf);
-						if ($result < 0) {
-							$error++; $errors=$interface->errors;
+						if (! empty($trigger_name))
+						{
+    						include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
+    						$interface=new Interfaces($db);
+    						$result=$interface->run_triggers($trigger_name,$object,$user,$langs,$conf);
+    						if ($result < 0) {
+    							$error++; $errors=$interface->errors;
+    						}
 						}
 					}
 						
@@ -398,8 +403,12 @@ if (($action == 'send' || $action == 'relance') && ! $_POST['addfile'] && ! $_PO
 						// This avoid sending mail twice if going out and then back to page
 						$mesg=$langs->trans('MailSuccessfulySent',$mailfile->getValidAddress($from,2),$mailfile->getValidAddress($sendto,2));
 						setEventMessages($mesg, null, 'mesgs');
-						if ($conf->dolimail->enabled) header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.$object->id.'&'.($paramname2?$paramname2:'mid').'='.$parm2val);
-						else header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.$object->id);
+						if ($conf->dolimail->enabled) 
+						{
+						    header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.(is_object($object)?$object->id:'').'&'.($paramname2?$paramname2:'mid').'='.$parm2val);
+						    exit;
+						}
+						header('Location: '.$_SERVER["PHP_SELF"].'?'.($paramname?$paramname:'id').'='.(is_object($object)?$object->id:''));
 						exit;
 					}
 				}

+ 6 - 0
htdocs/core/class/conf.class.php

@@ -580,6 +580,12 @@ class Conf
 
 		if (empty($this->global->MAIN_SIZE_SHORTLIST_LIMIT)) $this->global->MAIN_SIZE_SHORTLIST_LIMIT=3;
 
+		// Save inconsistent option
+		if (empty($conf->global->AGENDA_USE_EVENT_TYPE) && $conf->global->AGENDA_DEFAULT_FILTER_TYPE == 'AC_NON_AUTO')
+		{
+		    $conf->global->AGENDA_DEFAULT_FILTER_TYPE='0';    // 'AC_NON_AUTO' does not exists when AGENDA_DEFAULT_FILTER_TYPE is not on.
+		}
+		    
 		// For backward compatibility
 		if (isset($this->product))   $this->produit=$this->product;
 		if (isset($this->facture))   $this->invoice=$this->facture;

+ 1 - 1
htdocs/core/class/html.formmail.class.php

@@ -297,7 +297,7 @@ class FormMail extends Form
         	$arraydefaultmessage=$this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id);
 			//var_dump($arraydefaultmessage);
 
-        	$out.= "\n<!-- Begin form mail -->\n";
+        	$out.= "\n".'<!-- Begin form mail --><div id="mailformdiv"></div>'."\n";
         	if ($this->withform == 1)
         	{
         		$out.= '<form method="POST" name="mailform" id="mailform" enctype="multipart/form-data" action="'.$this->param["returnurl"].'#formmail">'."\n";

+ 23 - 26
htdocs/core/lib/functions.lib.php

@@ -280,8 +280,24 @@ function GETPOST($paramname, $check='', $method=0, $filter=NULL, $options=NULL)
     	$relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
     	$relativepathstring = preg_replace('/^\//', '', $relativepathstring);
 	
-	    // Management of default values
-	    if (! isset($_GET['sortfield']) && ! empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES))	// If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
+    	// Retrieve values if restore_lastsearch_values is set and there is saved values
+    	if ($_GET['restore_lastsearch_values'] && ! empty($_SESSION['lastsearch_values_'.$relativepathstring]))        // Keep $_GET here
+    	{
+	        $tmp=json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
+	        if (is_array($tmp))
+	        {
+	            foreach($tmp as $key => $val)
+	            {
+	                if ($key == $paramname)
+	                {
+	                    $out=$val;
+	                    break;
+	                }
+	            }
+	        }
+    	}
+	    // Else, retreive default values if we are not doing a sort
+	    elseif (! isset($_GET['sortfield']) && ! empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES))	// If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
 	    {
 	        if (! empty($_GET['action']) && $_GET['action'] == 'create' && ! isset($_GET[$paramname]) && ! isset($_POST[$paramname]))
 	        {
@@ -331,26 +347,6 @@ function GETPOST($paramname, $check='', $method=0, $filter=NULL, $options=NULL)
 	        }
 	    }
 	    
-	    // Retrieve values into restore_lastsearch_values
-	    if ($_GET['restore_lastsearch_values'])        // Keep $_GET here
-	    {
-	        if (! empty($_SESSION['lastsearch_values_'.$relativepathstring]))
-	        {
-	            $tmp=json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
-	            if (is_array($tmp))
-	            {
-    	            foreach($tmp as $key => $val)
-    	            {
-        	           if ($key == $paramname)
-        	           {
-    	                   $out=$val;
-    	                   break;
-        	           }
-    	            }
-	            }
-	        }
-	    }
-	    
 	}	
 	
 	if (empty($check) && ! empty($conf->global->MAIN_FEATURES_LEVEL) && $conf->global->MAIN_FEATURES_LEVEL >= 2)
@@ -455,13 +451,14 @@ function GETPOST($paramname, $check='', $method=0, $filter=NULL, $options=NULL)
 	    //if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield", 'smonth', 'syear', 'month', 'year')))
 	    if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder','sortfield')))
 	    {
-	        //var_dump($user->default_values[$relativepathstring]);exit;
-	        //if ($paramname == 'sortorder') var_dump($paramname.' - '.$out);
-	        
+	        //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
+
 	        // We save search key only if:
 	        // - not empty, or
 	        // - if value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
-	        if (! empty($out) || ! empty($user->default_values[$relativepathstring][$paramname]))
+	        
+	        //if (! empty($out) || ! empty($user->default_values[$relativepathstring]['filters'][$paramname]))
+	        if (! empty($out))
 	        {
                 $user->lastsearch_values_tmp[$relativepathstring][$paramname]=$out;
 	        }

+ 4 - 3
htdocs/core/lib/usergroups.lib.php

@@ -141,16 +141,17 @@ function user_prepare_head($object)
     // $this->tabs = array('entity:-tabname);   												to remove a tab
     complete_head_from_modules($conf,$langs,$object,$head,$h,'user');
 
-	if (! empty($conf->hrm->enabled) && $user->rights->hrm->employee->read)
+    if ((! empty($conf->salaries->enabled) && ! empty($user->rights->salaries->read))
+       || (! empty($conf->hrm->enabled) && ! empty($user->rights->hrm->employee->read)))
     {
 		// Bank
     	$head[$h][0] = DOL_URL_ROOT.'/user/bank.php?id='.$object->id;
-    	$head[$h][1] = $langs->trans("BankAccounts");
+    	$head[$h][1] = $langs->trans("HRAndBank");
     	$head[$h][2] = 'bank';
     	$h++;
 	}
 
-    //Info on users is visible only by internal user
+    // Such info on users is visible only by internal user
     if (empty($user->societe_id))
     {
 		// Notes

+ 1 - 1
htdocs/core/modules/modHRM.class.php

@@ -45,7 +45,7 @@ class modHRM extends DolibarrModules
 		$this->family = "hr";
 		// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
 		$this->name = preg_replace( '/^mod/i', '', get_class($this));
-		$this->description = "Management of employees carrier and feelings";
+		$this->description = "Management of employees carrier and feelings (department, employment contract)";
 		
 		// Possible values for version are: 'development', 'experimental', 'dolibarr' or version
 		$this->version = 'development';

+ 1 - 1
htdocs/core/modules/modSalaries.class.php

@@ -54,7 +54,7 @@ class modSalaries extends DolibarrModules
 		// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
 		$this->name = preg_replace('/^mod/i','',get_class($this));
 		// Module description used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
-		$this->description = "Employees contracts and salaries management";
+		$this->description = "Payment of salaries";
 
 		// Possible values for version are: 'development', 'experimental', 'dolibarr' or version
 		$this->version = 'dolibarr';

+ 3 - 55
htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php

@@ -76,6 +76,8 @@ class InterfaceActionsAuto extends DolibarrTriggers
 
 		$langs->load("agenda");
 
+		if (empty($object->actiontypecode)) $object->actiontypecode='AC_OTH_AUTO';
+
 		// Actions
 		if ($action == 'COMPANY_CREATE')
         {
@@ -83,7 +85,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("companies");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("NewCompanyToDolibarr",$object->name);
             $object->actionmsg=$langs->transnoentities("NewCompanyToDolibarr",$object->name);
             if (! empty($object->prefix)) $object->actionmsg.=" (".$object->prefix.")";
@@ -97,7 +98,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-            if (empty($object->actiontypecode)) $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) dol_syslog('Trigger called with property actionmsg2 on object not defined', LOG_ERR);
 
             // Parameters $object->sendtoid defined by caller
@@ -109,7 +109,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("contracts");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ContractValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("ContractValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -121,7 +120,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("propal");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("PropalValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -133,7 +131,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("propal");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProposalSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -149,7 +146,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("propal");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("PropalClosedSignedInDolibarr",$object->ref);
 
@@ -161,7 +157,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("propal");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClassifiedBilledInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("PropalClassifiedBilledInDolibarr",$object->ref);
 
@@ -173,7 +168,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("propal");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("PropalClosedRefusedInDolibarr",$object->ref);
 
@@ -184,7 +178,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("agenda");
             $langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -196,7 +189,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderDeliveredInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("OrderDeliveredInDolibarr",$object->ref);
 
@@ -208,7 +200,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderBilledInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("OrderBilledInDolibarr",$object->ref);
 
@@ -220,7 +211,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderCanceledInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("OrderCanceledInDolibarr",$object->ref);
 
@@ -232,7 +222,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -248,7 +237,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -260,7 +248,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
 
@@ -272,7 +259,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -289,7 +275,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("bills");
 
             // Values for this action can't be defined by caller.
-			$object->actiontypecode='AC_OTH_AUTO';
             $object->actionmsg2=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
 
@@ -301,7 +286,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
 
@@ -313,7 +297,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionCreatedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InterventionCreatedInDolibarr",$object->ref);
 
@@ -327,7 +310,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("InterventionValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -341,7 +323,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionModifiedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InterventionModifiedInDolibarr",$object->ref);
 
@@ -355,7 +336,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionSentByEMail",$object->ref);
             $object->actionmsg=$langs->transnoentities("InterventionSentByEMail",$object->ref);
 
@@ -368,7 +348,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-            $object->actiontypecode='AC_OTH_AUTO';
            	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
            	$object->actionmsg=$langs->transnoentities("InterventionClassifiedBilledInDolibarr",$object->ref);
 
@@ -380,7 +359,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-            $object->actiontypecode='AC_OTH_AUTO';
            	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
            	$object->actionmsg=$langs->transnoentities("InterventionClassifiedUnbilledInDolibarr",$object->ref);
 
@@ -392,7 +370,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("interventions");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InterventionDeletedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InterventionDeletedInDolibarr",$object->ref);
 
@@ -406,7 +383,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("sendings");
 
-        	$object->actiontypecode='AC_OTH_AUTO';
         	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ShippingValidated",($object->newref?$object->newref:$object->ref));
         	if (empty($object->actionmsg))
         	{
@@ -422,7 +398,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("sendings");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ShippingSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -438,7 +413,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderCreatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("OrderCreatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -450,7 +424,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("OrderValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -462,7 +435,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("other");
 			$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
 			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
 			$object->actionmsg=$langs->transnoentities("OrderApprovedInDolibarr",$object->ref);
 
@@ -474,7 +446,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("other");
 			$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
 			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
 			$object->actionmsg=$langs->transnoentities("OrderRefusedInDolibarr",$object->ref);
 
@@ -486,7 +457,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("SupplierOrderSubmitedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("SupplierOrderSubmitedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -498,7 +468,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("orders");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("SupplierOrderReceivedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("SupplierOrderReceivedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -511,7 +480,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("bills");
             $langs->load("orders");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("SupplierOrderSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -528,7 +496,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("bills");
             $langs->load("orders");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("SupplierOrderClassifiedBilled",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -543,7 +510,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("InvoiceValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
 
@@ -555,7 +521,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoiceBackToDraftInDolibarr",$object->ref);
 
@@ -568,7 +533,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("bills");
             $langs->load("orders");
 
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("SupplierInvoiceSentByEMail",$object->ref);
             if (empty($object->actionmsg))
             {
@@ -584,7 +548,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoicePaidInDolibarr",$object->ref);
 
@@ -596,7 +559,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("bills");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("InvoiceCanceledInDolibarr",$object->ref);
 
@@ -610,7 +572,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("members");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg=$langs->transnoentities("MemberValidatedInDolibarr",($object->newref?$object->newref:$object->ref));
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
@@ -624,7 +585,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("members");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberModifiedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("MemberModifiedInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
@@ -638,7 +598,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("members");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("MemberSubscriptionAddedInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
@@ -654,7 +613,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("members");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberResiliatedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("MemberResiliatedInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
@@ -668,7 +626,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("members");
 
-			$object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("MemberDeletedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("MemberDeletedInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Member").': '.$object->getFullName($langs);
@@ -684,7 +641,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
         	$langs->load("projects");
 
-        	$object->actiontypecode='AC_OTH_AUTO';
         	if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
         	$object->actionmsg=$langs->transnoentities("ProjectCreatedInDolibarr",$object->ref);
         	$object->actionmsg.="\n".$langs->transnoentities("Project").': '.$object->ref;
@@ -696,8 +652,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("projects");
         
-            $object->actiontypecode='AC_OTH_AUTO';
-        
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProjectValidatedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("ProjectValidatedInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Project").': '.$object->ref;
@@ -709,7 +663,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
             $langs->load("other");
             $langs->load("projects");
         
-            $object->actiontypecode='AC_OTH_AUTO';
             if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("ProjectModifiedInDolibarr",$object->ref);
             $object->actionmsg=$langs->transnoentities("ProjectModifieddInDolibarr",$object->ref);
             $object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
@@ -723,8 +676,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("other");
 			$langs->load("projects");
 
-			$object->actiontypecode='AC_OTH_AUTO';
-
 			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
 			$object->actionmsg=$langs->transnoentities("TaskCreatedInDolibarr",$object->ref);
 			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
@@ -737,7 +688,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("other");
 			$langs->load("projects");
 
-			$object->actiontypecode='AC_OTH_AUTO';
 			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskModifiedInDolibarr",$object->ref);
 			$object->actionmsg=$langs->transnoentities("TaskModifieddInDolibarr",$object->ref);
 			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
@@ -750,7 +700,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("other");
 			$langs->load("projects");
 
-			$object->actiontypecode='AC_OTH_AUTO';
 			if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
 			$object->actionmsg=$langs->transnoentities("TaskDeletedInDolibarr",$object->ref);
 			$object->actionmsg.="\n".$langs->transnoentities("Task").': '.$object->ref;
@@ -763,7 +712,6 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $langs->load("agenda");
 		    $langs->load("other");
 		    
-		    $object->actiontypecode='AC_OTH_AUTO';
 		    if (empty($object->actionmsg2)) $object->actionmsg2=$langs->transnoentities($action."InDolibarr",$object->ref);
 		    $object->actionmsg=$langs->transnoentities($action."InDolibarr",$object->ref);
 		    
@@ -805,7 +753,7 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		// Insertion action
 		require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
 		$actioncomm = new ActionComm($this->db);
-		$actioncomm->type_code   = $object->actiontypecode;		// code of parent table llx_c_actioncomm (will be deprecated)
+		$actioncomm->type_code   = $object->actiontypecode;		// Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
 		$actioncomm->code        = 'AC_'.$action;
 		$actioncomm->label       = $object->actionmsg2;
 		$actioncomm->note        = $object->actionmsg;          // TODO Replace with $actioncomm->email_msgid ? $object->email_content : $object->actionmsg

+ 16 - 1
htdocs/expedition/card.php

@@ -191,6 +191,7 @@ if (empty($reshook))
 	    $object->note				= GETPOST('note','alpha');
 	    $object->origin				= $origin;
 	    $object->origin_id			= $origin_id;
+            $object->fk_project         = GETPOST('projectid');
 	    $object->weight				= GETPOST('weight','int')==''?"NULL":GETPOST('weight','int');
 	    $object->sizeH				= GETPOST('sizeH','int')==''?"NULL":GETPOST('sizeH','int');
 	    $object->sizeW				= GETPOST('sizeW','int')==''?"NULL":GETPOST('sizeW','int');
@@ -595,7 +596,6 @@ if (empty($reshook))
 
 	// Actions to send emails
 	if (empty($id)) $id=$facid;
-	$actiontypecode='AC_SHIP';
 	$trigger_name='SHIPPING_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromshipment';
@@ -696,6 +696,21 @@ if ($action == 'create')
             print '<td colspan="3">'.$soc->getNomUrl(1).'</td>';
             print '</tr>';
 
+            // Project
+            if (! empty($conf->projet->enabled))
+            {
+                $projectid = GETPOST('projectid')?GETPOST('projectid'):0;
+                if ($origin == 'project') $projectid = ($originid ? $originid : 0);
+
+                $langs->load("projects");
+                print '<tr>';
+                print '<td>' . $langs->trans("Project") . '</td><td colspan="2">';
+                $numprojet = $formproject->select_projects($soc->id, $projectid, 'projectid', 0);
+                print ' &nbsp; <a href="'.DOL_URL_ROOT.'/projet/card.php?socid=' . $soc->id . '&action=create&status=1&backtopage='.urlencode($_SERVER["PHP_SELF"].'?action=create&socid='.$soc->id).'">' . $langs->trans("AddProject") . '</a>';
+                print '</td>';
+                print '</tr>';
+            }
+
             // Date delivery planned
             print '<tr><td>'.$langs->trans("DateDeliveryPlanned").'</td>';
             print '<td colspan="3">';

+ 2 - 0
htdocs/expedition/class/expedition.class.php

@@ -211,6 +211,7 @@ class Expedition extends CommonObject
 		$sql.= ", date_expedition";
 		$sql.= ", date_delivery";
 		$sql.= ", fk_soc";
+		$sql.= ", fk_projet";
 		$sql.= ", fk_address";
 		$sql.= ", fk_shipping_method";
 		$sql.= ", tracking_number";
@@ -234,6 +235,7 @@ class Expedition extends CommonObject
 		$sql.= ", ".($this->date_expedition>0?"'".$this->db->idate($this->date_expedition)."'":"null");
 		$sql.= ", ".($this->date_delivery>0?"'".$this->db->idate($this->date_delivery)."'":"null");
 		$sql.= ", ".$this->socid;
+		$sql.= ", ".$this->fk_project;
 		$sql.= ", ".($this->fk_delivery_address>0?$this->fk_delivery_address:"null");
 		$sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:"null");
 		$sql.= ", '".$this->db->escape($this->tracking_number)."'";

+ 1 - 0
htdocs/expedition/shipment.php

@@ -880,6 +880,7 @@ if ($id > 0 || ! empty($ref))
                 print '<input type="hidden" name="shipping_method_id" value="'.$object->shipping_method_id.'">';
 				print '<input type="hidden" name="origin" value="commande">';
 				print '<input type="hidden" name="origin_id" value="'.$object->id.'">';
+				print '<input type="hidden" name="projectid" value="'.$object->fk_project.'">';
 				//print '<table class="border" width="100%">';
 
 				$langs->load("stocks");

+ 0 - 2
htdocs/fichinter/card.php

@@ -719,8 +719,6 @@ if (empty($reshook))
 	 */
 
 	// Actions to send emails
-	$actiontypecode='AC_OTH_AUTO';
-	$trigger_name='FICHINTER_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromintervention';
 	$trackid='int'.$object->id;

+ 0 - 1
htdocs/fourn/commande/card.php

@@ -1154,7 +1154,6 @@ if (empty($reshook))
 	 */
 
 	// Actions to send emails
-	$actiontypecode='AC_SUP_ORD';
 	$trigger_name='ORDER_SUPPLIER_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromsupplierorder';

+ 0 - 1
htdocs/fourn/facture/card.php

@@ -1188,7 +1188,6 @@ if (empty($reshook))
 	 */
 
 	// Actions to send emails
-	$actiontypecode='AC_SUP_INV';
 	$trigger_name='BILL_SUPPLIER_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromsupplierinvoice';

+ 2 - 2
htdocs/hrm/admin/admin_establishment.php

@@ -74,7 +74,7 @@ print load_fiche_titre($langs->trans("HRMSetup"), $linkback);
 
 // Configuration header
 $head = hrm_admin_prepare_head();
-dol_fiche_head($head, 'establishments', $langs->trans("HRM"), 0, "user");
+dol_fiche_head($head, 'establishments', $langs->trans("HRM"), -1, "user");
 
 $sql = "SELECT e.rowid, e.name, e.address, e.zip, e.town, e.status";
 $sql.= " FROM ".MAIN_DB_PREFIX."establishment as e";
@@ -120,7 +120,7 @@ if ($result)
 			print '<td align="left">'.$obj->town.'</td>';
 
             print '<td align="right">';
-			print $establishmentstatic->getLibStatus(5);
+			print $establishmentstatic->getLibStatut(5);
 			print '</td>';
             print "</tr>\n";
 

+ 1 - 1
htdocs/hrm/admin/admin_hrm.php

@@ -78,7 +78,7 @@ print '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">';
 print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
 print '<input type="hidden" name="action" value="update">';
 
-dol_fiche_head($head, 'parameters', $langs->trans("HRM"), 0, "user");
+dol_fiche_head($head, 'parameters', $langs->trans("HRM"), -1, "user");
 
 print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre">';

+ 23 - 6
htdocs/hrm/class/establishment.class.php

@@ -33,8 +33,10 @@ class Establishment extends CommonObject
 	public $table_element_line = '';
 	public $fk_element = 'fk_establishment';
 	protected $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
-
-	public $id;
+    public $picto='building';
+    
+    public $id;
+    public $ref;
 	public $rowid;
 
 	public $name;
@@ -96,6 +98,7 @@ class Establishment extends CommonObject
 		$sql.= ", entity";
 		$sql.= ", datec";
 		$sql.= ", fk_user_author";
+		$sql.= ", fk_user_mod";
 		$sql.= ") VALUES (";
 		$sql.= " '".$this->db->escape($this->name)."'";
 		$sql.= ", '".$this->db->escape($this->address)."'";
@@ -106,6 +109,7 @@ class Establishment extends CommonObject
 		$sql.= ", ".$conf->entity;
 		$sql.= ", '".$this->db->idate($now)."'";
 		$sql.= ", ". $user->id;
+		$sql.= ", ". $user->id;
 		$sql.= ")";
 
 		dol_syslog(get_class($this)."::create", LOG_DEBUG);
@@ -158,7 +162,7 @@ class Establishment extends CommonObject
 		$sql .= ", zip = '".$this->db->escape($this->zip)."'";
 		$sql .= ", town = '".$this->db->escape($this->town)."'";
 		$sql .= ", fk_country = ".($this->country_id > 0 ? $this->country_id : 'null');
-		$sql .= ", status = '".$this->db->escape($this->status)."'";
+		$sql .= ", status = ".$this->db->escape($this->status);
 		$sql .= ", fk_user_mod = " . $user->id;
 		$sql .= " WHERE rowid = ".$this->id;
 
@@ -195,6 +199,7 @@ class Establishment extends CommonObject
 			$obj = $this->db->fetch_object($result);
 
 			$this->id			= $obj->rowid;
+			$this->ref			= $obj->rowid;
 			$this->name			= $obj->name;
 			$this->address		= $obj->address;
 			$this->zip			= $obj->zip;
@@ -247,9 +252,9 @@ class Establishment extends CommonObject
 	 * @param	int		$mode   	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
 	 * @return  string   		   	Label
 	 */
-	function getLibStatus($mode=0)
+	function getLibStatut($mode=0)
 	{
-		return $this->LibStatus($this->status,$mode);
+		return $this->LibStatut($this->status,$mode);
 	}
 
 	/**
@@ -259,7 +264,7 @@ class Establishment extends CommonObject
 	 *  @param  int		$mode       0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
 	 *  @return string      		Label
 	 */
-	function LibStatus($status,$mode=0)
+	function LibStatut($status,$mode=0)
 	{
 		global $langs;
 
@@ -381,4 +386,16 @@ class Establishment extends CommonObject
 
         return '';
     }
+    
+    /**
+     * Initialise object with example values
+     * Id must be 0 if object instance is a specimen
+     *
+     * @return void
+     */
+    public function initAsSpecimen()
+    {
+        $this->id = 0;
+        $this->ref = 'DEAAA';
+    }    
 }

+ 88 - 82
htdocs/hrm/establishment/card.php

@@ -140,7 +140,8 @@ else if ($action == 'update')
 			$object->town			= GETPOST('town', 'alpha');
 			$object->country_id     = GETPOST('country_id', 'int');
 			$object->fk_user_mod	= $user->id;
-
+			$object->status         = GETPOST('status','int');
+			
 			$result = $object->update($user);
 
             if ($result > 0)
@@ -184,13 +185,13 @@ if ($action == 'create')
     print '<table class="border" width="100%">';
 
 	// Name
-    print '<tr><td>'. fieldLabel('Name','name',1).'</td><td><input name="name" id="name" size="32" value="' . GETPOST("name") . '"></td></tr>';
+    print '<tr><td>'. fieldLabel('Name','name',1).'</td><td><input name="name" id="name" size="32" value="' . GETPOST("name", "alpha") . '"></td></tr>';
 
 	// Address
 	print '<tr>';
 	print '<td>'.fieldLabel('Address','address',0).'</td>';
 	print '<td>';
-	print '<input name="address" id="address" size="32" value="' . $object->address . '">';
+	print '<input name="address" id="address" class="qutrevingtpercent" value="' . GETPOST('address','alpha') . '">';
 	print '</td>';
 	print '</tr>';
 
@@ -220,7 +221,7 @@ if ($action == 'create')
 	print '<tr>';
 	print '<td>'.fieldLabel('Country','selectcountry_id',0).'</td>';
 	print '<td class="maxwidthonsmartphone">';
-	print $form->select_country($mysoc->country_id,'country_id');
+	print $form->select_country(GETPOST('country_id','int')>0?GETPOST('country_id','int'):$mysoc->country_id,'country_id');
 		if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
 	print '</td>';
 	print '</tr>';
@@ -229,7 +230,7 @@ if ($action == 'create')
     print '<tr>';
     print '<td>'.fieldLabel('Status','status',1).'</td>';
 	print '<td>';
-	print $form->selectarray('status',$status2label,GETPOST('status'));
+	print $form->selectarray('status',$status2label,GETPOST('status','alpha'));
     print '</td></tr>';
 
     print '</table>';
@@ -244,7 +245,9 @@ if ($action == 'create')
 
     print '</form>';
 }
-else if ($id)
+
+// Part to edit record
+if (($id || $ref) && $action == 'edit')
 {
     $result = $object->fetch($id);
     if ($result > 0)
@@ -316,91 +319,94 @@ else if ($id)
 
             print '</form>';
         }
-        else
-        {
-            /*
-             * Confirm delete
-             */
-            if ($action == 'delete')
-            {
-                print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("DeleteEstablishment"),$langs->trans("ConfirmDeleteEstablishment"),"confirm_delete");
-
-            }
-
-        	dol_fiche_head($head, 'card', $langs->trans("Establishment"), 0, 'building');
-
-        	print '<table class="border" width="100%">';
-
-            $linkback = '<a href="../admin/admin_establishment.php">'.$langs->trans("BackToList").'</a>';
+    }
+    else dol_print_error($db);
+}
 
-            // Ref
-            print '<tr><td width="25%">'.$langs->trans("Ref").'</td><td width="50%">';
-            print $object->id;
-			print '</td><td width="25%">';
-			print $linkback;
-            print '</td></tr>';
+if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create')))
+{
+    $res = $object->fetch_optionals($object->id, $extralabels);
+    
+    $head = establishment_prepare_head($object);
+    dol_fiche_head($head, 'card', $langs->trans("Establishment"), -1, 'building');
+    
+    // Confirmation to delete
+    if ($action == 'delete')
+    {
+        print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$id,$langs->trans("DeleteEstablishment"),$langs->trans("ConfirmDeleteEstablishment"),"confirm_delete");
 
-			// Name
-			print '<tr>';
-			print '<td>'.$langs->trans("Name").'</td>';
-			print '<td colspan="2">'.$object->name.'</td>';
-			print '</tr>';
+    }
 
-			// Address
-			print '<tr>';
-			print '<td>'.$langs->trans("Address").'</td>';
-			print '<td colspan="2">'.$object->address.'</td>';
-			print '</tr>';
-
-			// Zipcode
-			print '<tr>';
-			print '<td>'.$langs->trans("Zipcode").'</td>';
-			print '<td colspan="2">'.$object->zip.'</td>';
-			print '</tr>';
-
-			// Town
-			print '<tr>';
-			print '<td>'.$langs->trans("Town").'</td>';
-			print '<td colspan="2">'.$object->town.'</td>';
-			print '</tr>';
+	
+	// Object card
+	// ------------------------------------------------------------
+	
+	$linkback = '<a href="' . DOL_URL_ROOT . '/hrm/admin/admin_establishment.php' . (! empty($socid) ? '?socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	
+	$morehtmlref='<div class="refidno">';
+    $morehtmlref.='</div>';
+	
+    dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'id', $morehtmlref);
+    
+    
+    print '<div class="fichecenter">';
+    //print '<div class="fichehalfleft">';
+    print '<div class="underbanner clearboth"></div>';
+    print '<table class="border centpercent">'."\n"; 
 
-			// Country
-			print '<tr>';
-			print '<td>'.$langs->trans("Country").'</td>';
-			print '<td colspan="2">';
-			if ($object->country_id > 0)
-			{
-				$img=picto_from_langcode($object->country_code);
-				print $img?$img.' ':'';
-				print getCountry($object->getCountryCode(),0,$db);
-			}
-			print '</td>';
-			print '</tr>';
+	// Name
+	print '<tr>';
+	print '<td class="titlefield">'.$langs->trans("Name").'</td>';
+	print '<td>'.$object->name.'</td>';
+	print '</tr>';
 
-            // Status
-            print '<tr><td>'.$langs->trans("Status").'</td><td colspan="2">';
-            print $object->getLibStatus(4).'</td></tr>';
+	// Address
+	print '<tr>';
+	print '<td>'.$langs->trans("Address").'</td>';
+	print '<td>'.$object->address.'</td>';
+	print '</tr>';
 
-            print "</table>";
+	// Zipcode
+	print '<tr>';
+	print '<td>'.$langs->trans("Zipcode").'</td>';
+	print '<td>'.$object->zip.'</td>';
+	print '</tr>';
 
-            dol_fiche_end();
+	// Town
+	print '<tr>';
+	print '<td>'.$langs->trans("Town").'</td>';
+	print '<td>'.$object->town.'</td>';
+	print '</tr>';
 
-            /*
-             * Barre d'actions
-            */
+	// Country
+	print '<tr>';
+	print '<td>'.$langs->trans("Country").'</td>';
+	print '<td>';
+	if ($object->country_id > 0)
+	{
+		$img=picto_from_langcode($object->country_code);
+		print $img?$img.' ':'';
+		print getCountry($object->getCountryCode(),0,$db);
+	}
+	print '</td>';
+	print '</tr>';
 
-            print '<div class="tabsAction">';
-            print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&id='.$id.'">'.$langs->trans('Modify').'</a>';
-			print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&id='.$id.'">'.$langs->trans('Delete').'</a>';
-            print '</div>';
-        }
-    }
-    else
-    {
-        dol_print_error($db);
-    }
+    print '</table>';
+    print '</div>';
+    
+    print '<div class="clearboth"></div><br>';
+    
+    dol_fiche_end();
+
+    /*
+     * Barre d'actions
+    */
+
+    print '<div class="tabsAction">';
+    print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&id='.$id.'">'.$langs->trans('Modify').'</a>';
+	print '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&id='.$id.'">'.$langs->trans('Delete').'</a>';
+    print '</div>';
 }
-
+ 
 llxFooter();
-
 $db->close();

+ 1 - 1
htdocs/hrm/establishment/info.php

@@ -44,7 +44,7 @@ if ($id)
 
 	$head = establishment_prepare_head($object);
 
-	dol_fiche_head($head, 'info', $langs->trans("Establishment"), 0, 'building');
+	dol_fiche_head($head, 'info', $langs->trans("Establishment"), -1, 'building');
 
     print '<table width="100%"><tr><td>';
     dol_print_object_info($object);

+ 6 - 6
htdocs/install/mysql/data/llx_c_actioncomm.sql

@@ -38,12 +38,12 @@ insert into llx_c_actioncomm (id, code, type, libelle, module, active, position)
 insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 5,'AC_RDV','system','Rendez-vous',NULL, 1, 1);
 insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values (11,'AC_INT','system','Intervention on site',NULL, 1, 4);
 -- Code kept for backward compatibility < 3.3 
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 3,'AC_PROP','systemauto', 'Send commercial proposal by email','propal',0,10);
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 8,'AC_COM','systemauto','Send customer order by email','order', 0,8);
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 9,'AC_FAC','systemauto', 'Send customer invoice by email','invoice',0,6);
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 10,'AC_SHIP','systemauto', 'Send shipping by email','shipping',0,11);
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 30,'AC_SUP_ORD','systemauto','Send supplier order by email','order_supplier',0,9);
-insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 31,'AC_SUP_INV','systemauto','Send supplier invoice by email','invoice_supplier',0,7);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 3,'AC_PROP','systemauto', 'Send commercial proposal by email','propal',0,10);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 8,'AC_COM','systemauto','Send customer order by email','order', 0,8);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 9,'AC_FAC','systemauto', 'Send customer invoice by email','invoice',0,6);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 10,'AC_SHIP','systemauto', 'Send shipping by email','shipping',0,11);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 30,'AC_SUP_ORD','systemauto','Send supplier order by email','order_supplier',0,9);
+--insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 31,'AC_SUP_INV','systemauto','Send supplier invoice by email','invoice_supplier',0,7);
 -- Code used from 3.3+ when type of event is not used
 insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 40,'AC_OTH_AUTO','systemauto','Other (automatically inserted events)',NULL, 1, 20);
 insert into llx_c_actioncomm (id, code, type, libelle, module, active, position) values ( 50,'AC_OTH','system','Other (manually inserted events)',NULL, 1, 5);

+ 3 - 2
htdocs/install/mysql/migration/5.0.0-6.0.0.sql

@@ -47,6 +47,8 @@ ALTER TABLE llx_ecm_files ADD INDEX idx_ecm_files_label (label);
 ALTER TABLE llx_holiday ADD COLUMN import_key				varchar(14);
 ALTER TABLE llx_holiday ADD COLUMN extraparams				varchar(255);	
 
+ALTER TABLE llx_expedition ADD COLUMN fk_projet integer DEFAULT NULL after fk_soc;
+
 ALTER TABLE llx_expensereport ADD COLUMN import_key			varchar(14);
 ALTER TABLE llx_expensereport ADD COLUMN extraparams		varchar(255);	
 
@@ -308,7 +310,6 @@ ALTER TABLE llx_events MODIFY COLUMN ip varchar(250);
 
 ALTER TABLE llx_facture ADD COLUMN fk_fac_rec_source integer;
 
-
-
+DELETE from llx_c_actioncomm where code in ('AC_PROP','AC_COM','AC_FAC','AC_SHIP','AC_SUP_ORD','AC_SUP_INV') AND id NOT IN (SELECT DISTINCT fk_action FROM llx_actioncomm);
 
 

+ 1 - 0
htdocs/install/mysql/tables/llx_expedition.sql

@@ -26,6 +26,7 @@ create table llx_expedition
   ref                   varchar(30)        NOT NULL,
   entity                integer  DEFAULT 1 NOT NULL,	-- multi company id
   fk_soc                integer            NOT NULL,
+  fk_projet  		integer  DEFAULT NULL,
   
   ref_ext               varchar(30),					-- reference into an external system (not used by dolibarr)
   ref_int				varchar(30),					-- reference into an internal system (used by dolibarr to store extern id like paypal info)

+ 5 - 3
htdocs/langs/en_US/admin.lang

@@ -519,8 +519,8 @@ Module410Name=Webcalendar
 Module410Desc=Webcalendar integration
 Module500Name=Special expenses
 Module500Desc=Management of special expenses (taxes, social or fiscal taxes, dividends)
-Module510Name=Employee contracts and salaries
-Module510Desc=Management of employees contracts, salaries and payments
+Module510Name=Payment of employee wages
+Module510Desc=Record and follow payment of your employee wages
 Module520Name=Loan
 Module520Desc=Management of loans
 Module600Name=Notifications
@@ -563,7 +563,7 @@ Module2900Desc=GeoIP Maxmind conversions capabilities
 Module3100Name=Skype
 Module3100Desc=Add a Skype button into users / third parties / contacts / members cards
 Module4000Name=HRM
-Module4000Desc=Human resources management
+Module4000Desc=Human resources management (mangement of department, employee contracts and feelings)
 Module5000Name=Multi-company
 Module5000Desc=Allows you to manage multiple companies
 Module6000Name=Workflow
@@ -1512,6 +1512,7 @@ AGENDA_DEFAULT_FILTER_STATUS=Set automatically this status for events into searc
 AGENDA_DEFAULT_VIEW=Which tab do you want to open by default when selecting menu Agenda
 AGENDA_NOTIFICATION=Enable event notification on user browsers when event date is reached (each user is able to refuse this from the browser confirmation question)
 AGENDA_NOTIFICATION_SOUND=Enable sound notification
+AGENDA_SHOW_LINKED_OBJECT=Show linked object into agenda view
 ##### Clicktodial #####
 ClickToDialSetup=Click To Dial module setup
 ClickToDialUrlDesc=Url called when a click on phone picto is done.  In URL, you can use tags<br><b>__PHONETO__</b> that will be replaced with the phone number of person to call<br><b>__PHONEFROM__</b> that will be replaced with phone number of calling person (yours)<br><b>__LOGIN__</b> that will be replaced with clicktodial login (defined on user card)<br><b>__PASS__</b> that will be replaced with clicktodial password (defined on user card).
@@ -1632,6 +1633,7 @@ MinimumNoticePeriod=Minimum notice period (Your leave request must be done befor
 NbAddedAutomatically=Number of days added to counters of users (automatically) each month
 EnterAnyCode=This field contains a reference to identify line. Enter any value of your choice, but without special characters.
 UnicodeCurrency=Enter here between braces, list of byte number that represent the currency symbol. For exemple: for $, enter [36] - for brazil real R$ [82,36] - for €, enter [8364]
+ColorFormat=The RGB color is in HEX format, eg: FF0000
 PositionIntoComboList=Position of line into combo lists
 SellTaxRate=Sale tax rate
 RecuperableOnly=Yes for VAT "Non Perçue Récupérable" dedicated for some state in France. Keep value to "No" in all other cases.

+ 2 - 0
htdocs/langs/en_US/main.lang

@@ -771,6 +771,8 @@ ModuleBuilder=Module Builder
 SetMultiCurrencyCode=Set currency
 BulkActions=Bulk actions
 ClickToShowHelp=Click to show tooltip help
+HR=HR
+HRAndBank=HR and Bank
 # Week day
 Monday=Monday
 Tuesday=Tuesday

+ 1 - 0
htdocs/langs/en_US/projects.lang

@@ -82,6 +82,7 @@ ListPredefinedInvoicesAssociatedProject=List of customer template invoices assoc
 ListSupplierOrdersAssociatedProject=List of supplier orders associated with the project
 ListSupplierInvoicesAssociatedProject=List of supplier invoices associated with the project
 ListContractAssociatedProject=List of contracts associated with the project
+ListShippingAssociatedProject=List of shippings associated with the project
 ListFichinterAssociatedProject=List of interventions associated with the project
 ListExpenseReportsAssociatedProject=List of expense reports associated with the project
 ListDonationsAssociatedProject=List of donations associated with the project

+ 2 - 0
htdocs/langs/fr_FR/admin.lang

@@ -1479,6 +1479,7 @@ AGENDA_DEFAULT_FILTER_STATUS=Régler automatiquement le statut d'événement dan
 AGENDA_DEFAULT_VIEW=Quel onglet voulez-vous voir ouvrir par défaut quand on choisit le menu Agenda
 AGENDA_NOTIFICATION=Activer les notifications d'événements dans le navigateur utilisateur quand la date de l'événement est atteinte (Chaque utilisateur peut refuser ceci au moment de la question de confirmation posée par le navigateur).
 AGENDA_NOTIFICATION_SOUND=Activer les notifications sonores.
+AGENDA_SHOW_LINKED_OBJECT=Afficher l'objet lié dans la vue agenda
 ##### Clicktodial #####
 ClickToDialSetup=Configuration du module Click To Dial
 ClickToDialUrlDesc=URL appelée lors d'un clic sur le pictogramme téléphone. Dans l'URL, vous pouvez utiliser les balises<br><b>__PHONETO__</b> qui sera remplacée par le téléphone de l'appelé<br><b>__PHONEFROM__</b> qui sera remplacée par le téléphone de l'appelant (le votre, défini sur votre fiche utilisateur)<br><b>__LOGIN__</b> qui sera remplacée par votre identifiant clicktodial (défini sur votre fiche utilisateur)<br><b>__PASS__</b> qui sera remplacée par votre mot de passe clicktodial (défini sur votre fiche utilisateur).
@@ -1600,6 +1601,7 @@ MinimumNoticePeriod=Période de préavis minimum (Votre demande de congé doit 
 NbAddedAutomatically=Nombre de jours ajoutés aux compteurs des utilisateurs (automatiquement) chaque mois
 EnterAnyCode=Ce champ contient une référence pour identifier le champ. Entrez une valeur de votre choix, mais sans caractères spéciaux.
 UnicodeCurrency=Saisissez ici entre accolades, la liste du numéro des octets qui représentent le symbole de la monnaie. Pour exemple: pour $, entrez [36] - pour le Real Brésilien R$ [82,36] - pour l'euro €, entrez [8364]
+ColorFormat=La couleur RVB est au format HEX, ex: FF0000
 PositionIntoComboList=Position de la ligne dans des listes déroulantes
 SellTaxRate=Taux de TVA
 RecuperableOnly=Oui pour une TVA "Perçue Non Récupérable" dédiée à certains pays comme la France. Gardez la valeur à "Non" dans tous les autres cas.

+ 1 - 0
htdocs/langs/fr_FR/projects.lang

@@ -79,6 +79,7 @@ ListSupplierOrdersAssociatedProject=Liste des commandes fournisseurs associées
 ListSupplierInvoicesAssociatedProject=Liste des factures fournisseurs associées au projet
 ListContractAssociatedProject=Liste des contrats associés au projet
 ListFichinterAssociatedProject=Liste des interventions associées au projet
+ListShippingAssociatedProject=Liste des expéditions associées au projet
 ListExpenseReportsAssociatedProject=Liste des notes de frais associées avec ce projet
 ListDonationsAssociatedProject=Liste des dons associés au projet
 ListActionsAssociatedProject=Liste des événements associés au projet

+ 197 - 0
htdocs/langs/fr_NC/projects.lang

@@ -0,0 +1,197 @@
+# Dolibarr language file - Source file is en_US - projects
+RefProject=Réf. projet
+ProjectRef=Ref projet
+ProjectId=Id projet
+ProjectLabel=Libellé projet
+Project=Projet
+Projects=Projets
+ProjectsArea=Espace projets
+ProjectStatus=Statut projet
+SharedProject=Tout le monde
+PrivateProject=Contacts projet
+MyProjectsDesc=Cette vue projet est restreinte aux projets pour lesquels vous êtes un contact affecté (quel qu'en soit le type).
+ProjectsPublicDesc=Cette vue présente tous les projets pour lesquels vous êtes habilité à avoir une visibilité.
+TasksOnProjectsPublicDesc=Cette vue affiche toutes les tâches de projets selon vos permissions utilisateur
+ProjectsPublicTaskDesc=Cette vue présente tous les projets et tâches pour lesquels vous êtes habilité à avoir une visibilité.
+ProjectsDesc=Cette vue présente tous les projets (vos habilitations vous offrant une vue exhaustive).
+TasksOnProjectsDesc=Cette vue présente toutes les tâches sur tous les projets (vos permissions d'utilisateur vous accordent la permission de voir tout).
+MyTasksDesc=Cette vue est restreinte aux projets et tâches pour lesquels vous êtes un contact affecté à au moins une tâche (quel qu'en soit le type).
+OnlyOpenedProject=Seuls les projets ouverts sont visibles (les projets à l'état brouillon ou fermé ne sont pas visibles).
+ClosedProjectsAreHidden=Les projets fermés ne sont pas visible.
+TasksPublicDesc=Cette vue présente tous les projets et tâches pour lesquels vous êtes habilité à avoir une visibilité.
+TasksDesc=Cette vue présente tous les projets et tâches (vos habilitations vous offrant une vue exhaustive).
+AllTaskVisibleButEditIfYouAreAssigned=Toutes les tâches d'un tel projet sont visibles mais il n'est possible de saisir du temps passé que sur celles qui vous sont assignées.\nAssignez vous la tache pour pouvoir saisir un temps passé.
+OnlyYourTaskAreVisible=Seules les tâches qui vous sont assignées sont visibles. Assignez vous une tâche pour la voir et saisir du temps passé
+ImportDatasetTasks=Tâches des projets
+NewProject=Nouveau projet
+AddProject=Créer projet
+DeleteAProject=Supprimer un projet
+DeleteATask=Supprimer une tâche
+ConfirmDeleteAProject=Êtes-vous sûr de vouloir supprimer ce projet ?
+ConfirmDeleteATask=Êtes-vous sûr de vouloir supprimer cette tâche ?
+OpenedProjects=Projets ouverts
+OpenedTasks=Tâches ouvertes
+OpportunitiesStatusForOpenedProjects=Montant des opportunités des projets ouverts par statut
+OpportunitiesStatusForProjects=Montant des opportunités des projets par statut
+ShowProject=Afficher projet
+SetProject=Définir projet
+NoProject=Aucun projet défini ou responsable
+NbOfProjects=Nombre de projets
+TimeSpent=Temps consommé
+TimeSpentByYou=Temps consommé par vous
+TimeSpentByUser=Temps consommé par utilisateur
+TimesSpent=Temps consommés
+RefTask=Ref. tâche
+LabelTask=Libellé tâche
+TaskTimeSpent=Temps consommé sur les tâches
+TaskTimeUser=Utilisateur
+TaskTimeNote=Note
+TaskTimeDate=Date
+TasksOnOpenedProject=Tâches sur projets ouverts
+WorkloadNotDefined=Charge de travail non définie
+NewTimeSpent=Nouveau consommé
+MyTimeSpent=Mon consommé
+Tasks=Tâches
+Task=Tâche
+TaskDateStart=Date de début de tâche
+TaskDateEnd=Date de fin de tâche
+TaskDescription=Description de la tâche
+NewTask=Nouvelle tâche
+AddTask=Créer tâche
+AddTimeSpent=Saisir temps consommé
+Activity=Activité
+Activities=Tâches/activités
+MyActivities=Mes tâches/activités
+MyProjects=Mes projets
+MyProjectsArea=Espace Mes projets
+DurationEffective=Durée effective
+ProgressDeclared=Progression déclarée
+ProgressCalculated=Progression calculée
+Time=Temps
+ListOfTasks=Liste de tâches
+GoToListOfTimeConsumed=Aller à la liste des temps consommés
+GoToListOfTasks=Aller à la liste des tâches
+ListProposalsAssociatedProject=Liste des propositions commerciales associées au projet
+ListOrdersAssociatedProject=Liste des commandes clients associées au projet
+ListInvoicesAssociatedProject=Liste des factures clients associées au projet
+ListPredefinedInvoicesAssociatedProject=Liste des modèles de facture client associées au projet
+ListSupplierOrdersAssociatedProject=Liste des commandes fournisseurs associées au projet
+ListSupplierInvoicesAssociatedProject=Liste des factures fournisseurs associées au projet
+ListContractAssociatedProject=Liste des contrats associés au projet
+ListFichinterAssociatedProject=Liste des interventions associées au projet
+ListShippingAssociatedProject=Liste des expéditions associées au projet
+ListExpenseReportsAssociatedProject=Liste des notes de frais associées avec ce projet
+ListDonationsAssociatedProject=Liste des dons associés au projet
+ListActionsAssociatedProject=Liste des événements associés au projet
+ListTaskTimeUserProject=Liste du temps consommé sur les tâches d'un projet
+ActivityOnProjectToday=Activité projet aujourd'hui
+ActivityOnProjectYesterday=Activité projet hier
+ActivityOnProjectThisWeek=Activité sur les projets cette semaine
+ActivityOnProjectThisMonth=Activité sur les projets ce mois
+ActivityOnProjectThisYear=Activité sur les projets cette année
+ChildOfTask=Fille du projet/tâche
+NotOwnerOfProject=Non responsable de ce projet privé
+AffectedTo=Affecté à
+CantRemoveProject=Ce projet ne peut être supprimé car il est référencé par de nombreux objets (factures, commandes ou autre). voir la liste sur l'onglet Reférents.
+ValidateProject=Valider projet
+ConfirmValidateProject=Êtes-vous sûr de vouloir valider ce projet ?
+CloseAProject=Clore projet
+ConfirmCloseAProject=Êtes-vous sûr de vouloir clore ce projet ?
+AlsoCloseAProject=Fermer également le projet (laissez-le ouvert si vous devez suivre la production de tâches dessus)
+ReOpenAProject=Réouvrir projet
+ConfirmReOpenAProject=Êtes-vous sûr de vouloir rouvrir ce projet ?
+ProjectContact=Contacts projet
+ActionsOnProject=Événements sur le projet
+YouAreNotContactOfProject=Vous n'êtes pas contact de ce projet privé
+DeleteATimeSpent=Suppression du temps consommé
+ConfirmDeleteATimeSpent=Êtes-vous sûr de vouloir supprimer ce temps consommé ?
+DoNotShowMyTasksOnly=Voir aussi les tâches qui ne me sont pas affectées
+ShowMyTasksOnly=Ne voir que les tâches qui me sont affectées
+TaskRessourceLinks=Ressources
+ProjectsDedicatedToThisThirdParty=Projets dédiés à ce tiers
+NoTasks=Aucune tâche pour ce projet
+LinkedToAnotherCompany=Liés à autre société
+TaskIsNotAffectedToYou=Tâche qui ne vous sont pas affectées
+ErrorTimeSpentIsEmpty=Le temps consommé n'est pas renseigné
+ThisWillAlsoRemoveTasks=Cette opération détruira également les tâches du projet (<b>%s</b> tâches actuellement) et le suivi des consommés.
+IfNeedToUseOhterObjectKeepEmpty=Si des objets (facture, commande, ...), appartenant à un autre tiers que celui choisi, doivent être liés au projet à créer, laisser vide afin de laisser le projet multi-tiers.
+CloneProject=Cloner le projet
+CloneTasks=Cloner les tâches
+CloneContacts=Cloner les contacts
+CloneNotes=Cloner les notes
+CloneProjectFiles=Cloner les pièces jointes du projet
+CloneTaskFiles=Cloner les pièces jointes des tâche(s) (si tâche(s) cloner)
+CloneMoveDate=Mettre à jour les dates projet/tâches à partir de maintenant
+ConfirmCloneProject=Êtes-vous sûr de vouloir cloner ce projet ?
+ProjectReportDate=Reporter les dates des tâches en fonction de la date de départ.
+ErrorShiftTaskDate=Une erreur s'est produite dans le report des dates des tâches.
+ProjectsAndTasksLines=Projets et tâches
+ProjectCreatedInDolibarr=Projet %s créé
+ProjectModifiedInDolibarr=Projet %s modifié
+TaskCreatedInDolibarr=Tâche %s créée
+TaskModifiedInDolibarr=Tâche %s modifiée
+TaskDeletedInDolibarr=Tâche %s supprimée
+OpportunityStatus=Statut opportunité
+OpportunityStatusShort=Status opp.
+OpportunityProbability=Probabilité d'opportunité
+OpportunityProbabilityShort=Prob. opp.
+OpportunityAmount=Montant opportunité
+OpportunityAmountShort=Montant Opp.
+OpportunityAmountAverageShort=montant moyen des opportunités
+OpportunityAmountWeigthedShort=Montant pondéré des opportunités
+WonLostExcluded=hors opportunités remportées/perdues
+##### Types de contacts #####
+TypeContact_project_internal_PROJECTLEADER=Chef de projet
+TypeContact_project_external_PROJECTLEADER=Chef de projet
+TypeContact_project_internal_PROJECTCONTRIBUTOR=Contributeur
+TypeContact_project_external_PROJECTCONTRIBUTOR=Contributeur
+TypeContact_project_task_internal_TASKEXECUTIVE=Responsable
+TypeContact_project_task_external_TASKEXECUTIVE=Responsable
+TypeContact_project_task_internal_TASKCONTRIBUTOR=Contributeur
+TypeContact_project_task_external_TASKCONTRIBUTOR=Contributeur
+SelectElement=Séléctionnez l'élément
+AddElement=Associer l'élément
+# Documents models
+DocumentModelBeluga=Modèle de document de rapport pour l'aperçu projet
+DocumentModelBaleine=Modèles de document de rapport de tâches de projets
+PlannedWorkload=Charge de travail prévue
+PlannedWorkloadShort=Charge de travail
+ProjectReferers=Objets associés
+ProjectMustBeValidatedFirst=Le projet doit être validé d'abord
+FirstAddRessourceToAllocateTime=Affecter un utilisateur pour saisir des temps
+InputPerDay=Saisie par jour
+InputPerWeek=Saisie par semaine
+InputPerAction=Saisie par action
+TimeAlreadyRecorded=Temps consommé déjà enregistré pour cette tâche/jour et utilisateur %s
+ProjectsWithThisUserAsContact=Projets avec cet utilisateur comme contact
+TasksWithThisUserAsContact=Tâches assignées à cet utilisateur
+ResourceNotAssignedToProject=Non assigné à un projet
+ResourceNotAssignedToTheTask=Non assigné à la tache
+AssignTaskToMe=M'assigner la tâche
+AssignTask=Assigner
+ProjectOverview=Vue d'ensemble
+ManageTasks=Utiliser les projets pour suivre les tâches
+ManageOpportunitiesStatus=Utiliser les projets pour suivre les affaires / opportunités
+ProjectNbProjectByMonth=Nb de projets créés par mois
+ProjectOppAmountOfProjectsByMonth=Montant des opportunités par mois
+ProjectWeightedOppAmountOfProjectsByMonth=Montant pondéré des opportunités par mois
+ProjectOpenedProjectByOppStatus=Opportunités/affaires ouvertes par statut
+ProjectsStatistics=Statistics sur les projets
+TaskAssignedToEnterTime=Tâche assignée. La saisie de temps sur cette tâche devrait être possible.
+IdTaskTime=Id ligne de temps
+YouCanCompleteRef=SI vous souhaitez compléter la référence avec d'autres informations filtrables, il est recommandé d'ajouter le caractère - entre les données. La numérotation automatique sera alors fonctionnelle pour le prochain compteur. Par exemple %s-ABC. Il est également possible d'ajouter des mots-clés dans le libellé. Il est cependant recommandé d'utiliser un attribut supplémentaire ou extrafield.
+OpenedProjectsByThirdparties=Projets ouverts par tiers
+OnlyOpportunitiesShort=Opportunités uniquement
+OpenedOpportunitiesShort=Opportunités ouvertes
+NotAnOpportunityShort=Non une opportunité
+OpportunityTotalAmount=Montant total des opportunités
+OpportunityPonderatedAmount=Montant pondéré des opportunités
+OpportunityPonderatedAmountDesc=Montant des opportunités pondéré par la probabilité
+OppStatusPROSP=Prospection
+OppStatusQUAL=Qualification
+OppStatusPROPO=Proposition
+OppStatusNEGO=Négociation
+OppStatusPENDING=En attente
+OppStatusWON=Gagné
+OppStatusLOST=Perdu
+Budget=Budget

+ 71 - 0
htdocs/langs/fr_NC/sendings.lang

@@ -0,0 +1,71 @@
+# Dolibarr language file - Source file is en_US - sendings
+RefSending=Réf. expédition
+Sending=Expédition
+Sendings=Expéditions
+AllSendings=Toutes les expéditions
+Shipment=Expédition
+Shipments=Expéditions
+ShowSending=Afficher Expéditions
+Receivings=Bons de réceptions
+SendingsArea=Espace expéditions
+ListOfSendings=Liste des expéditions
+SendingMethod=Méthode d'expédition
+LastSendings=Les %s dernières expéditions
+StatisticsOfSendings=Statistiques des expéditions
+NbOfSendings=Nombre d'expéditions
+NumberOfShipmentsByMonth=Nombre d'expéditions par mois
+SendingCard=Fiche expédition
+NewSending=Nouvelle expédition
+CreateShipment=Créer expédition
+QtyShipped=Qté. expédiée
+QtyPreparedOrShipped=Quantité préparée ou envoyée
+QtyToShip=Qté. à expédier
+QtyReceived=Qté. reçue
+QtyInOtherShipments=Qté dans les autres expéditions
+KeepToShip=Reste à expédier
+OtherSendingsForSameOrder=Autres expéditions pour cette commande
+SendingsAndReceivingForSameOrder=Expéditions et réceptions pour cette commande
+SendingsToValidate=Expéditions à valider
+StatusSendingCanceled=Annulée
+StatusSendingDraft=Brouillon
+StatusSendingValidated=Validée (produits à envoyer ou envoyés)
+StatusSendingProcessed=Traitée
+StatusSendingDraftShort=Brouillon
+StatusSendingValidatedShort=Validée
+StatusSendingProcessedShort=Traitée
+SendingSheet=Fiche expédition
+ConfirmDeleteSending=Êtes-vous sûr de vouloir supprimer cette expédition ?
+ConfirmValidateSending=Êtes-vous sûr de vouloir valider cette expédition sous la référence <b>%s</b>?
+ConfirmCancelSending=Êtes-vous sûr de vouloir annuler cette expédition ?
+DocumentModelSimple=Modèle simple
+DocumentModelMerou=Modèle Merou A5
+WarningNoQtyLeftToSend=Alerte, aucun produit en attente d'expédition.
+StatsOnShipmentsOnlyValidated=Statistiques effectuées sur les expéditions validées uniquement. La date prise en compte est la date de validation (la date de prévision de livraison n'étant pas toujours renseignée).
+DateDeliveryPlanned=Date prévue de livraison
+RefDeliveryReceipt=Ref bon de réception
+StatusReceipt=Status du bon de réception
+DateReceived=Date de réception réelle
+SendShippingByEMail=Envoyer bon d'expédition par email
+SendShippingRef=Envoi du bordereau d'expédition %s
+ActionsOnShipping=Événements sur l'expédition
+LinkToTrackYourPackage=Lien pour le suivi de votre colis
+ShipmentCreationIsDoneFromOrder=Pour le moment, la création d'une nouvelle expédition se fait depuis la fiche commande.
+ShipmentLine=Ligne d'expédition
+ProductQtyInCustomersOrdersRunning=Quantité de produit en commandes client ouvertes
+ProductQtyInSuppliersOrdersRunning=Quantité de produit en commandes fournisseur ouvertes
+ProductQtyInShipmentAlreadySent=Quantité du produit parmi les commandes clients déjà envoyées
+ProductQtyInSuppliersShipmentAlreadyRecevied=Quantité de produit déjà reçu en commandes fournisseur ouvertes
+NoProductToShipFoundIntoStock=Aucun produit à expédier n'a été trouver dans l'entrepôt <b>%s</b>. Corrigez l'inventaire ou retourner choisir un autre entrepôt.
+WeightVolShort=Poids/vol.
+ValidateOrderFirstBeforeShipment=Vous devez d'abord valider la commande pour pouvoir créer une expédition.
+
+# Sending methods
+# ModelDocument
+DocumentModelTyphon=Modèle de bon de réception/livraison complet (logo…)
+Error_EXPEDITION_ADDON_NUMBER_NotDefined=Constante EXPEDITION_ADDON_NUMBER non définie
+SumOfProductVolumes=Somme des volumes des produits
+SumOfProductWeights=Somme des poids des produits
+
+# warehouse details
+DetailWarehouseNumber= Détail de l'entrepôt
+DetailWarehouseFormat= W:%s (Qté : %d)

+ 277 - 24
htdocs/modulebuilder/skeletons/skeleton_card.php

@@ -297,52 +297,305 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea
 {
     $res = $object->fetch_optionals($object->id, $extralabels);
 
-	$head = commande_prepare_head($object);
-	dol_fiche_head($head, 'order', $langs->trans("CustomerOrder"), 0, 'order');
+	$head = mymodule_prepare_head($object);
+	dol_fiche_head($head, 'order', $langs->trans("CustomerOrder"), -1, 'order');
 		
-	print load_fiche_titre($langs->trans("MyModule"));
-    
-	dol_fiche_head();
-
+	$formconfirm = '';
+	
+	// Confirmation to delete
 	if ($action == 'delete') {
-		$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteMyOjbect'), $langs->trans('ConfirmDeleteMyObject'), 'confirm_delete', '', 0, 1);
-		print $formconfirm;
+	    $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteOrder'), $langs->trans('ConfirmDeleteOrder'), 'confirm_delete', '', 0, 1);
 	}
 	
+	// Confirmation of action xxxx
+	if ($action == 'xxx')
+	{
+	    $formquestion=array();
+	    /*
+	        $formquestion = array(
+	            // 'text' => $langs->trans("ConfirmClone"),
+	            // array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneMainAttributes"), 'value' => 1),
+	            // array('type' => 'checkbox', 'name' => 'update_prices', 'label' => $langs->trans("PuttingPricesUpToDate"), 'value' => 1),
+	            // array('type' => 'other',    'name' => 'idwarehouse',   'label' => $langs->trans("SelectWarehouseForStockDecrease"), 'value' => $formproduct->selectWarehouses(GETPOST('idwarehouse')?GETPOST('idwarehouse'):'ifone', 'idwarehouse', '', 1)));
+	    }*/	
+	    $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('XXX'), $text, 'confirm_xxx', $formquestion, 0, 1, 220);
+	}
+	
+	if (! $formconfirm) {
+	    $parameters = array('lineid' => $lineid);
+	    $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
+	    if (empty($reshook)) $formconfirm.=$hookmanager->resPrint;
+	    elseif ($reshook > 0) $formconfirm=$hookmanager->resPrint;
+	}
+	
+	// Print form confirm
+	print $formconfirm;
+	
+	
+	
+	// Object card
+	// ------------------------------------------------------------
+	
+	$linkback = '<a href="' . DOL_URL_ROOT . '/mymodule/list.php' . (! empty($socid) ? '?socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	
+	
+	$morehtmlref='<div class="refidno">';
+	/*
+	// Ref bis
+	$morehtmlref.=$form->editfieldkey("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->creer, 'string', '', 0, 1);
+	$morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->mymodule->creer, 'string', '', null, null, '', 1);
+	// Thirdparty
+	$morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
+	// Project
+	if (! empty($conf->projet->enabled))
+	{
+	    $langs->load("projects");
+	    $morehtmlref.='<br>'.$langs->trans('Project') . ' ';
+	    if ($user->rights->mymodule->creer)
+	    {
+	        if ($action != 'classify')
+	        {
+	            $morehtmlref.='<a href="' . $_SERVER['PHP_SELF'] . '?action=classify&amp;id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
+	            if ($action == 'classify') {
+	                //$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
+	                $morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
+	                $morehtmlref.='<input type="hidden" name="action" value="classin">';
+	                $morehtmlref.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+	                $morehtmlref.=$formproject->select_projects($object->socid, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
+	                $morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
+	                $morehtmlref.='</form>';
+	            } else {
+	                $morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
+	            }
+	        }
+	    } else {
+	        if (! empty($object->fk_project)) {
+	            $proj = new Project($db);
+	            $proj->fetch($object->fk_project);
+	            $morehtmlref.='<a href="'.DOL_URL_ROOT.'/projet/card.php?id=' . $object->fk_project . '" title="' . $langs->trans('ShowProject') . '">';
+	            $morehtmlref.=$proj->ref;
+	            $morehtmlref.='</a>';
+	        } else {
+	            $morehtmlref.='';
+	        }
+	    }
+	}
+	*/
+	$morehtmlref.='</div>';
+	
+	
+	dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
+	
+	
+	print '<div class="fichecenter">';
+	print '<div class="fichehalfleft">';
+	print '<div class="underbanner clearboth"></div>';
 	print '<table class="border centpercent">'."\n";
 	// print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td>'.$object->label.'</td></tr>';
 	// LIST_OF_TD_LABEL_FIELDS_VIEW
+
+
+	// Other attributes
+	$cols = 2;
+	include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
+
 	print '</table>';
+	print '</div>';
+	print '<div class="fichehalfright">';
+	print '<div class="ficheaddleft">';
+	print '<div class="underbanner clearboth"></div>';
+	print '<table class="border centpercent">';
+	
+	
+
+	print '</table>';
+	print '</div>';
+	print '</div>';
+	print '</div>';
+	
+	print '<div class="clearboth"></div><br>';
 	
 	dol_fiche_end();
 
 
-	// Buttons
-	print '<div class="tabsAction">'."\n";
-	$parameters=array();
-	$reshook=$hookmanager->executeHooks('addMoreActionsButtons',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
-	if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+	// Buttons for actions
+	if ($action != 'presend' && $action != 'editline') {
+    	print '<div class="tabsAction">'."\n";
+    	$parameters=array();
+    	$reshook=$hookmanager->executeHooks('addMoreActionsButtons',$parameters,$object,$action);    // Note that $action and $object may have been modified by hook
+    	if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+    
+    	if (empty($reshook))
+    	{
+    		if ($user->rights->mymodule->write)
+    		{
+    			print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=edit">'.$langs->trans("Modify").'</a></div>'."\n";
+    		}
+    
+    		if ($user->rights->mymodule->delete)
+    		{
+    			print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=delete">'.$langs->trans('Delete').'</a></div>'."\n";
+    		}
+    	}
+    	print '</div>'."\n";
+	}
+
+	
+	// Select mail models is same action as presend
+	if (GETPOST('modelselected')) {
+	    $action = 'presend';
+	}
+	
+	if ($action != 'presend')
+	{
+	    print '<div class="fichecenter"><div class="fichehalfleft">';
+	    print '<a name="builddoc"></a>'; // ancre
+	    // Documents
+	    $comref = dol_sanitizeFileName($object->ref);
+	    $relativepath = $comref . '/' . $comref . '.pdf';
+	    $filedir = $conf->mymodule->dir_output . '/' . $comref;
+	    $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
+	    $genallowed = $user->rights->mymodule->creer;
+	    $delallowed = $user->rights->mymodule->supprimer;
+	    print $formfile->showdocuments('mymodule', $comref, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
+	
+	
+	    // Show links to link elements
+	    $linktoelem = $form->showLinkToObjectBlock($object, null, array('order'));
+	    $somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
+	
+	
+	    print '</div><div class="fichehalfright"><div class="ficheaddleft">';
+	
+	    // List of actions on element
+	    include_once DOL_DOCUMENT_ROOT . '/core/class/html.formactions.class.php';
+	    $formactions = new FormActions($db);
+	    $somethingshown = $formactions->showactions($object, 'order', $socid);
+	
+	    print '</div></div></div>';
+	}
+	
 
-	if (empty($reshook))
+	/*
+	 * Action presend
+	 */
+    /*
+	if ($action == 'presend')
 	{
-		if ($user->rights->mymodule->write)
+		$object->fetch_projet();
+
+		$ref = dol_sanitizeFileName($object->ref);
+		include_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
+		$fileparams = dol_most_recent_file($conf->commande->dir_output . '/' . $ref, preg_quote($ref, '/').'[^\-]+');
+		$file = $fileparams['fullname'];
+
+		// Define output language
+		$outputlangs = $langs;
+		$newlang = '';
+		if ($conf->global->MAIN_MULTILANGS && empty($newlang) && ! empty($_REQUEST['lang_id']))
+			$newlang = $_REQUEST['lang_id'];
+		if ($conf->global->MAIN_MULTILANGS && empty($newlang))
+			$newlang = $object->thirdparty->default_lang;
+
+		if (!empty($newlang))
 		{
-			print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=edit">'.$langs->trans("Modify").'</a></div>'."\n";
+			$outputlangs = new Translate('', $conf);
+			$outputlangs->setDefaultLang($newlang);
+			$outputlangs->load('commercial');
 		}
 
-		if ($user->rights->mymodule->delete)
+		// Build document if it not exists
+		if (! $file || ! is_readable($file)) {
+			$result = $object->generateDocument(GETPOST('model') ? GETPOST('model') : $object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
+			if ($result <= 0) {
+				dol_print_error($db, $object->error, $object->errors);
+				exit();
+			}
+			$fileparams = dol_most_recent_file($conf->commande->dir_output . '/' . $ref, preg_quote($ref, '/').'[^\-]+');
+			$file = $fileparams['fullname'];
+		}
+
+		print '<div id="formmailbeforetitle" name="formmailbeforetitle"></div>';
+		print '<div class="clearboth"></div>';
+		print '<br>';
+		print load_fiche_titre($langs->trans('SendOrderByMail'));
+
+		dol_fiche_head('');
+
+		// Cree l'objet formulaire mail
+		include_once DOL_DOCUMENT_ROOT . '/core/class/html.formmail.class.php';
+		$formmail = new FormMail($db);
+		$formmail->param['langsmodels']=(empty($newlang)?$langs->defaultlang:$newlang);
+        $formmail->fromtype = (GETPOST('fromtype')?GETPOST('fromtype'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user'));
+
+        if($formmail->fromtype === 'user'){
+            $formmail->fromid = $user->id;
+
+        }
+		$formmail->trackid='ord'.$object->id;
+		if (! empty($conf->global->MAIN_EMAIL_ADD_TRACK_ID) && ($conf->global->MAIN_EMAIL_ADD_TRACK_ID & 2))	// If bit 2 is set
 		{
-			print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&amp;action=delete">'.$langs->trans('Delete').'</a></div>'."\n";
+			include DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+			$formmail->frommail=dolAddEmailTrackId($formmail->frommail, 'ord'.$object->id);
 		}
-	}
-	print '</div>'."\n";
+		$formmail->withfrom = 1;
+		$liste = array();
+		foreach ($object->thirdparty->thirdparty_and_contact_email_array(1) as $key => $value)
+			$liste [$key] = $value;
+		$formmail->withto = GETPOST('sendto') ? GETPOST('sendto') : $liste;
+		$formmail->withtocc = $liste;
+		$formmail->withtoccc = $conf->global->MAIN_EMAIL_USECCC;
+		if (empty($object->ref_client)) {
+			$formmail->withtopic = $outputlangs->trans('SendOrderRef', '__ORDERREF__');
+		} else if (! empty($object->ref_client)) {
+			$formmail->withtopic = $outputlangs->trans('SendOrderRef', '__ORDERREF__ (__REFCLIENT__)');
+		}
+		$formmail->withfile = 2;
+		$formmail->withbody = 1;
+		$formmail->withdeliveryreceipt = 1;
+		$formmail->withcancel = 1;
+		// Tableau des substitutions
+		$formmail->setSubstitFromObject($object);
+		$formmail->substit ['__ORDERREF__'] = $object->ref;
+
+		$custcontact = '';
+		$contactarr = array();
+		$contactarr = $object->liste_contact(- 1, 'external');
+
+		if (is_array($contactarr) && count($contactarr) > 0)
+		{
+			foreach ($contactarr as $contact)
+			{
+				if ($contact['libelle'] == $langs->trans('TypeContact_commande_external_CUSTOMER')) {	// TODO Use code and not label
+					$contactstatic = new Contact($db);
+					$contactstatic->fetch($contact ['id']);
+					$custcontact = $contactstatic->getFullName($langs, 1);
+				}
+			}
 
+			if (! empty($custcontact)) {
+				$formmail->substit['__CONTACTCIVNAME__'] = $custcontact;
+			}
+		}
+
+		// Tableau des parametres complementaires
+		$formmail->param['action'] = 'send';
+		$formmail->param['models'] = 'order_send';
+		$formmail->param['models_id']=GETPOST('modelmailselected','int');
+		$formmail->param['orderid'] = $object->id;
+		$formmail->param['returnurl'] = $_SERVER["PHP_SELF"] . '?id=' . $object->id;
+
+		// Init list of files
+		if (GETPOST("mode") == 'init') {
+			$formmail->clear_attached_files();
+			$formmail->add_attached_files($file, basename($file), dol_mimetype($file));
+		}
 
-	// Example 2 : Adding links to objects
-	// Show links to link elements
-	//$linktoelem = $form->showLinkToObjectBlock($object, null, array('skeleton'));
-	//$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
+		// Show form
+		print $formmail->get_form();
 
+		dol_fiche_end();
+	}*/
 }
 
 

+ 132 - 89
htdocs/product/inventory/listview.class.php

@@ -39,6 +39,8 @@ class Listview
 		$this->form = null;
 		$this->totalRowToShow=0;
 		$this->totalRow=0;
+		
+		$this->TField=array();
 	}
 
     /**
@@ -70,14 +72,15 @@ class Listview
 			,'head_search'=>''
 			,'export'=>array()
 			,'view_type'=>''
+			,'massactions'=>array()
 		),$TParam['list']);
 		
 		if (empty($TParam['limit'])) $TParam['limit'] = array();
 		
 		$page = GETPOST('page');
-		if (!empty($page)) $TParam['limit']['page'] = $page+1; // TODO dolibarr start page at 0 instead 1
+		if (!empty($page)) $TParam['limit']['page'] = $page;
 		
-		$TParam['limit'] = array_merge(array('page'=>1, 'nbLine' => $conf->liste_limit, 'global'=>0), $TParam['limit']);
+		$TParam['limit'] = array_merge(array('page'=>0, 'nbLine' => $conf->liste_limit, 'global'=>0), $TParam['limit']);
 		
 		if (GETPOST('sortfield'))
 		{
@@ -137,17 +140,6 @@ class Listview
 		
 		return $TKey;
 	}
-
-    /**
-     * @param timestamp    $date   date to convert
-     * @return int|string   Date TMS or ''
-     */
-    private function dateToSQLDate($date)
-    {
-		return $this->db->idate($date);
-	}
-
-
     /**
      * @param string     $TSQLMore   contain some additional sql instructions
      * @param string    $value      date with read format
@@ -160,13 +152,11 @@ class Listview
 			$TSQLDate=array();
 			if(!empty($value['start']))
 			{
-//				$valueDeb = $this->dateToSQLDate($value['start'].' 00:00:00');
 				$TSQLDate[]=$sKey." >= '".$value['start']."'" ;
 			}
 
 			if(!empty($value['end']))
 			{
-//				$valueFin = $this->dateToSQLDate($value['end'].' 23:59:59');
 				$TSQLDate[]=$sKey." <= '".$value['end']."'" ;
 			}
 
@@ -174,7 +164,6 @@ class Listview
 		}
 		else
 		{
-//			$value = $this->dateToSQLDate($value);
 			$TSQLMore[]=$sKey." LIKE '".$value."%'" ;
 		}
 	}
@@ -227,9 +216,7 @@ class Listview
      */
     private function search($sql, &$TParam)
     {
-		$ListPOST = GETPOST('Listview');
-		
-		if (!GETPOST("button_removefilter_x") && !GETPOST("button_removefilter.x") && !GETPOST("button_removefilter"))
+		if (empty($TParam['no-auto-sql-search']) && !GETPOST("button_removefilter_x") && !GETPOST("button_removefilter.x") && !GETPOST("button_removefilter"))
 		{
 			foreach ($TParam['search'] as $field => $info)
 			{
@@ -237,12 +224,14 @@ class Listview
 				$TSQLMore = array();
 				$allow_is_null = $this->getSearchNull($field,$TParam);
 				
+				$fieldname = !empty($info['fieldname']) ? $info['fieldname'] : 'Listview_'.$this->id.'_search_'.$field;
+				
 				foreach ($TsKey as $i => &$sKey)
 				{
-					$value = '';
-					if (isset($ListPOST[$this->id]['search'][$field])) $value = $ListPOST[$this->id]['search'][$field];
+					$value = GETPOST($fieldname);
+					$value_null = GETPOST('Listview_'.$this->id.'_search_on_null_'.$field);
 					
-					if ($allow_is_null && !empty($ListPOST[$this->id]['search_on_null'][$field]))
+					if ($allow_is_null && !empty($value_null))
 					{
 						$TSQLMore[] = $sKey.' IS NULL ';
 						$value = '';
@@ -250,7 +239,7 @@ class Listview
 					
 					if (isset($TParam['type'][$field]) && ($TParam['type'][$field]==='date' || $TParam['type'][$field]==='datetime'))
 					{
-						$k = 'Listview_'.$this->id.'_search_'.$field;
+						$k = $fieldname;
 						if ($info['search_type'] === 'calendars')
 						{
 							$value = array();
@@ -296,25 +285,22 @@ class Listview
     {
         global $conf;
         
-		$TField=array();
+        $TField= & $this->TField;
 		
 		$this->init($TParam);
 
         $THeader = $this->initHeader($TParam);
 		
 		$sql = $this->search($sql,$TParam);
-		$sql.= $this->db->order($TParam['param']['sortfield'], $TParam['param']['sortorder']);
-
-		$nbtotalofrecords = '';
+		$sql.= $this->db->order($TParam['sortfield'], $TParam['sortorder']);
+	
 		if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 		{
 		    $result = $this->db->query($sql);
-		    $nbtotalofrecords = $this->db->num_rows($result);
+		    $this->totalRow = $this->db->num_rows($result);
 		}
-		$sql.= $this->db->plimit($TParam['param']['limit'] + 1, $TParam['param']['offset']);
 		
 		$this->parse_sql($THeader, $TField, $TParam, $sql);
-		
 		list($TTotal, $TTotalGroup)=$this->get_total($TField, $TParam);
 		
 		return $this->renderList($THeader, $TField, $TTotal, $TTotalGroup, $TParam);
@@ -335,44 +321,42 @@ class Listview
 		
 		$nb_search_in_bar = 0;
 		
-		if(!empty($TParam['search']))
+		foreach($THeader as $key => $libelle)
 		{
-			foreach($THeader as $key => $libelle)
-			{
-				if(empty($TSearch[$key]))$TSearch[$key]='';
-			}
-		}	
+			if(empty($TSearch[$key]))$TSearch[$key]='';
+		}
 		
-		$ListPOST = GETPOST('Listview');
 		$removeFilter = (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter"));
 		foreach($TParam['search'] as $key => $param_search)
 		{
-			$value = isset($ListPOST[$this->id]['search'][$key]) ? $ListPOST[$this->id]['search'][$key] : '';
 			if ($removeFilter) $value = '';
 			
 			$typeRecherche = (is_array($param_search) && isset($param_search['search_type'])) ? $param_search['search_type'] : $param_search;  
 			
+			$fieldname = !empty($param_search['fieldname']) ? $param_search['fieldname'] : 'Listview_'.$this->id.'_search_'.$key;
+			$value = $removeFilter ? '' : GETPOST($fieldname);
+			
 			if(is_array($typeRecherche))
 			{
-				$fsearch=$form->selectarray('Listview['.$this->id.'][search]['.$key.']', $typeRecherche,$value,1);
+				$fsearch=$form->selectarray($fieldname, $typeRecherche,$value,1);
 			}
 			else if($typeRecherche==='calendar')
 			{
-				if (!$removeFilter) $value = GETPOST('Listview_'.$this->id.'_search_'.$key) ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'month'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'day'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'year') ) : '';
+				if (!$removeFilter) $value = GETPOST($fieldname) ? mktime(0,0,0, (int) GETPOST($fieldname.'month'), (int) GETPOST($fieldname.$key.'day'), (int) GETPOST($fieldname.'year') ) : '';
 				
-				$fsearch = $form->select_date($value, 'Listview_'.$this->id.'_search_'.$key,0, 0, 1, "", 1, 0, 1);
+				$fsearch = $form->select_date($value, $fieldname,0, 0, 1, "", 1, 0, 1);
 			}
 			else if($typeRecherche==='calendars')
 			{
 				$value_start = $value_end = '';
 				if (!$removeFilter)
 				{
-					$value_start = GETPOST('Listview_'.$this->id.'_search_'.$key.'_start') ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startmonth'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startday'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_startyear') ) : '';
-					$value_end = GETPOST('Listview_'.$this->id.'_search_'.$key.'_end') ? mktime(0,0,0, (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endmonth'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endday'), (int) GETPOST('Listview_'.$this->id.'_search_'.$key.'_endyear') ) : '';
+					$value_start = GETPOST($fieldname.'_start') ? mktime(0,0,0, (int) GETPOST($fieldname.'_startmonth'), (int) GETPOST($fieldname.'_startday'), (int) GETPOST($fieldname.'_startyear') ) : '';
+					$value_end = GETPOST($fieldname.'_end') ? mktime(0,0,0, (int) GETPOST($fieldname.'_endmonth'), (int) GETPOST($fieldname.'_endday'), (int) GETPOST($fieldname.'_endyear') ) : '';
 				}
 			
-				$fsearch = $form->select_date($value_start, 'Listview_'.$this->id.'_search_'.$key.'_start',0, 0, 1, "", 1, 0, 1)
-						 . $form->select_date($value_end, 'Listview_'.$this->id.'_search_'.$key.'_end',0, 0, 1, "", 1, 0, 1);
+				$fsearch = $form->select_date($value_start,$fieldname.'_start',0, 0, 1, "", 1, 0, 1)
+				. $form->select_date($value_end, $fieldname.'_end',0, 0, 1, "", 1, 0, 1);
 				
 			}
 			else if(is_string($typeRecherche))
@@ -381,13 +365,13 @@ class Listview
 			}
 			else
             {
-				$fsearch='<input type="text" name="Listview['.$this->id.'][search]['.$key.']" id="Listview['.$this->id.'][search]['.$key.']" value="'.$value.'" size="15" />';
+            	$fsearch='<input type="text" name="'.$fieldname.'" id="'.$fieldname.'" value="'.$value.'" size="10" />';
 			}
 
 			if(!empty($param_search['allow_is_null']))
 			{
-				$valueNull = isset($ListPOST[$this->id]['search_on_null'][$key]) ? 1 : 0;
-				$fsearch.=' '.$form->checkbox1('', 'Listview['.$this->id.'][search_on_null]['.$key.']',1, $valueNull,' onclick=" if($(this).is(\':checked\')){ $(this).prev().val(\'\'); }" ').img_help(1, $langs->trans('SearchOnNUllValue'));
+				$valueNull = GETPOST($fieldname.'search_on_null_'.$key) ? 1 : 0;
+				$fsearch.=' '.$form->checkbox1('', $fieldname.'search_on_null_'.$key,1, $valueNull,' onclick=" if($(this).is(\':checked\')){ $(this).prev().val(\'\'); }" ').img_help(1, $langs->trans('SearchOnNUllValue'));
 			}
 
 			if(!empty($THeader[$key]))
@@ -395,20 +379,10 @@ class Listview
 				$TSearch[$key] = $fsearch;
 				$nb_search_in_bar++;
 			}
-			else
-            {
-				$label = !empty($TParam['title'][$key]) ? $TParam['title'][$key] : $key ;
-				$TParam['list']['head_search'].= '<th>'.$label.'</th>';
-//				$TParam['list']['head_search'].='<div><span style="min-width:200px;display:inline-block;">'.$label.'</span> '.$fsearch.'</div>';	
-			}
 		}
 		
 		$search_button = ' <a href="#" onclick="Listview_submitSearch(this);" class="list-search-link">'.img_search().'</a>';
-
-		if(!empty($TParam['list']['head_search']))
-		{
-			$TParam['list']['head_search']='<div style="float:right;">'.$search_button.'</div>'.$TParam['list']['head_search'];
-		}
+		$search_button .= ' <a href="#" onclick="Listview_clearSearch(this);" class="list-search-link">'.img_searchclear().'</a>';
 		
 		if($nb_search_in_bar>0)
 		{
@@ -603,7 +577,7 @@ class Listview
      */
     private function renderList(&$THeader, &$TField, &$TTotal, &$TTotalGroup, &$TParam)
     {
-		global $bc;
+		global $bc,$form;
 		
 		$TSearch = $this->setSearch($THeader, $TParam);
 		$TExport = $this->setExport($TParam, $TField, $THeader);
@@ -611,13 +585,24 @@ class Listview
 		
 		//$out = $this->getJS();
 		
+		$massactionbutton= empty($TParam['list']['massactions']) ? '' : $form->selectMassAction('', $TParam['list']['massactions']);
+		
 		$dolibarr_decalage = $this->totalRow > $this->totalRowToShow ? 1 : 0;
 		ob_start();
-		print_barre_liste($TParam['list']['title'], $TParam['limit']['page']-1, $_SERVER["PHP_SELF"], '&'.$TParam['list']['param_url'], $TParam['sortfield'], $TParam['sortorder'], '', $this->totalRowToShow+$dolibarr_decalage, $this->totalRow, $TParam['list']['image'], 0, '', '', $TParam['limit']['nbLine']);
+		print_barre_liste($TParam['list']['title'], $TParam['limit']['page'], $_SERVER["PHP_SELF"], '&'.$TParam['list']['param_url'], $TParam['sortfield'], $TParam['sortorder'], $massactionbutton, $this->totalRowToShow+$dolibarr_decalage, $this->totalRow, $TParam['list']['image'], 0, '', '', $TParam['limit']['nbLine']);
 		$out .= ob_get_clean();
 		
+		$classliste='liste';
+		if(!empty($TParam['head_search'])) {
+			$out.='<div class="liste_titre liste_titre_bydiv centpercent">';
+			$out.=$TParam['head_search'];
+			$out.='</div>';
+			
+			$classliste.=' listwithfilterbefore';
+		}
 	
-		$out.= '<table id="'.$this->id.'" class="liste" width="100%"><thead>';
+		$out.= '<div class="div-table-responsive">';
+		$out.= '<table id="'.$this->id.'" class="'.$classliste.'" width="100%"><thead>';
 			
     	if(count($TSearch)>0)
 		{
@@ -627,12 +612,12 @@ class Listview
 			{
 				if ($field === 'selectedfields')
 				{
-					$out.= '<td class="liste_titre" align="right">'.$this->form->showFilterAndCheckAddButtons(0).'</td>';
+					$out.= '<th class="liste_titre" align="right">'.$this->form->showFilterAndCheckAddButtons(0).'</th>';
 				}
 				else
 				{
 					$moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"';
-					$out .= '<td class="liste_titre" '.$moreattrib.'>'.$TSearch[$field].'</td>';
+					$out .= '<th class="liste_titre" '.$moreattrib.'>'.$TSearch[$field].'</th>';
 				}
 			}
 			
@@ -646,10 +631,17 @@ class Listview
 			$search = '';
 			$prefix = '';
 
+			$label = $head['label'];
+			
 			if ($field === 'selectedfields')
 			{
 				$moreattrib = 'align="right" ';
 				$prefix = 'maxwidthsearch ';
+
+				if(!empty($TParam['list']['massactions'])) {
+					$label.=$form->showCheckAddButtons('checkforselect', 1);
+				}
+				
 			}
 
 			if (empty($head['width'])) $head['width'] = 'auto';
@@ -662,10 +654,10 @@ class Listview
 				else $search = $field;
 			}
 
-			$out .= getTitleFieldOfList($head['label'], 0, $_SERVER["PHP_SELF"], $search, '', $moreparam, $moreattrib, $TParam['sortfield'], $TParam['sortorder'], $prefix);
+			$out .= getTitleFieldOfList($label, 0, $_SERVER["PHP_SELF"], $search, '', $moreparam, $moreattrib, $TParam['sortfield'], $TParam['sortorder'], $prefix);
 			$out .= $head['more'];
 		}
-		
+
 		//$out .= '<th aligne="right" class="maxwidthsearch liste_titre">--</th>';
 		$out .= '</tr>';
 		
@@ -673,23 +665,34 @@ class Listview
 		
 		if(empty($TField))
 		{
-			if (!empty($TParam['list']['messageNothing'])) $out .= '<tr class="oddeven"><td colspan="'.(count($TParam['title'])+1).'"><span class="opacitymedium">'.$TParam['list']['messageNothing'].'</span></td></tr>';
+			if (!empty($TParam['list']['messageNothing'])) $out .= '<tr class="oddeven"><td colspan="'.(count($THeader)+1).'"><span class="opacitymedium">'.$TParam['list']['messageNothing'].'</span></td></tr>';
 		}
 		else
         {
-			$var=true;
 			$line_number = 0;
 			foreach($TField as $fields)
 			{
 				if($this->in_view($TParam, $line_number))
 				{
-					$var=!$var;
-					$out.='<tr '.$bc[$var].'> <!-- '.$field.' -->';
+					$out.='<tr class="oddeven"> <!-- '.$field.' -->';
 
 					foreach ($THeader as $field => $head)
 					{
+						$value_aff =(isset($fields[$field]) ? $fields[$field] : '&nbsp;');
+						
+						if ($field === 'selectedfields')
+						{
+							$head['text-align']='center';
+							if(!empty($TParam['list']['massactions'])) {
+								$arrayofselected=array(); // TODO get in param
+								$selected=0;
+								if (in_array($obj->rowid, $arrayofselected)) $selected=1;
+								$value_aff.='<input id="cb'.$fields['rowid'].'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$fields['rowid'].'"'.($selected?' checked="checked"':'').'>';
+							}
+						}
+						
 						$moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"';
-						$out.='<td class="'.$field.'" '.$moreattrib.'>'.$fields[$field].'</td>';
+						$out.='<td class="'.$field.'" '.$moreattrib.'>'.$value_aff.'</td>';
 					}
 
 					$out.='</tr>';
@@ -718,6 +721,7 @@ class Listview
 		}
 
 		$out .= '</table>';
+		$out .= '</div>';
 		
 		return $out;
 	}
@@ -760,7 +764,7 @@ class Listview
 		
 		foreach($TField as $row)
 		{
-			$this->set_line($TField, $TParam, $row);
+			$this->set_line($THeader, $TField, $TParam, $row);
 		}
 	}
 
@@ -778,7 +782,7 @@ class Listview
 		}
 		
 		$contextpage=md5($_SERVER['PHP_SELF']);
-		if(!empty($TParam['allow-field-select']))
+		if(!empty($TParam['allow-fields-select']))
 		{
 			$selectedfields = GETPOST('Listview'.$this->id.'_selectedfields');
 			
@@ -839,18 +843,25 @@ class Listview
 					'order'=>(in_array($field, $TParam['orderby']['noOrder']) ? 0 : 1),
 					'width'=>(!empty($TParam['size']['width'][$field]) ? $TParam['size']['width'][$field] : 'auto'),
 					'text-align'=>(!empty($TParam['position']['text-align'][$field]) ? $TParam['position']['text-align'][$field] : 'auto'),
+					'rank'=>(!empty($TParam['position']['rank'][$field]) ? $TParam['position']['rank'][$field] : 0),
 					'more'=>''
 				);
 			}
 		}
 		
-		if(!empty($selectedfields))
-		{
-			$THeader['selectedfields']['label']='<div style="float:right">'.$selectedfields.'</div>';
-		}
+		uasort($THeader,array('Listview','sortHeaderRank'));
+		
+		$THeader['selectedfields']['label']=$selectedfields;
 		
 		return $THeader;
 	}
+	
+	public function sortHeaderRank(&$a, &$b) {
+		if($a['rank']>$b['rank']) return 1;
+		else if($a['rank']<$b['rank']) return -1;
+		else return 0;
+		
+	}
 
     /**
      * @param string $TParam        TParam
@@ -874,11 +885,14 @@ class Listview
 	}
 
     /**
-     * @param string $TField        TField
-     * @param string $TParam        TParam
-     * @param string $currentLine   aaa
+     * Apply function to result and set fields array
+     * 
+     * @param string $THeader       array of headers
+     * @param string $TField        array of fields
+     * @param string $TParam        array of parameters
+     * @param string $currentLine   object containing current sql result
      */
-    private function set_line(&$TField, &$TParam, $currentLine)
+    private function set_line(&$THeader, &$TField, &$TParam, $currentLine)
     {
         global $conf;
 
@@ -887,16 +901,21 @@ class Listview
         if($this->in_view($TParam,$line_number))
         {
 			$this->totalRowToShow++;
-            $row=array(); $trans = array();
-            foreach($currentLine as $field=>$value)
+            $row=array(); 
+            $trans = array();
+            foreach($currentLine as $kF=>$vF)$trans['@'.$kF.'@'] = addslashes($vF);
+            
+            foreach($THeader as $field=>$dummy)
             {
+            	$value = isset($currentLine->{$field}) ? $currentLine->{$field}: '';
+            	
                 if(is_object($value))
                 {
                     if(get_class($value)=='stdClass') {$value=print_r($value, true);}
                     else $value=(string) $value;
                 }
 
-                $trans['@'.$field.'@'] = $value;
+                $trans['@'.$field.'@'] = addslashes($value);
 
                 if(!empty($TParam['math'][$field]))
                 {
@@ -910,17 +929,19 @@ class Listview
 
                     if(isset($TParam['eval'][$field]) && in_array($field,array_keys($row)))
                     {
-                        $strToEval = 'return '.strtr( $TParam['eval'][$field],  array_merge( $trans, array('@val@'=>$row[$field])  )).';';
+                        $strToEval = 'return '.strtr( $TParam['eval'][$field],  array_merge( $trans, array('@val@'=>addslashes( $row[$field] ))  )).';';
                         $row[$field] = eval($strToEval);
+                        
                     }
 
                     if(isset($TParam['type'][$field]) && !isset($TParam['eval'][$field]))
                     {
                         if($TParam['type'][$field]=='date' || $TParam['type'][$field]=='datetime' )
                         {
+                        
                             if($row[$field] != '0000-00-00 00:00:00' && $row[$field] != '1000-01-01 00:00:00' && $row[$field] != '0000-00-00' && !empty($row[$field]))
                             {
-                                if($TParam['type'][$field]=='datetime')$row[$field] = dol_print_date(strtotime($row[$field]),'dayhoursec');
+                                if($TParam['type'][$field]=='datetime')$row[$field] = dol_print_date(strtotime($row[$field]),'dayhour');
                                 else $row[$field] = dol_print_date(strtotime($row[$field]),'day');
                             }
                             else
@@ -996,6 +1017,8 @@ class Listview
 		{
 			$sql.=' LIMIT '.(int) $TParam['limit']['global'];
 		}
+		else if(!empty($TParam['limit'])) $sql.= $this->db->plimit($TParam['limit']['nbLine']+1, $TParam['limit']['page'] * $TParam['limit']['nbLine']);
+		
 		
 		return $sql;
 	}
@@ -1008,7 +1031,7 @@ class Listview
      */
     private function parse_sql(&$THeader, &$TField, &$TParam, $sql)
     {
-		$this->sql = $this->limitSQL($sql, $TParam);
+    	$this->sql = $this->limitSQL($sql, $TParam);
 		
 		$this->TTotalTmp=array();
 		$this->THideFlip = array_flip($TParam['hide']);
@@ -1016,12 +1039,13 @@ class Listview
 		$res = $this->db->query($this->sql);
 		if($res!==false)
 		{
-			$this->totalRow = $this->db->num_rows($res);
 			dol_syslog(get_class($this)."::parse_sql id=".$this->id." sql=".$this->sql, LOG_DEBUG);
 			
+			if(empty($this->totalRow))$this->totalRow = $this->db->num_rows($res);
+			
 			while($currentLine = $this->db->fetch_object($res))
             {
-				$this->set_line($TField, $TParam, $currentLine);
+				$this->set_line($THeader, $TField, $TParam, $currentLine);
 			}
 		}
 		else
@@ -1029,4 +1053,23 @@ class Listview
 			dol_syslog(get_class($this)."::parse_sql id=".$this->id." sql=".$this->sql, LOG_ERR);
 		}
 	}	
+	
+	static function getCachedOjbect($class_name, $fk_object) {
+		global $db, $TCacheListObject;
+		
+		if(!class_exists($class_name)) return false;
+		
+		if(empty($TCacheListObject)) $TCacheListObject = array();
+		if(empty($TCacheListObject[$class_name])) $TCacheListObject[$class_name]  =array();
+		
+		if(empty($TCacheListObject[$class_name][$fk_object])) {
+			$TCacheListObject[$class_name][$fk_object]= new $class_name($db);
+			if( $TCacheListObject[$class_name][$fk_object]->fetch($fk_object)<0) {
+				return false;
+			}
+		}
+		
+		return $TCacheListObject[$class_name][$fk_object];
+	}
+	
 }

+ 702 - 0
htdocs/product/list-with-listview.php

@@ -0,0 +1,702 @@
+<?php
+/* Copyright (C) 2001-2006  Rodolphe Quiedeville    <rodolphe@quiedeville.org>
+ * Copyright (C) 2004-2016  Laurent Destailleur     <eldy@users.sourceforge.net>
+ * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
+ * Copyright (C) 2012-2016  Marcos García           <marcosgdf@gmail.com>
+ * Copyright (C) 2013-2016	Juanjo Menent           <jmenent@2byte.es>
+ * Copyright (C) 2013-2015  Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
+ * Copyright (C) 2013       Jean Heimburger         <jean@tiaris.info>
+ * Copyright (C) 2013       Cédric Salvador         <csalvador@gpcsolutions.fr>
+ * Copyright (C) 2013       Florian Henry           <florian.henry@open-concept.pro>
+ * Copyright (C) 2013       Adolfo segura           <adolfo.segura@gmail.com>
+ * Copyright (C) 2015       Jean-François Ferry     <jfefe@aternatik.fr>
+ * Copyright (C) 2016       Ferran Marcet		    <fmarcet@2byte.es>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ *  \file       htdocs/product/list.php
+ *  \ingroup    produit
+ *  \brief      Page to list products and services
+ */
+
+require '../main.inc.php';
+require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+require_once DOL_DOCUMENT_ROOT.'/product/inventory/listview.class.php';
+require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
+if (! empty($conf->categorie->enabled))
+	require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+
+$langs->load("products");
+$langs->load("stocks");
+$langs->load("suppliers");
+$langs->load("companies");
+if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
+
+$action=GETPOST('action','alpha');
+$massaction=GETPOST('massaction','alpha');
+$show_files=GETPOST('show_files','int');
+$confirm=GETPOST('confirm','alpha');
+$toselect = GETPOST('toselect', 'array');
+
+$sref=GETPOST("sref");
+$sbarcode=GETPOST("sbarcode");
+$snom=GETPOST("snom");
+$sall=GETPOST("sall");
+$type= (int) GETPOST("type","int");
+$search_sale = GETPOST("search_sale");
+$search_categ = GETPOST("search_categ",'int');
+$tosell = GETPOST("tosell", 'int');
+$tobuy = GETPOST("tobuy", 'int');
+$fourn_id = GETPOST("fourn_id",'int');
+$catid = GETPOST('catid','int');
+$search_tobatch = GETPOST("search_tobatch",'int');
+$search_accountancy_code_sell = GETPOST("search_accountancy_code_sell",'alpha');
+$search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
+$optioncss = GETPOST('optioncss','alpha');
+
+//Show/hide child products. Hidden by default
+if (!$_POST) {
+	$search_hidechildproducts = 'on';
+} else {
+	$search_hidechildproducts = GETPOST('search_hidechildproducts');
+}
+
+$diroutputmassaction=$conf->product->dir_output . '/temp/massgeneration/'.$user->id;
+
+$limit = GETPOST("limit")?GETPOST("limit","int"):$conf->liste_limit;
+$sortfield = GETPOST("sortfield",'alpha');
+$sortorder = GETPOST("sortorder",'alpha');
+$page = (GETPOST("page",'int')?GETPOST("page", 'int'):0);
+if ($page == -1) { $page = 0; }
+$offset = $limit * $page;
+$pageprev = $page - 1;
+$pagenext = $page + 1;
+if (! $sortfield) $sortfield="p.ref";
+if (! $sortorder) $sortorder="ASC";
+
+// Initialize context for list
+$contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'productservicelist';
+if ((string) $type == '1') { $contextpage='servicelist'; if ($search_type=='') $search_type='1'; }
+if ((string) $type == '0') { $contextpage='productlist'; if ($search_type=='') $search_type='0'; }
+
+// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
+$hookmanager->initHooks(array($contextpage));
+$extrafields = new ExtraFields($db);
+$form=new Form($db);
+
+// fetch optionals attributes and labels
+$extralabels = $extrafields->fetch_name_optionals_label('product');
+$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
+
+if (empty($action)) $action='list';
+
+// Get object canvas (By default, this is not defined, so standard usage of dolibarr)
+$canvas=GETPOST("canvas");
+$objcanvas=null;
+if (! empty($canvas))
+{
+    require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
+    $objcanvas = new Canvas($db,$action);
+    $objcanvas->getCanvas('product','list',$canvas);
+}
+
+// Security check
+if ($type=='0') $result=restrictedArea($user,'produit','','','','','',$objcanvas);
+else if ($type=='1') $result=restrictedArea($user,'service','','','','','',$objcanvas);
+else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas);
+
+// Define virtualdiffersfromphysical
+$virtualdiffersfromphysical=0;
+if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER))
+{
+    $virtualdiffersfromphysical=1;		// According to increase/decrease stock options, virtual and physical stock may differs.
+}
+
+// List of fields to search into when doing a "search in all"
+$fieldstosearchall = array(
+	'p.ref'=>"Ref",
+    'pfp.ref_fourn'=>"RefSupplier",
+	'p.label'=>"ProductLabel",
+	'p.description'=>"Description",
+    "p.note"=>"Note",
+);
+// multilang
+if (! empty($conf->global->MAIN_MULTILANGS))
+{
+	$fieldstosearchall['pl.label']='ProductLabelTranslated';
+	$fieldstosearchall['pl.description']='ProductDescriptionTranslated';
+	$fieldstosearchall['pl.note']='ProductNoteTranslated';
+}
+if (! empty($conf->barcode->enabled)) {
+	$fieldstosearchall['p.barcode']='Gencod';
+}
+
+if (empty($conf->global->PRODUIT_MULTIPRICES))
+{
+	$titlesellprice=$langs->trans("SellingPrice");
+	if (! empty($conf->global->PRODUIT_CUSTOMER_PRICES))
+	{
+		$titlesellprice=$form->textwithpicto($langs->trans("SellingPrice"), $langs->trans("DefaultPriceRealPriceMayDependOnCustomer"));
+	}
+}
+
+// Definition of fields for lists
+$arrayfields=array(
+    'p.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
+    //'pfp.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))),
+    'p.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
+	'p.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>($contextpage != 'servicelist'), 'enabled'=>(! empty($conf->barcode->enabled))),
+    'p.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))),
+	'p.price'=>array('label'=>$langs->trans("SellingPrice"), 'checked'=>1, 'enabled'=>empty($conf->global->PRODUIT_MULTIPRICES)),
+    'p.minbuyprice'=>array('label'=>$langs->trans("BuyingPriceMinShort"), 'checked'=>1, 'enabled'=>(! empty($user->rights->fournisseur->lire))),
+	'p.seuil_stock_alerte'=>array('label'=>$langs->trans("StockLimit"), 'checked'=>0, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
+    'p.desiredstock'=>array('label'=>$langs->trans("DesiredStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
+    'p.stock'=>array('label'=>$langs->trans("PhysicalStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service')),
+    'stock_virtual'=>array('label'=>$langs->trans("VirtualStock"), 'checked'=>1, 'enabled'=>(! empty($conf->stock->enabled) && $user->rights->stock->lire && $contextpage != 'service' && $virtualdiffersfromphysical)),
+    'p.tobatch'=>array('label'=>$langs->trans("ManageLotSerial"), 'checked'=>0, 'enabled'=>(! empty($conf->productbatch->enabled))),
+	'p.accountancy_code_sell'=>array('label'=>$langs->trans("ProductAccountancySellCode"), 'checked'=>0),
+	'p.accountancy_code_buy'=>array('label'=>$langs->trans("ProductAccountancyBuyCode"), 'checked'=>0),
+	'p.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
+    'p.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500),
+    'p.tosell'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Sell").')', 'checked'=>1, 'position'=>1000),
+    'p.tobuy'=>array('label'=>$langs->trans("Status").' ('.$langs->trans("Buy").')', 'checked'=>1, 'position'=>1000)
+);
+// Extra fields
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
+{
+   foreach($extrafields->attribute_label as $key => $val) 
+   {
+       $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key]);
+   }
+}
+
+
+
+/*
+ * Actions
+ */
+
+if (GETPOST('cancel')) { $action='list'; $massaction=''; }
+if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; }
+
+$parameters=array();
+$reshook=$hookmanager->executeHooks('doActions',$parameters, $object, $action);    // Note that $action and $object may have been modified by some hooks
+if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
+
+if (empty($reshook))
+{
+    // Selection of new fields
+    include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
+
+    // Purge search criteria
+    if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
+    {
+    	$sall="";
+    	$sref="";
+    	$snom="";
+    	$sbarcode="";
+    	$search_categ=0;
+    	$tosell="";
+    	$tobuy="";
+    	$search_tobatch='';
+    	$search_accountancy_code_sell='';
+    	$search_accountancy_code_buy='';
+    	$search_array_options=array();
+    }
+    
+    // Mass actions
+    $objectclass='Product';
+    if ((string) $type == '1') { $objectlabel='Services'; }
+    if ((string) $type == '0') { $objectlabel='Products'; }
+    
+    $permtoread = $user->rights->produit->lire;
+    $permtodelete = $user->rights->produit->supprimer;
+    $uploaddir = $conf->product->dir_output;
+    include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';    
+}
+
+
+/*
+ * View
+ */
+
+$htmlother=new FormOther($db);
+
+if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
+{
+	$objcanvas->assign_values($action);       // This must contains code to load data (must call LoadListDatas($limit, $offset, $sortfield, $sortorder))
+    $objcanvas->display_canvas($action);  	  // This is code to show template
+}
+else
+{
+	$title=$langs->trans("ProductsAndServices");
+
+	if (isset($type))
+	{
+		if ($type==1)
+		{
+			$texte = $langs->trans("Services");
+		}
+		else
+		{
+			$texte = $langs->trans("Products");
+		}
+	}
+	else
+	{
+		$texte = $langs->trans("ProductsAndServices");
+	}
+
+    $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
+    $sql.= ' p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
+    $sql.= ' p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy,';
+    $sql.= ' p.datec, p.tms,';
+    //$sql.= ' pfp.ref_fourn as ref_supplier, ';
+    $sql.= ' MIN(pfp.unitprice) as minsellprice';
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+		$sql .= ', pac.rowid prod_comb_id';
+	}
+	// Add fields from extrafields
+    foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key.' as options_'.$key : '');
+	// Add fields from hooks
+	$parameters=array();
+	$reshook=$hookmanager->executeHooks('printFieldListSelect',$parameters);    // Note that $action and $object may have been modified by hook
+	$sql.=$hookmanager->resPrint;
+    $sql.= ' FROM '.MAIN_DB_PREFIX.'product as p';
+	if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_extrafields as ef on (p.rowid = ef.fk_object)";
+    if (! empty($search_categ) || ! empty($catid)) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX."categorie_product as cp ON p.rowid = cp.fk_product"; // We'll need this table joined to the select in order to filter by categ
+   	$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
+	// multilang
+	if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'";
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
+	}
+
+	$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
+	if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
+    // if the type is not 1, we show all products (type = 0,2,3)
+    if (dol_strlen($type))
+    {
+    	if ($type == 1) $sql.= " AND p.fk_product_type = '1'";
+    	else $sql.= " AND p.fk_product_type <> '1'";
+    }
+	if ($sref)     $sql .= natural_search('p.ref', $sref);
+	if ($snom)     $sql .= natural_search('p.label', $snom);
+	if ($sbarcode) $sql .= natural_search('p.barcode', $sbarcode);
+    if (isset($tosell) && dol_strlen($tosell) > 0  && $tosell!=-1) $sql.= " AND p.tosell = ".$db->escape($tosell);
+    if (isset($tobuy) && dol_strlen($tobuy) > 0  && $tobuy!=-1)   $sql.= " AND p.tobuy = ".$db->escape($tobuy);
+    if (dol_strlen($canvas) > 0)                    $sql.= " AND p.canvas = '".$db->escape($canvas)."'";
+    if ($catid > 0)    $sql.= " AND cp.fk_categorie = ".$catid;
+    if ($catid == -2)  $sql.= " AND cp.fk_categorie IS NULL";
+    if ($search_categ > 0)   $sql.= " AND cp.fk_categorie = ".$db->escape($search_categ);
+    if ($search_categ == -2) $sql.= " AND cp.fk_categorie IS NULL";
+    if ($fourn_id > 0) $sql.= " AND pfp.fk_soc = ".$fourn_id;
+    if ($search_tobatch != '' && $search_tobatch >= 0)   $sql.= " AND p.tobatch = ".$db->escape($search_tobatch);
+    if ($search_accountancy_code_sell)   $sql.= natural_search('p.accountancy_code_sell', $search_accountancy_code_sell);
+    if ($search_accountancy_code_sell)   $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
+    // Add where from extra fields
+
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+		$sql .= " AND pac.rowid IS NULL";
+	}
+
+	// Add where from extra fields
+	foreach ($search_array_options as $key => $val)
+	{
+	    $crit=$val;
+	    $tmpkey=preg_replace('/search_options_/','',$key);
+	    $typ=$extrafields->attribute_type[$tmpkey];
+	    $mode=0;
+	    if (in_array($typ, array('int','double'))) $mode=1;    // Search on a numeric
+	    if ($val && ( ($crit != '' && ! in_array($typ, array('select'))) || ! empty($crit))) 
+	    {
+	        $sql .= natural_search('ef.'.$tmpkey, $crit, $mode);
+	    }
+	}
+	// Add where from hooks
+	$parameters=array();
+	$reshook=$hookmanager->executeHooks('printFieldListWhere',$parameters);    // Note that $action and $object may have been modified by hook
+	$sql.=$hookmanager->resPrint;
+    $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
+    $sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
+    $sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy';
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+		$sql .= ', pac.rowid';
+	}
+	// Add fields from extrafields
+    foreach ($extrafields->attribute_label as $key => $val) $sql.=($extrafields->attribute_type[$key] != 'separate' ? ",ef.".$key : '');
+	// Add fields from hooks
+	$parameters=array();
+	$reshook=$hookmanager->executeHooks('printFieldSelect',$parameters);    // Note that $action and $object may have been modified by hook
+	$sql.=$hookmanager->resPrint;
+
+	// TODO put these functions into product.lib.php if this go from demo to core
+	/**
+	 * Function return formated sell price
+	 *
+	 * @param   int 	$fk_object rowid of product
+	 * @return string
+	 */
+	function list_get_product_sellprice($fk_object) {
+		global $langs,$conf, $user;
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		if($object === false) return '';
+		
+		if ($object->status)
+		{
+			if ($object->price_base_type == 'TTC') return price($object->price_ttc).' '.$langs->trans("TTC");
+			else return price($object->price).' '.$langs->trans("HT");
+		}
+		return '';
+	}
+
+	/**
+	 * Function return formated product status sell or buy
+	 *
+	 * @param   int 	$fk_object 	rowid of product
+	 * @param	string	$field		concerned field status|status_buy
+	 * @param	int		$type		for libstatus
+	 * @return string	
+	 */
+	function list_get_product_status($fk_object, $field, $type) {
+		global $conf, $user;
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		
+		if($object === false) return '';
+		
+		if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
+			return ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
+		} else {
+			return $object->LibStatut($object->{$field},5,$type);
+		}
+		
+	}
+	
+	/**
+	 * Function return formated ref
+	 *
+	 * @param   int $fk_object rowid of product
+	 * @return string
+	 */
+	function list_get_product_ref($fk_object) {
+		global $conf, $user;
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		
+		if($object === false) return '';
+		
+		return $object->getNomUrl(1,'',24);
+	}
+	
+	/**
+	 * Function return formated extrafield
+	 *
+	 * @param   int 	$fk_object 	rowid of product
+	 * @param	string	$key		extrafield to output
+	 * @return string
+	 */
+	function list_get_product_extrafield($fk_object, $key) {
+		global $extrafields;
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		if($object === false) return '';
+		
+		return $extrafields->showOutputField($key, $object->array_options['options_'.$key], '', 1);
+	}
+
+	/**
+	 * Function return formated virtual stock
+	 *
+	 * @param   int $fk_object 	rowid of product
+	 * @return string
+	 */
+	function list_get_product_virtual_stock($fk_object) {
+		global $langs;
+	
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		if($object === false) return '';
+		
+		$object->load_stock('nobatch');
+		
+		$out = '';
+		if ($object->type != 1)
+		{
+			if ($object->seuil_stock_alerte != '' && $object->stock_theorique < (float) $object->seuil_stock_alerte) $out.= img_warning($langs->trans("StockTooLow")).' ';
+			$out.= (double) $object->stock_theorique;
+		}
+
+		return $out;
+	}
+	
+	/**
+	 * Function return formated stock
+	 *
+	 * @param   int $fk_object rowid of product
+	 * @return string
+	 */
+	function list_get_product_stock($fk_object) {
+		global $langs;
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		if($object === false) return '';
+		
+		$out = '';
+		if ($object->type != 1)
+		{
+			if ($object->seuil_stock_alerte != '' && $object->stock_reel< (float) $object->seuil_stock_alerte) $out.= img_warning($langs->trans("StockTooLow")).' ';
+			$out.= (double) $object->stock_reel;
+		}
+		
+		return $out;
+	}
+	/**
+	 * Function return formated min buy price
+	 *
+	 * @param   int $fk_object rowid of product
+	 * @return string
+	 */
+	function list_get_product_minbuyprice($fk_object) {
+		global $conf, $user, $langs,$db,$form;
+		
+		$out = '';
+		
+		$object = Listview::getCachedOjbect('Product', $fk_object);
+		if($object === false || empty($object->status_buy) ) return '';
+		
+		$product_fourn =new ProductFournisseur($db);
+		if ($product_fourn->find_min_price_product_fournisseur($fk_object) > 0)
+		{
+			if ($product_fourn->product_fourn_price_id > 0)
+			{
+				if (! empty($conf->fournisseur->enabled) && $user->rights->fournisseur->lire)
+				{
+					$htmltext=$product_fourn->display_price_product_fournisseur(1, 1, 0, 1);
+					$out.= $form->textwithpicto(price($product_fourn->fourn_unitprice).' '.$langs->trans("HT"),$htmltext);
+				}
+				else $out.= price($product_fourn->fourn_unitprice).' '.$langs->trans("HT");
+			}
+		}
+		return $out;
+	}
+	
+	// array of customized field function
+	$arrayeval = array(
+			'tobuy'=>'list_get_product_status(@rowid@, "status_buy",1)'
+			,'tosell'=>'list_get_product_status(@rowid@, "status",0)'
+			,'ref'=>'list_get_product_ref(@rowid@)'
+			,'label'=>'dol_trunc("@val@",40)'
+			,'price'=>'list_get_product_sellprice(@rowid@)'
+			,'stock_virtual'=>'list_get_product_virtual_stock(@rowid@)'
+			,'stock'=>'list_get_product_stock(@rowid@)'
+			,'minbuyprice'=>'list_get_product_minbuyprice(@rowid@)'
+	);
+	
+	// defined list align for field
+	$arrayalign = array(
+			'price'=>'right'
+			,'tobuy'=>'right'
+			,'tosell'=>'right'
+			,'desiredstock'=>'right'
+			,'stock'=>'right'
+			,'stock_virtual'=>'right'
+			,'minbuyprice'=>'right'
+			,'datec'=>'center'
+			,'tms'=>'center'
+	);
+	
+	$parameters=array('arrayfields'=>$arrayfields);
+	$reshook=$hookmanager->executeHooks('printFieldListMoreFields',$parameters);    // Note that $action and $object may have been modified by hook
+	if($reshook) {
+		$arrayfields = $hookmanager->resArray;
+	}
+	
+	// init title, hidden field (allowed into selected fields), and position
+	$arrayhide = $arraytitle = $arrayposition = array();
+    foreach($arrayfields as $k=>$data) {
+    	if(!isset($data['enabled']) || $data['enabled']) {
+    		list($t,$f) = explode('.',$k);
+    		if(empty($f))$f = $k;
+    		$arraytitle[$f]=$data['label'];
+    		if(empty($data['checked'])) $arrayhide[] = $f;
+    		$arrayposition[$f] = empty($data['position']) ? 0 : $data['position'];
+    	}
+    }
+    
+    // Extra fields
+    if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
+    {
+    	foreach($extrafields->attribute_label as $key => $val)
+    	{
+    		$arrayalign[$key]=$extrafields->getAlignFlag($key);
+   			$arrayeval[$key] = 'list_get_product_extrafield(@rowid@, "'.$key.'")';
+    	}
+    }
+    // List of mass actions available
+    $arrayofmassactions =  array(
+    		//'presend'=>$langs->trans("SendByMail"),
+    		//'builddoc'=>$langs->trans("PDFMerge"),
+    );
+    if ($user->rights->produit->supprimer) $arrayofmassactions['delete']=$langs->trans("Delete");
+    if ($massaction == 'presend' || $massaction == 'createbills') $arrayofmassactions=array();
+    
+    // Filter on categories
+    $moreforfilter='';
+    if (! empty($conf->categorie->enabled))
+    {
+    	$moreforfilter.='<div class="divsearchfield">';
+    	$moreforfilter.=$langs->trans('Categories'). ': ';
+    	$moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1);
+    	$moreforfilter.='</div>';
+    }
+    
+    //Show/hide child products. Hidden by default
+    if (!empty($conf->variants->enabled) && $type === 0) {
+    	$moreforfilter.='<div class="divsearchfield">';
+    	$moreforfilter.= '<input type="checkbox" id="search_hidechildproducts" name="search_hidechildproducts" value="on"'.($search_hidechildproducts ? 'checked="checked"' : '').'>';
+    	$moreforfilter.= ' <label for="search_hidechildproducts">'.$langs->trans('HideChildProducts').'</label>';
+    	$moreforfilter.='</div>';
+    }
+    
+    if ($moreforfilter)
+    {
+    	$parameters=array();
+    	$reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters);    // Note that $action and $object may have been modified by hook
+    	
+    	if(!empty($hookmanager->resPrint)) {
+    		$moreforfilter.=$hookmanager->resPrint;
+    	}
+    				
+    }
+
+    $param='';
+    if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
+    if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
+    if ($search_categ > 0) $param.="&amp;search_categ=".urlencode($search_categ);
+    if ($sref) $param="&amp;sref=".urlencode($sref);
+    if ($search_ref_supplier) $param="&amp;search_ref_supplier=".urlencode($search_ref_supplier);
+    if ($sbarcode) $param.=($sbarcode?"&amp;sbarcode=".urlencode($sbarcode):"");
+    if ($snom) $param.="&amp;snom=".urlencode($snom);
+    if ($sall) $param.="&amp;sall=".urlencode($sall);
+    if ($tosell != '') $param.="&amp;tosell=".urlencode($tosell);
+    if ($tobuy != '') $param.="&amp;tobuy=".urlencode($tobuy);
+    if ($fourn_id > 0) $param.=($fourn_id?"&amp;fourn_id=".$fourn_id:"");
+    if ($seach_categ) $param.=($search_categ?"&amp;search_categ=".urlencode($search_categ):"");
+    if ($type != '') $param.='&amp;type='.urlencode($type);
+    if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
+    if ($search_tobatch) $param="&amp;search_ref_supplier=".urlencode($search_ref_supplier);
+    if ($search_accountancy_code_sell) $param="&amp;search_accountancy_code_sell=".urlencode($search_accountancy_code_sell);
+    if ($search_accountancy_code_buy) $param="&amp;search_accountancy_code_buy=".urlencode($search_accountancy_code_buy);
+    // Add $param from extra fields
+    foreach ($search_array_options as $key => $val)
+    {
+    	$crit=$val;
+    	$tmpkey=preg_replace('/search_options_/','',$key);
+    	if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
+    }
+    
+    //var_dump($arraytitle,$arrayhide);
+    $list=new Listview($db, 'products');
+    $listHTML = $list->render($sql,array(
+    		'list'=>array(
+    				'title'=>$texte
+    				,'image'=>'title_products.png'
+    				,'massactions'=>$arrayofmassactions
+    				,'param_url'=>$param
+    				,'messageNothing'=>''
+    		)
+    		,'limit'=>array(
+    				'nbLine'=>$limit
+    		)
+    		,'sortfield'=>$sortfield
+    		,'sortorder'=>$sortorder
+    		,'title'=>$arraytitle // column definition title (only defined where abble to show)
+    		,'position'=>array(
+    				'text-align'=>$arrayalign
+    				,'rank'=>$arrayposition
+    		)
+    		,'allow-fields-select'=>1 // allow to select hidden fields
+    		,'head_search'=>$moreforfilter //custom search on head
+    		,'no-auto-sql-search'=>1 //disabled auto completion sql for search and pager url, use dolibarr style for migration of product list
+			,'translate'=>array()    		
+    		,'search'=>array(
+    				'ref'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'sref')
+    				,'label'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'snom')
+    				,'tosell'=>array('search_type'=> array('0'=>$langs->trans('ProductStatusNotOnSellShort'),'1'=>$langs->trans('ProductStatusOnSellShort')), 'fieldname'=>'tosell')
+    				,'tobuy'=>array('search_type'=> array('0'=>$langs->trans('ProductStatusNotOnBuyShort'),'1'=>$langs->trans('ProductStatusOnBuyShort')), 'fieldname'=>'tobuy')
+    				,'barcode'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'sbarcode')
+    				,'accountancy_code_sell'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'search_accountancy_code_sell')
+    				,'accountancy_code_buy'=>array('search_type'=>true, 'table'=>'p', 'fieldname'=>'search_accountancy_code_buy')
+    		)
+    		,'type'=>array(
+    				'datec'=>'datetime'
+    				,'tms'=>'datetime'
+    		)
+    		,'hide'=>$arrayhide
+    		,'eval'=>$arrayeval
+    ));
+    
+    $num = $list->totalRow;
+    
+    	$arrayofselected=is_array($toselect)?$toselect:array();
+    	
+    	if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
+    	{
+    	    $id = $list->TField[0]->rowid;
+    	    header("Location: ".DOL_URL_ROOT.'/product/card.php?id='.$id);
+    	    exit;
+    	}
+
+    	$helpurl='';
+    	if (isset($type))
+    	{
+    		if ($type == 0)
+    		{
+    			$helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
+    		}
+    		else if ($type == 1)
+    		{
+    			$helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
+    		}
+    	}
+
+    	llxHeader('',$title,$helpurl,'');
+
+    	// Displays product removal confirmation
+    	if (GETPOST('delprod'))	{
+		    setEventMessages($langs->trans("ProductDeleted", GETPOST('delprod')), null, 'mesgs');
+	    }
+
+		print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">';
+        if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
+		print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+		print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
+		print '<input type="hidden" name="action" value="list">';
+		print '<input type="hidden" name="sortfield" value="'.$sortfield.'">';
+		print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
+		print '<input type="hidden" name="type" value="'.$type.'">';
+
+		echo $listHTML;
+    
+    	print '</form>';
+    
+}
+
+
+llxFooter();
+$db->close();

+ 12 - 0
htdocs/projet/element.php

@@ -43,6 +43,7 @@ if (! empty($conf->fournisseur->enabled))	require_once DOL_DOCUMENT_ROOT.'/fourn
 if (! empty($conf->fournisseur->enabled))	require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
 if (! empty($conf->contrat->enabled))		require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
 if (! empty($conf->ficheinter->enabled))	require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
+if (! empty($conf->expedition->enabled))    require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
 if (! empty($conf->deplacement->enabled))	require_once DOL_DOCUMENT_ROOT.'/compta/deplacement/class/deplacement.class.php';
 if (! empty($conf->expensereport->enabled))	require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
 if (! empty($conf->agenda->enabled))		require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
@@ -341,6 +342,17 @@ $listofreferent=array(
     'buttonnew'=>'AddIntervention',
     'testnew'=>$user->rights->ficheinter->creer,
     'test'=>$conf->ficheinter->enabled && $user->rights->ficheinter->lire),
+'shipping'=>array(
+    'name'=>"Shippings",
+	'title'=>"ListShippingAssociatedProject",
+	'class'=>'Expedition',
+	'table'=>'expedition',
+	'datefieldname'=>'date_valid',
+	'urlnew'=>DOL_URL_ROOT.'/expedition/card.php?action=create&origin=project&originid='.$id.'&socid='.$socid,
+	'lang'=>'sendings',
+	'buttonnew'=>'CreateShipment',
+	'testnew'=>0,
+	'test'=>$conf->expedition->enabled && $user->rights->expedition->lire),
 'trip'=>array(
 	'name'=>"TripsAndExpenses",
 	'title'=>"ListExpenseReportsAssociatedProject",

+ 3 - 3
htdocs/societe/ajax/company.php

@@ -83,11 +83,11 @@ else
 	sort($match);
 	$id = (! empty($match[0]) ? $match[0] : '');
 
-	if (! GETPOST($htmlname) && ! GETPOST($id)) return;
-
 	// When used from jQuery, the search term is added as GET param "term".
-	$searchkey=(GETPOST($id)?GETPOST($id):(GETPOST($htmlname)?GETPOST($htmlname):''));
+	$searchkey=(($id && GETPOST($id, 'alpha'))?GETPOST($id, 'alpha'):(($htmlname && GETPOST($htmlname, 'alpha'))?GETPOST($htmlname, 'alpha'):''));
 
+	if (! $searchkey) return;
+	
 	$form = new Form($db);
 	$arrayresult=$form->select_thirdparty_list(0,$htmlname,$filter,1,0,0,null,$searchkey,$outjson);
 

+ 0 - 1
htdocs/societe/card.php

@@ -750,7 +750,6 @@ if (empty($reshook))
 
     // Actions to send emails
     $id=$socid;
-    $actiontypecode='AC_OTH_AUTO';
     $trigger_name='COMPANY_SENTBYMAIL';
     $paramname='socid';
     $mode='emailfromthirdparty';

+ 0 - 1
htdocs/supplier_proposal/card.php

@@ -466,7 +466,6 @@ if (empty($reshook))
 	include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
 
 	// Actions to send emails
-	$actiontypecode='AC_ASKPRICE';
 	$trigger_name='SUPPLIER_PROPOSAL_SENTBYMAIL';
 	$paramname='id';
 	$mode='emailfromsupplierproposal';

+ 1 - 0
htdocs/theme/eldy/style.css.php

@@ -1101,6 +1101,7 @@ div.nopadding {
 	padding-top: 1px;
 	padding-bottom: 1px;
 	width: 44px;
+	text-align:center;
 }
 div.attacharea {
 	padding-top: 18px;

+ 2 - 1
htdocs/theme/md/style.css.php

@@ -1145,6 +1145,7 @@ img.hideonsmartphone.pictoactionview {
 	padding-top: 1px;
 	padding-bottom: 1px;
 	width: 44px;
+	text-align:center;
 }
 div.attacharea {
 	padding-top: 18px;
@@ -3054,7 +3055,7 @@ div.info {
   -moz-border-radius: 4px;
   -webkit-border-radius: 4px;
   border-radius: 4px;
-  background: #EaE4Ea;
+  background: #868;
   text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
 }
 

+ 22 - 9
htdocs/user/bank.php

@@ -24,7 +24,7 @@
 /**
  *	    \file       htdocs/user/bank.php
  *      \ingroup    HRM
- *		\brief      BAN tab for users
+ *		\brief      Tab for HRM
  */
 
 require '../main.inc.php';
@@ -47,7 +47,7 @@ $socid=0;
 if ($user->societe_id > 0) $socid = $user->societe_id;
 $feature2 = (($socid && $user->rights->user->self->creer)?'':'user');
 if ($user->id == $id) $feature2=''; // A user can always read its own card
-$result = restrictedArea($user, 'user', $id, 'user&user', $feature2);
+$result = restrictedArea($user, 'salaries|hrm', $id, 'user&user', $feature2);
 
 $object = new User($db);
 if ($id > 0 || ! empty($ref))
@@ -155,14 +155,27 @@ if ($account->id && $action != 'edit')
         
     print '<div class="fichecenter">';
 
+    print '<div class="underbanner clearboth"></div>';
+    
+    print '<table class="border centpercent">';
+    
+    print '<tr><td class="titlefield">'.$langs->trans("xxx").'</td>';
+    print '<td></td></tr>';
+    
+    print '</table>';
+    
+    print '</br>';
+    
+    print load_fiche_titre($langs->trans("BAN"));
+    
     print '<div class="underbanner clearboth"></div>';
     print '<table class="border centpercent">';
 
     print '<tr><td class="titlefield">'.$langs->trans("LabelRIB").'</td>';
-    print '<td colspan="4">'.$account->label.'</td></tr>';
+    print '<td>'.$account->label.'</td></tr>';
 
 	print '<tr><td>'.$langs->trans("BankName").'</td>';
-	print '<td colspan="4">'.$account->bank.'</td></tr>';
+	print '<td>'.$account->bank.'</td></tr>';
 
 	// Show fields of bank account
 	foreach ($account->getFieldsToShow() as $val) {
@@ -182,7 +195,7 @@ if ($account->id && $action != 'edit')
 	}
 
 	print '<tr><td class="tdtop">'.$langs->trans("IBAN").'</td>';
-	print '<td colspan="4">'.$account->iban . '&nbsp;';
+	print '<td>'.$account->iban . '&nbsp;';
     if (! empty($account->iban)) {
         if (! checkIbanForAccount($account)) {
             print img_picto($langs->trans("IbanNotValid"),'warning');
@@ -193,7 +206,7 @@ if ($account->id && $action != 'edit')
     print '</td></tr>';
 
 	print '<tr><td class="tdtop">'.$langs->trans("BIC").'</td>';
-	print '<td colspan="4">'.$account->bic.'&nbsp;';
+	print '<td>'.$account->bic.'&nbsp;';
     if (! empty($account->bic)) {
         if (! checkSwiftForAccount($account)) {
             print img_picto($langs->trans("SwiftNotValid"),'warning');
@@ -203,15 +216,15 @@ if ($account->id && $action != 'edit')
     }
     print '</td></tr>';
 
-	print '<tr><td class="tdtop">'.$langs->trans("BankAccountDomiciliation").'</td><td colspan="4">';
+	print '<tr><td class="tdtop">'.$langs->trans("BankAccountDomiciliation").'</td><td>';
 	print $account->domiciliation;
 	print "</td></tr>\n";
 
-	print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwner").'</td><td colspan="4">';
+	print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwner").'</td><td>';
 	print $account->proprio;
 	print "</td></tr>\n";
 
-	print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerAddress").'</td><td colspan="4">';
+	print '<tr><td class="tdtop">'.$langs->trans("BankAccountOwnerAddress").'</td><td>';
 	print $account->owner_address;
 	print "</td></tr>\n";
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 552 - 557
htdocs/user/card.php


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio