From 13c3db08e74df0430b92960b946b6c09dc32f161 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Sun, 18 Sep 2016 15:48:29 +0200
Subject: [PATCH] Uniformize code and look and feel

---
 htdocs/compta/bank/index.php    | 448 +++++++++++++++++++++++---------
 htdocs/projet/list.php          |  94 +++++--
 htdocs/theme/eldy/style.css.php |   3 +
 htdocs/theme/md/style.css.php   |   3 +
 4 files changed, 400 insertions(+), 148 deletions(-)

diff --git a/htdocs/compta/bank/index.php b/htdocs/compta/bank/index.php
index a5038fc2e78..444f4a1b55d 100644
--- a/htdocs/compta/bank/index.php
+++ b/htdocs/compta/bank/index.php
@@ -33,14 +33,93 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
 $langs->load("banks");
 $langs->load("categories");
 
+$action=GETPOST('action','alpha');
+$massaction=GETPOST('massaction','alpha');
+$show_files=GETPOST('show_files','int');
+$confirm=GETPOST('confirm','alpha');
+$toselect = GETPOST('toselect', 'array');
+
+$statut=GETPOST('statut')?GETPOST('statut', 'alpha'):'opened';                      // 'all' or ''='opened'
+$optioncss = GETPOST('optioncss','alpha');
+
 // Security check
 if ($user->societe_id) $socid=$user->societe_id;
 $result=restrictedArea($user,'banque');
 
-$statut=GETPOST('statut');
+$diroutputmassaction=$conf->banque->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');
+if ($page == -1) { $page = 0; }
+$offset = $limit * $page;
+$pageprev = $page - 1;
+$pagenext = $page + 1;
+if (! $sortfield) $sortfield='b.label';
+if (! $sortorder) $sortorder='ASC';
+
+// Initialize technical object to manage context to save list fields
+$contextpage='bankaccountlist';
+
+// Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
+$hookmanager->initHooks(array($contextpage));
+$extrafields = new ExtraFields($db);
+
+// fetch optionals attributes and labels
+$extralabels = $extrafields->fetch_name_optionals_label('bankaccount');
+$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
+
+// List of fields to search into when doing a "search in all"
+$fieldstosearchall = array(
+    'b.ref'=>'Ref',
+    'b.label'=>'Label',
+);
+
+$checkedtypetiers=0;
+$arrayfields=array(
+    'b.ref'=>array('label'=>$langs->trans("BankAccounts"), 'checked'=>1),
+    'accountype'=>array('label'=>$langs->trans("AccountType"), 'checked'=>1),
+    'b.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
+    'b.number'=>array('label'=>$langs->trans("AccountIdShort"), 'checked'=>1),
+    'toreconcile'=>array('label'=>$langs->trans("TransactionsToConciliate"), 'checked'=>1),
+    'b.datec'=>array('label'=>$langs->trans("DateCreation"), 'checked'=>0, 'position'=>500),
+    'b.tms'=>array('label'=>$langs->trans("DateModificationShort"), 'checked'=>0, 'position'=>500),
+    'b.clos'=>array('label'=>$langs->trans("Status"), 'checked'=>1, 'position'=>1000),
+    'balance'=>array('label'=>$langs->trans("Balance"), 'checked'=>1, 'position'=>1010),
+);
+// 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], 'enabled'=>$extrafields->attribute_perms[$key]);
+    }
+}
+
 
+/*
+ * Actions
+ */
 
+if (GETPOST('cancel')) { $action='list'; $massaction=''; }
+if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; }
 
+$parameters=array('socid'=>$socid);
+$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');
+
+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 test are required to be compatible with all browsers
+{
+    $statut = 'all';
+    
+}
+    
+    
+    
 /*
  * View
  */
@@ -50,11 +129,48 @@ $title=$langs->trans('BankAccounts');
 // Load array of financial accounts (opened by default)
 $accounts = array();
 
-$sql  = "SELECT rowid, courant, rappro";
-$sql.= " FROM ".MAIN_DB_PREFIX."bank_account";
+$sql  = "SELECT rowid, label, courant, rappro";
+// 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."bank_account as b";
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."bankcacount_extrafields as ef on (c.rowid = ef.fk_object)";
 $sql.= " WHERE entity IN (".getEntity('bank_account', 1).")";
-if ($statut != 'all') $sql.= " AND clos = 0";
-$sql.= $db->order('label', 'ASC');
+if ($statut == 'opened') $sql.= " AND clos = 0";
+if ($statut == 'closed') $sql.= " AND clos = 1";
+
+// 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.= $db->order($sortfield,$sortorder);
+
+// Count total nb of records
+$nbtotalofrecords = 0;
+if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
+{
+    $result = $db->query($sql);
+    $nbtotalofrecords = $db->num_rows($result);
+}
+
+$sql.= $db->plimit($limit + 1,$offset);
 
 $resql = $db->query($sql);
 if ($resql)
@@ -70,164 +186,230 @@ if ($resql)
     $db->free($resql);
 }
 
-$nbtotalofrecords = $num;
 
 
 $help_url='EN:Module_Banks_and_Cash|FR:Module_Banques_et_Caisses|ES:M&oacute;dulo_Bancos_y_Cajas';
 llxHeader('',$title,$help_url);
 
 $link='';
-if ($statut == '') $link='<a href="'.$_SERVER["PHP_SELF"].'?statut=all">'.$langs->trans("IncludeClosedAccount").'</a>';
-if ($statut == 'all') $link='<a href="'.$_SERVER["PHP_SELF"].'">'.$langs->trans("OnlyOpenedAccount").'</a>';
 
-print_barre_liste($title,$page,$_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,$link,$num,$nbtotalofrecords,'title_bank.png',0,'','',$limit, 1);
 
+$num_rows = count($accounts);
 
+$arrayofselected=is_array($toselect)?$toselect:array();
 
-/*
- * Comptes courants (courant = 1)
- */
-print '<table class="liste" width="100%">';
-print '<tr class="liste_titre"><td width="30%">'.$langs->trans("CurrentAccounts").'</td>';
-print '<td width="20%">'.$langs->trans("Bank").'</td>';
-print '<td align="left">'.$langs->trans("AccountIdShort").'</td>';
-print '<td align="center">'.$langs->trans("TransactionsToConciliate").'</td>';
-print '<td align="center" width="70">'.$langs->trans("Status").'</td>';
-print '<td align="right" width="100">'.$langs->trans("BankBalance").'</td>';
-print "</tr>\n";
-
-$total = array(); $found = 0;
-$var=true;
-foreach ($accounts as $key=>$type)
+$param='';
+if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
+if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
+if ($statut != '')          $param.='&statut='.$statut;
+if ($show_files)            $param.='&show_files=' .$show_files;
+if ($optioncss != '')       $param.='&optioncss='.$optioncss;
+// Add $param from extra fields
+foreach ($search_array_options as $key => $val)
 {
-	if ($type == 1)
-	{
-	    $found++;
+    $crit=$val;
+    $tmpkey=preg_replace('/search_options_/','',$key);
+    if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
+}
 
-		$acc = new Account($db);
-		$acc->fetch($key);
+// List of mass actions available
+$arrayofmassactions =  array(
+//    'presend'=>$langs->trans("SendByMail"),
+//    'builddoc'=>$langs->trans("PDFMerge"),
+);
+if ($user->rights->banque->supprimer) $arrayofmassactions['delete']=$langs->trans("Delete");
+if ($massaction == 'presend') $arrayofmassactions=array();
+$massactionbutton=$form->selectMassAction('', $arrayofmassactions);
 
-		$var = !$var;
-		$solde = $acc->solde(1);
 
-		print '<tr '.$bc[$var].'>';
-		print '<td class="titlefield">'.$acc->getNomUrl(1).'</td>';
-		print '<td>'.$acc->bank.'</td>';
-		print '<td>'.$acc->number.'</td>';
-		print '<td align="center">';
-		if ($acc->rappro)
-		{
-			$result=$acc->load_board($user,$acc->id);
-            if ($result<0) {
-                setEventMessages($acc->error, $acc->errors, 'errors');
-            } else {
-                print $result->nbtodo;
-                if ($result->nbtodolate) print ' &nbsp; ('.$result->nbtodolate.img_warning($langs->trans("Late")).')';
-            }
-		}
-		else print $langs->trans("FeatureDisabled");
-		print '</td>';
-		print '<td align="center">'.$acc->getLibStatut(2).'</td>';
-		print '<td align="right">';
-		print '<a href="account.php?account='.$acc->id.'">'.price($solde, 0, $langs, 0, 0, -1, $acc->currency_code).'</a>';
-		print '</td>';
-		print '</tr>';
+// Lines of title fields
+print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
+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="viewstatut" value="'.$viewstatut.'">';
 
-		$total[$acc->currency_code] += $solde;
-	}
-}
-if (! $found) print '<tr '.$bc[$var].'><td colspan="6" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
-// Total
-foreach ($total as $key=>$solde)
+print_barre_liste($title,$page,$_SERVER["PHP_SELF"],$param,$sortfield,$sortorder,'',$num,$nbtotalofrecords,'title_bank.png',0,'','',$limit, 1);
+
+
+if ($sall)
 {
-	print '<tr class="liste_total"><td colspan="5" class="liste_total">'.$langs->trans("Total").' '.$key.'</td><td align="right" class="liste_total">'.price($solde, 0, $langs, 0, 0, -1, $key).'</td></tr>';
+    foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
+    print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall);
 }
 
-print '</table>';
-print '<br>';
+$moreforfilter='';
 
-/*
- * Comptes caisse/liquide (courant = 2)
- */
-print '<table class="liste" width="100%">';
-print '<tr class="liste_titre"><td width="30%">'.$langs->trans("CashAccounts").'</td><td width="20%">&nbsp;</td>';
-print '<td align="left">&nbsp;</td>';
-print '<td align="left" width="100">&nbsp;</td>';
-print '<td align="center" width="70">'.$langs->trans("Status").'</td>';
-print '<td align="right" width="100">'.$langs->trans("BankBalance").'</td>';
-print "</tr>\n";
 
-$total = array(); $found = 0;
-$var=true;
-foreach ($accounts as $key=>$type)
+// Bank accounts
+$parameters=array();
+$reshook=$hookmanager->executeHooks('printFieldPreListTitle',$parameters);    // Note that $action and $object may have been modified by hook
+if (empty($reshook)) $moreforfilter .= $hookmanager->resPrint;
+else $moreforfilter = $hookmanager->resPrint;
+
+if (! empty($moreforfilter))
 {
-	if ($type == 2)
-	{
-	    $found++;
+	print '<div class="liste_titre liste_titre_bydiv centpercent">';
+	print $moreforfilter;
+	print '</div>';
+}
 
-	    $acc = new Account($db);
-		$acc->fetch($key);
+$varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
+//$selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
 
-		$var = !$var;
-		$solde = $acc->solde(1);
+print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 
-		print "<tr ".$bc[$var].">";
-		print '<td width="30%">'.$acc->getNomUrl(1).'</td>';
-		print '<td>'.$acc->bank.'</td>';
-		print '<td>&nbsp;</td>';
-		print '<td>&nbsp;</td>';
-		print '<td align="center">'.$acc->getLibStatut(2).'</td>';
-		print '<td align="right">';
-		print '<a href="account.php?account='.$acc->id.'">'.price($solde, 0, $langs, 0, 0, -1, $acc->currency_code).'</a>';
-		print '</td>';
-		print '</tr>';
+// Fields title
+print '<tr class="liste_titre">';
+if (! empty($arrayfields['b.ref']['checked']))            print_liste_field_titre($arrayfields['b.ref']['label'],$_SERVER["PHP_SELF"],'b.ref','',$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['accountype']['checked']))       print_liste_field_titre($arrayfields['accountype']['label'],$_SERVER["PHP_SELF"],'','',$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['b.label']['checked']))          print_liste_field_titre($arrayfields['b.label']['label'],$_SERVER["PHP_SELF"],'b.label','',$param,'',$sortfield,$sortorder);
+if (! empty($arrayfields['b.number']['checked']))          print_liste_field_titre($arrayfields['b.number']['label'],$_SERVER["PHP_SELF"],'b.number','',$param,'',$sortfield,$sortorder);
+print '<td align="center">'.$langs->trans("TransactionsToConciliate").'</td>';
+print '<td align="center" width="70">'.$langs->trans("Status").'</td>';
+print '<td align="right" width="100">'.$langs->trans("BankBalance").'</td>';
+// Extra fields
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
+{
+   foreach($extrafields->attribute_label as $key => $val) 
+   {
+       if (! empty($arrayfields["ef.".$key]['checked'])) 
+       {
+			$align=$extrafields->getAlignFlag($key);
+			print_liste_field_titre($extralabels[$key],$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+       }
+   }
+}
+// Hook fields
+$parameters=array('arrayfields'=>$arrayfields);
+$reshook=$hookmanager->executeHooks('printFieldListTitle',$parameters);    // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="right"',$sortfield,$sortorder,'maxwidthsearch ');
+print "</tr>\n";
 
-		$total[$acc->currency_code] += $solde;
-	}
+
+print '<tr class="liste_titre">';
+// Ref
+if (! empty($arrayfields['b.ref']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '<input class="flat" size="6" type="text" name="search_ref" value="'.$search_ref.'">';
+    print '</td>';
 }
-if (! $found)
+// Account type
+if (! empty($arrayfields['accountype']['checked']))
 {
-	$var = !$var;
-	print '<tr '.$bc[false].'><td colspan="6" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
+    print '<td class="liste_titre">';
+    print '</td>';
 }
-// Total
-foreach ($total as $key=>$solde)
+// Ref
+if (! empty($arrayfields['b.label']['checked']))
 {
-	print '<tr class="liste_total"><td colspan="5" class="liste_total">'.$langs->trans("Total").' '.$key.'</td><td align="right" class="liste_total">'.price($solde, 0, $langs, 0, 0, -1, $key).'</td></tr>';
+    print '<td class="liste_titre">';
+    print '<input class="flat" size="6" type="text" name="search_label" value="'.$search_label.'">';
+    print '</td>';
 }
+// Number
+if (! empty($arrayfields['b.number']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '<input class="flat" size="6" type="text" name="search_number" value="'.$search_number.'">';
+    print '</td>';
+}
+// Transactions to reconcile
+if (! empty($arrayfields['toreconcile']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '</td>';
+}
+// Extra fields
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
+{
+    foreach($extrafields->attribute_label as $key => $val)
+    {
+        if (! empty($arrayfields["ef.".$key]['checked']))
+        {
+            $align=$extrafields->getAlignFlag($key);
+            $typeofextrafield=$extrafields->attribute_type[$key];
+            print '<td class="liste_titre'.($align?' '.$align:'').'">';
+            if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select')))
+            {
+                $crit=$val;
+                $tmpkey=preg_replace('/search_options_/','',$key);
+                $searchclass='';
+                if (in_array($typeofextrafield, array('varchar', 'select'))) $searchclass='searchstring';
+                if (in_array($typeofextrafield, array('int', 'double'))) $searchclass='searchnum';
+                print '<input class="flat'.($searchclass?' '.$searchclass:'').'" size="4" type="text" name="search_options_'.$tmpkey.'" value="'.dol_escape_htmltag($search_array_options['search_options_'.$tmpkey]).'">';
+            }
+            print '</td>';
+        }
+    }
+}
+// Fields from hook
+$parameters=array('arrayfields'=>$arrayfields);
+$reshook=$hookmanager->executeHooks('printFieldListOption',$parameters);    // Note that $action and $object may have been modified by hook
+print $hookmanager->resPrint;
+// Date creation
+if (! empty($arrayfields['b.datec']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '</td>';
+}
+// Date modification
+if (! empty($arrayfields['b.tms']['checked']))
+{
+    print '<td class="liste_titre">';
+    print '</td>';
+}
+// Statut
+if (! empty($arrayfields['b.clos']['checked']))
+{
+    print '<td class="liste_titre">';
+    $array=array(
+        'opened'=>$langs->trans("Opened"),
+        'closed'=>$langs->trans("Closed")
+    );
+    print $form->selectarray("statut", $array, $statut, 1);
+    print '</td>';
+}
+// Balance
+print '<td></td>';
+// Action column
+print '<td class="liste_titre" align="middle">';
+$searchpitco=$form->showFilterAndCheckAddButtons($massactionbutton?1:0, 'checkforselect', 1);
+print $searchpitco;
+print '</td>';
+print '</tr>';
 
-print '</table>';
-print '<br>';
 
-/*
- * Comptes placements (courant = 0)
- */
-print '<table class="liste" width="100%">';
-print '<tr class="liste_titre">';
-print '<td width="30%">'.$langs->trans("SavingAccounts").'</td>';
-print '<td width="20%">'.$langs->trans("Bank").'</td>';
-print '<td align="left">'.$langs->trans("Numero").'</td>';
-print '<td align="center">'.$langs->trans("TransactionsToConciliate").'</td>';
-print '<td align="center" width="70">'.$langs->trans("Status").'</td>';
-print '<td align="right" width="100">'.$langs->trans("BankBalance").'</td>';
-print "</tr>\n";
 
 $total = array(); $found = 0;
 $var=true;
 foreach ($accounts as $key=>$type)
 {
-	if ($type == 0)
-	{
+	//if ($type == 1)
+	//{
 	    $found++;
 
-	    $acc = new Account($db);
+		$acc = new Account($db);
 		$acc->fetch($key);
 
 		$var = !$var;
 		$solde = $acc->solde(1);
 
-		print "<tr ".$bc[$var].">";
-		print '<td width="30%">'.$acc->getNomUrl(1).'</td>';
+		
+		
+		
+		
+		print '<tr '.$bc[$var].'>';
+		print '<td class="titlefield">'.$acc->getNomUrl(1).'</td>';
+		print '<td>';
+		print $langs->trans("CashAccounts");
+		print $acc->type_lib[$acc->type];
+		print '</td>';
 		print '<td>'.$acc->bank.'</td>';
 		print '<td>'.$acc->number.'</td>';
 		print '<td align="center">';
@@ -238,7 +420,7 @@ foreach ($accounts as $key=>$type)
                 setEventMessages($acc->error, $acc->errors, 'errors');
             } else {
                 print $result->nbtodo;
-                if ($result->nbtodolate) print ' ('.$result->nbtodolate.img_warning($langs->trans("Late")).')';
+                if ($result->nbtodolate) print ' &nbsp; ('.$result->nbtodolate.img_warning($langs->trans("Late")).')';
             }
 		}
 		else print $langs->trans("FeatureDisabled");
@@ -247,27 +429,35 @@ foreach ($accounts as $key=>$type)
 		print '<td align="right">';
 		print '<a href="account.php?account='.$acc->id.'">'.price($solde, 0, $langs, 0, 0, -1, $acc->currency_code).'</a>';
 		print '</td>';
+		
+		// Action column
+		print '<td class="nowrap" align="center">';
+		if ($massactionbutton || $massaction)   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+		{
+		    $selected=0;
+		    if (in_array($obj->rowid, $arrayofselected)) $selected=1;
+		    print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected?' checked="checked"':'').'>';
+		}
+		print '</td>';
+		if (! $i) $totalarray['nbfield']++;
+		
 		print '</tr>';
 
 		$total[$acc->currency_code] += $solde;
-	}
-}
-if (! $found)
-{
-	$var = !$var;
-	print '<tr '.$bc[$var].'><td colspan="6" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
+	//}
 }
+if (! $found) print '<tr '.$bc[$var].'><td colspan="7" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
 // Total
 foreach ($total as $key=>$solde)
 {
-	print '<tr class="liste_total"><td colspan="5" class="liste_total">'.$langs->trans("Total").' '.$key.'</td><td align="right" class="liste_total">'.price($solde, 0, $langs, 0, 0, -1, $key).'</td></tr>';
+	print '<tr class="liste_total"><td colspan="6" class="liste_total">'.$langs->trans("Total").' '.$key.'</td><td align="right" class="liste_total">'.price($solde, 0, $langs, 0, 0, -1, $key).'</td></tr>';
 }
 
-print "</table>";
+print '</table>';
 
 
 /*
- * Boutons d'actions
+ * Buttons actions
  */
 
 print '<div class="tabsAction">'."\n";
diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php
index 8b466d655b3..a2384158926 100644
--- a/htdocs/projet/list.php
+++ b/htdocs/projet/list.php
@@ -383,16 +383,6 @@ if ($resql)
 
 	$moreforfilter='';
 	
-	// If the user can view thirdparties other than his'
-	if ($user->rights->societe->client->voir || $socid)
-	{
-		$langs->load("commercial");
-		$moreforfilter.='<div class="divsearchfield">';
-		$moreforfilter.=$langs->trans('ThirdPartiesOfSaleRepresentative'). ': ';
-		$moreforfilter.=$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, 1, 'maxwidth300');
-		$moreforfilter.='</div>';
-	}
-
 	// If the user can view user other than himself
 	$moreforfilter.='<div class="divsearchfield">';
 	$moreforfilter.=$langs->trans('ProjectsWithThisUserAsContact'). ': ';
@@ -411,6 +401,16 @@ if ($resql)
         $moreforfilter.='</div>';
 	}
 	
+	// If the user can view thirdparties other than his'
+	if ($user->rights->societe->client->voir || $socid)
+	{
+		$langs->load("commercial");
+		$moreforfilter.='<div class="divsearchfield">';
+		$moreforfilter.=$langs->trans('ThirdPartiesOfSaleRepresentative'). ': ';
+		$moreforfilter.=$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, 1, 'maxwidth300');
+		$moreforfilter.='</div>';
+	}
+
 	if (! empty($moreforfilter))
 	{
 		print '<div class="liste_titre liste_titre_bydiv centpercent">';
@@ -586,7 +586,9 @@ if ($resql)
 
     print '</tr>'."\n";
 
-    $i = 0;
+    $i=0;
+	$var=true;
+	$totalarray=array();
     while ($i < min($num,$limit))
     {
     	$obj = $db->fetch_object($resql);
@@ -612,6 +614,7 @@ if ($resql)
         		print $projectstatic->getNomUrl(1);
         		if ($projectstatic->hasDelay()) print img_warning($langs->trans('Late'));
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
     		// Title
         	if (! empty($arrayfields['p.title']['checked']))
@@ -619,6 +622,7 @@ if ($resql)
             	print '<td>';
         		print dol_trunc($obj->title,80);
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
     		// Company
         	if (! empty($arrayfields['s.nom']['checked']))
@@ -635,6 +639,7 @@ if ($resql)
         			print '&nbsp;';
         		}
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
     		// Sales Representatives
         	if (! empty($arrayfields['commercial']['checked']))
@@ -676,6 +681,7 @@ if ($resql)
         			print '&nbsp';
         		}
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
     		// Date start
         	if (! empty($arrayfields['p.dateo']['checked']))
@@ -683,13 +689,15 @@ if ($resql)
 				print '<td class="center">';
 	    		print dol_print_date($db->jdate($obj->date_start),'day');
 	    		print '</td>';
-			}
+    		    if (! $i) $totalarray['nbfield']++;
+        	}
     		// Date end
         	if (! empty($arrayfields['p.datee']['checked']))
         	{
     			print '<td class="center">';
         		print dol_print_date($db->jdate($obj->date_end),'day');
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
     		// Visibility
         	if (! empty($arrayfields['p.public']['checked']))
@@ -698,31 +706,46 @@ if ($resql)
         		if ($obj->public) print $langs->trans('SharedProject');
         		else print $langs->trans('PrivateProject');
         		print '</td>';
+    		    if (! $i) $totalarray['nbfield']++;
         	}
         	// Amount
         	if (! empty($arrayfields['p.opp_amount']['checked']))
         	{
     			print '<td align="right">';
-    			if ($obj->opp_status_code) print price($obj->opp_amount, 1, '', 1, -1, -1, '');
+    			if ($obj->opp_status_code) 
+    			{
+    			    print price($obj->opp_amount, 1, '', 1, -1, -1, '');
+    			    $totalarray['totalopp'] += $obj->opp_amount;
+    			}
     			print '</td>';
+    			if (! $i) $totalarray['nbfield']++;
+    			if (! $i) $totalarray['totaloppfield']=$totalarray['nbfield'];
         	}
         	if (! empty($arrayfields['p.fk_opp_status']['checked']))
         	{
                 print '<td align="middle">';
     			if ($obj->opp_status_code) print $langs->trans("OppStatusShort".$obj->opp_status_code);
     			print '</td>';
-    		}
+    		    if (! $i) $totalarray['nbfield']++;
+        	}
     	    if (! empty($arrayfields['p.opp_percent']['checked']))
         	{
     			print '<td align="right">';
     			if ($obj->opp_percent) print price($obj->opp_percent, 1, '', 1, 0).'%';
     			print '</td>';
-    	    }
+    		    if (! $i) $totalarray['nbfield']++;
+        	}
     	    if (! empty($arrayfields['p.budget_amount']['checked']))
         	{
     			print '<td align="right">';
-    			if ($obj->budget_amount != '') print price($obj->budget_amount, 1, '', 1, -1, -1);
+    			if ($obj->budget_amount != '') 
+    			{
+    			    print price($obj->budget_amount, 1, '', 1, -1, -1);
+    			    $totalarray['totalbudget'] += $obj->budget_amount;
+    			}
     			print '</td>';
+    			if (! $i) $totalarray['nbfield']++;
+    			if (! $i) $totalarray['totalbudgetfield']=$totalarray['nbfield'];
         	}
     		// Extra fields
     		if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
@@ -740,6 +763,7 @@ if ($resql)
     		            print '</td>';
     		        }
     		    }
+    		    if (! $i) $totalarray['nbfield']++;
     		}
     		// Fields from hook
     		$parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj);
@@ -751,6 +775,7 @@ if ($resql)
     		    print '<td align="center">';
     		    print dol_print_date($db->jdate($obj->date_creation), 'dayhour');
     		    print '</td>';
+    			if (! $i) $totalarray['nbfield']++;
     		}
     		// Date modification
     		if (! empty($arrayfields['p.tms']['checked']))
@@ -758,16 +783,26 @@ if ($resql)
     		    print '<td align="center">';
     		    print dol_print_date($db->jdate($obj->date_update), 'dayhour');
     		    print '</td>';
+    			if (! $i) $totalarray['nbfield']++;
     		}
     		// Status
     		if (! empty($arrayfields['p.fk_statut']['checked']))
     		{
         		$projectstatic->statut = $obj->fk_statut;
         		print '<td align="right">'.$projectstatic->getLibStatut(5).'</td>';
+    			if (! $i) $totalarray['nbfield']++;
     		}
-    		// Action column
-    		print '<td></td>';
-
+            // Action column
+            print '<td class="nowrap" align="center">';
+            if ($massactionbutton || $massaction)   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+            {
+                $selected=0;
+        		if (in_array($obj->rowid, $arrayofselected)) $selected=1;
+        		print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected?' checked="checked"':'').'>';
+            }
+            print '</td>';
+    		if (! $i) $totalarray['nbfield']++;
+    		
     		print "</tr>\n";
 
     	}
@@ -775,6 +810,27 @@ if ($resql)
     	$i++;
 
     }
+    
+    // Show total line
+    if (isset($totalarray['totaloppfield']) || isset($totalarray['totalbudgetfield']))
+    {
+        print '<tr class="liste_total">';
+        $i=0;
+        while ($i < $totalarray['nbfield'])
+        {
+            $i++;
+            if ($i == 1)
+            {
+                if ($num < $limit) print '<td align="left">'.$langs->trans("Total").'</td>';
+                else print '<td align="left">'.$langs->trans("Totalforthispage").'</td>';
+            }
+            elseif ($totalarray['totaloppfield'] == $i) print '<td align="right">'.price($totalarray['totalopp']).'</td>';
+            elseif ($totalarray['totalbudgetfield'] == $i) print '<td align="right">'.price($totalarray['totalbudget']).'</td>';
+            else print '<td></td>';
+        }
+        print '</tr>';
+    }
+    
     $db->free($resql);
 
 	$parameters=array('sql' => $sql);
diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php
index f32685f6eeb..bf5a0e66085 100644
--- a/htdocs/theme/eldy/style.css.php
+++ b/htdocs/theme/eldy/style.css.php
@@ -2773,6 +2773,9 @@ tr.liste_titre_topborder td {
 .liste_titre td a.notasortlink {
 	color: rgb(<?php echo $colortextlink; ?>);
 }
+.liste_titre td a.notasortlink:hover {
+	background: transparent;
+}
 
 tr.liste_titre_sel th, th.liste_titre_sel, tr.liste_titre_sel td, td.liste_titre_sel, form.liste_titre_sel div
 {
diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php
index fb0a8d972b2..4c790b20d44 100644
--- a/htdocs/theme/md/style.css.php
+++ b/htdocs/theme/md/style.css.php
@@ -2638,6 +2638,9 @@ tr.liste_titre_topborder td {
 .liste_titre td a.notasortlink {
 	color: rgb(<?php echo $colortextlink; ?>);
 }
+.liste_titre td a.notasortlink:hover {
+	background: transparent;
+}
 div.liste_titre {
 	padding-left: 3px;
 }
-- 
GitLab