From c088ccea32f98ebcdec91c11f575aea60af03e21 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Tue, 13 Jun 2017 18:50:31 +0200
Subject: [PATCH] Fix better management of export of extrafield computed.

---
 htdocs/compta/facture/list.php                |  96 ++++++++--------
 htdocs/core/extrafieldsinexport.inc.php       |  23 +++-
 htdocs/core/modules/DolibarrModules.class.php |  24 ++++
 htdocs/core/modules/modProjet.class.php       |  19 ++--
 htdocs/exports/class/export.class.php         |  50 +++++----
 htdocs/exports/export.php                     | 106 ++++++++++++------
 6 files changed, 198 insertions(+), 120 deletions(-)

diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php
index 00b18c00759..cf037942324 100644
--- a/htdocs/compta/facture/list.php
+++ b/htdocs/compta/facture/list.php
@@ -213,7 +213,7 @@ if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter") || GETPOS
     $search_state="";
     $search_type='';
     $search_country='';
-    $search_type_thirdparty='';    
+    $search_type_thirdparty='';
     $day='';
     $year='';
     $month='';
@@ -239,17 +239,17 @@ if (empty($reshook))
 if ($massaction == 'withdrawrequest')
 {
     $langs->load("withdrawals");
-    
+
     if (!$user->rights->prelevement->bons->creer)
     {
         $error++;
         setEventMessages($langs->trans("NotEnoughPermissions"), null, 'errors');
     }
-    else 
+    else
     {
         //Checking error
         $error = 0;
-        	
+
 	    $arrayofselected=is_array($toselect)?$toselect:array();
         $listofbills=array();
         foreach($arrayofselected as $toselectid)
@@ -274,7 +274,7 @@ if ($massaction == 'withdrawrequest')
                     $error++;
                     setEventMessages($objecttmp->ref.' '.$langs->trans("Draft"), $objecttmp->errors, 'errors');
                 }
-                	
+
                 $rsql = "SELECT pfd.rowid, pfd.traite, pfd.date_demande as date_demande";
                 $rsql .= " , pfd.date_traite as date_traite";
                 $rsql .= " , pfd.amount";
@@ -291,7 +291,7 @@ if ($massaction == 'withdrawrequest')
                 {
                     $numprlv = $db->num_rows($result_sql);
                 }
-                	
+
                 if($numprlv>0){
                     $error++;
                     setEventMessages($objecttmp->ref.' '.$langs->trans("RequestAlreadyDone"), $objecttmp->errors, 'errors');
@@ -300,7 +300,7 @@ if ($massaction == 'withdrawrequest')
                     $error++;
                     setEventMessages($objecttmp->ref.' '.$langs->trans("BadPaymentMethod"), $objecttmp->errors, 'errors');
                 }
-                	
+
             }
         }
 
@@ -327,13 +327,13 @@ if ($massaction == 'withdrawrequest')
             if ($nbwithdrawrequestok > 0)
             {
                 setEventMessages($langs->trans("WithdrawRequestsDone", $nbwithdrawrequestok), null, 'mesgs');
-            }   
+            }
         }
     }
 
 }
 
-    
+
 
 /*
  * View
@@ -350,7 +350,7 @@ llxHeader('',$langs->trans('CustomersInvoices'),'EN:Customers_Invoices|FR:Factur
 
 $sql = 'SELECT';
 if ($sall || $search_product_category > 0) $sql = 'SELECT DISTINCT';
-$sql.= ' f.rowid as facid, f.facnumber, f.ref_client, f.type, f.note_private, f.note_public, f.increment, f.fk_mode_reglement, f.total as total_ht, f.tva as total_vat, f.total_ttc,';
+$sql.= ' f.rowid as id, f.facnumber as ref, f.ref_client, f.type, f.note_private, f.note_public, f.increment, f.fk_mode_reglement, f.total as total_ht, f.tva as total_vat, f.total_ttc,';
 $sql.= ' f.localtax1 as total_localtax1, f.localtax2 as total_localtax2,';
 $sql.= ' f.datef as df, f.date_lim_reglement as datelimite,';
 $sql.= ' f.paye as paye, f.fk_statut,';
@@ -360,7 +360,7 @@ $sql.= " typent.code as typent_code,";
 $sql.= " state.code_departement as state_code, state.nom as state_name";
 // We need dynamount_payed to be able to sort on status (value is surely wrong because we can count several lines several times due to other left join or link with contacts. But what we need is just 0 or > 0)
 // TODO Better solution to be able to sort on already payed or remain to pay is to store amount_payed in a denormalized field.
-if (! $sall) $sql.= ', SUM(pf.amount) as dynamount_payed';   
+if (! $sall) $sql.= ', SUM(pf.amount) as dynamount_payed';
 // 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
@@ -424,7 +424,7 @@ if ($search_company) $sql .= natural_search('s.nom', $search_company);
 if ($search_montant_ht != '') $sql.= natural_search('f.total', $search_montant_ht, 1);
 if ($search_montant_vat != '') $sql.= natural_search('f.tva', $search_montant_vat, 1);
 if ($search_montant_localtax1 != '') $sql.= natural_search('f.localtax1', $search_montant_localtax1, 1);
-if ($search_montant_localtax2 != '') $sql.= natural_search('f.localtax2', $search_montant_localtax2, 1); 
+if ($search_montant_localtax2 != '') $sql.= natural_search('f.localtax2', $search_montant_localtax2, 1);
 if ($search_montant_ttc != '') $sql.= natural_search('f.total_ttc', $search_montant_ttc, 1);
 if ($search_status != '' && $search_status >= 0)
 {
@@ -577,7 +577,7 @@ if ($resql)
 	   $langs->load("withdrawals");
 	   $arrayofmassactions['withdrawrequest']=$langs->trans("MakeWithdrawRequest");
 	}
-	if ($user->rights->facture->supprimer) 
+	if ($user->rights->facture->supprimer)
 	{
 	    //if (! empty($conf->global->STOCK_CALCULATE_ON_BILL) || empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED))
 	    if (empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED))
@@ -608,8 +608,8 @@ if ($resql)
 	if ($massaction == 'presend')
 	{
 		$langs->load("mails");
-		
-		if (! GETPOST('cancel')) 
+
+		if (! GETPOST('cancel'))
 		{
 			$objecttmp=new Facture($db);
 			$listofselectedid=array();
@@ -618,7 +618,7 @@ if ($resql)
 			foreach($arrayofselected as $toselectid)
 			{
 				$result=$objecttmp->fetch($toselectid);
-				if ($result > 0) 
+				if ($result > 0)
 				{
 					$listofselectedid[$toselectid]=$toselectid;
 					$thirdpartyid=$objecttmp->fk_soc?$objecttmp->fk_soc:$objecttmp->socid;
@@ -629,10 +629,10 @@ if ($resql)
 		}
 
 		print '<input type="hidden" name="massaction" value="confirm_presend">';
-		
+
 		include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
 		$formmail = new FormMail($db);
-		
+
 		dol_fiche_head(null, '', '');
 
 		$topicmail="SendBillRef";
@@ -700,7 +700,7 @@ if ($resql)
 		//$formmail->param['returnurl']=$_SERVER["PHP_SELF"].'?id='.$object->id;
 
 		print $formmail->get_form();
-        
+
         dol_fiche_end();
 	}
 
@@ -709,7 +709,7 @@ if ($resql)
         foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
         print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall);
     }
-    
+
  	// If the user can view prospects other than his'
     $moreforfilter='';
  	if ($user->rights->societe->client->voir || $socid)
@@ -753,7 +753,7 @@ if ($resql)
     $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
     $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
     if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1);
-    
+
     print '<div class="div-table-responsive">';
     print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
 
@@ -788,7 +788,7 @@ if ($resql)
 		print '</td>';
 	}
 	// Date invoice
-	if (! empty($arrayfields['f.date']['checked'])) 
+	if (! empty($arrayfields['f.date']['checked']))
 	{
     	print '<td class="liste_titre" align="center">';
         if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="day" value="'.dol_escape_htmltag($day).'">';
@@ -797,7 +797,7 @@ if ($resql)
         print '</td>';
 	}
 	// Date due
-	if (! empty($arrayfields['f.date_lim_reglement']['checked'])) 
+	if (! empty($arrayfields['f.date_lim_reglement']['checked']))
 	{
     	print '<td class="liste_titre" align="center">';
         if (! empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat" type="text" size="1" maxlength="2" name="day_lim" value="'.dol_escape_htmltag($day_lim).'">';
@@ -812,7 +812,7 @@ if ($resql)
 	    print '<td class="liste_titre" align="left"><input class="flat" type="text" size="6" name="search_project" value="'.$search_project.'"></td>';
 	}
 	// Thirpdarty
-	if (! empty($arrayfields['s.nom']['checked'])) 
+	if (! empty($arrayfields['s.nom']['checked']))
 	{
 	   print '<td class="liste_titre" align="left"><input class="flat" type="text" size="6" name="search_societe" value="'.$search_societe.'"></td>';
 	}
@@ -842,7 +842,7 @@ if ($resql)
 	    print '</td>';
 	}
 	// Payment mode
-	if (! empty($arrayfields['f.fk_mode_reglement']['checked'])) 
+	if (! empty($arrayfields['f.fk_mode_reglement']['checked']))
 	{
     	print '<td class="liste_titre" align="left">';
     	$form->select_types_paiements($search_paymentmode, 'search_paymentmode', '', 0, 0, 1, 10);
@@ -987,8 +987,8 @@ if ($resql)
     if (! empty($arrayfields['f.tms']['checked']))       print_liste_field_titre($arrayfields['f.tms']['label'],$_SERVER["PHP_SELF"],"f.tms","",$param,'align="center" class="nowrap"',$sortfield,$sortorder);
     if (! empty($arrayfields['f.fk_statut']['checked'])) print_liste_field_titre($arrayfields['f.fk_statut']['label'],$_SERVER["PHP_SELF"],"fk_statut,paye,type,dynamount_payed","",$param,'align="right"',$sortfield,$sortorder);
     print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch ');
-    print "</tr>\n";    
-    
+    print "</tr>\n";
+
     if ($num > 0)
     {
         $i=0;
@@ -998,8 +998,8 @@ if ($resql)
             $obj = $db->fetch_object($resql);
 
             $datelimit=$db->jdate($obj->datelimite);
-            $facturestatic->id=$obj->facid;
-            $facturestatic->ref=$obj->facnumber;
+            $facturestatic->id=$obj->id;
+            $facturestatic->ref=$obj->ref;
             $facturestatic->type=$obj->type;
             $facturestatic->statut=$obj->fk_statut;
             $facturestatic->date_lim_reglement=$db->jdate($obj->datelimite);
@@ -1011,28 +1011,28 @@ if ($resql)
             $totaldeposits = $facturestatic->getSumDepositsUsed();
             $totalpay = $paiement + $totalcreditnotes + $totaldeposits;
             $remaintopay = $obj->total_ttc - $totalpay;
-            
+
             print '<tr class="oddeven">';
     		if (! empty($arrayfields['f.facnumber']['checked']))
     		{
                 print '<td class="nowrap">';
 
                 print '<table class="nobordernopadding"><tr class="nocellnopadd">';
-    
+
                 print '<td class="nobordernopadding nowrap">';
                 print $facturestatic->getNomUrl(1,'',200,0,'',0,1);
                 print empty($obj->increment)?'':' ('.$obj->increment.')';
                 print '</td>';
-    
+
                 print '<td style="min-width: 20px" class="nobordernopadding nowrap">';
-                $filename=dol_sanitizeFileName($obj->facnumber);
-                $filedir=$conf->facture->dir_output . '/' . dol_sanitizeFileName($obj->facnumber);
-                $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->facid;
+                $filename=dol_sanitizeFileName($obj->ref);
+                $filedir=$conf->facture->dir_output . '/' . dol_sanitizeFileName($obj->ref);
+                $urlsource=$_SERVER['PHP_SELF'].'?id='.$obj->id;
                 print $formfile->getDocumentsLink($facturestatic->element, $filename, $filedir);
     			print '</td>';
                 print '</tr>';
                 print '</table>';
-    
+
                 print "</td>\n";
     		    if (! $i) $totalarray['nbfield']++;
     		}
@@ -1089,7 +1089,7 @@ if ($resql)
     		    print '</td>';
     		    if (! $i) $totalarray['nbfield']++;
     		}
-    		
+
     		// Third party
     		if (! empty($arrayfields['s.nom']['checked']))
     		{
@@ -1256,18 +1256,18 @@ if ($resql)
                 print "</td>";
                 if (! $i) $totalarray['nbfield']++;
             }
-            
+
     		// 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->facid, $arrayofselected)) $selected=1;
-        		print '<input id="cb'.$obj->facid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->facid.'"'.($selected?' checked="checked"':'').'>';
+        		if (in_array($obj->id, $arrayofselected)) $selected=1;
+        		print '<input id="cb'.$obj->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->id.'"'.($selected?' checked="checked"':'').'>';
             }
     		print '</td>' ;
     		if (! $i) $totalarray['nbfield']++;
-				
+
             print "</tr>\n";
 
             $i++;
@@ -1303,31 +1303,31 @@ if ($resql)
     		   else print '<td></td>';
     		}
     		print '</tr>';
-    		
+
     	}
     }
 
     $db->free($resql);
-	
+
 	$parameters=array('arrayfields'=>$arrayfields, 'sql'=>$sql);
 	$reshook=$hookmanager->executeHooks('printFieldListFooter',$parameters);    // Note that $action and $object may have been modified by hook
 	print $hookmanager->resPrint;
-    
+
 	print "</table>\n";
     print '</div>';
-    
+
     print "</form>\n";
-    
+
     if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files)
     {
         // Show list of available documents
         $urlsource=$_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
         $urlsource.=str_replace('&amp;','&',$param);
-        
+
         $filedir=$diroutputmassaction;
         $genallowed=$user->rights->facture->lire;
         $delallowed=$user->rights->facture->lire;
-    
+
         print $formfile->showdocuments('massfilesarea_invoices','',$filedir,$urlsource,0,$delallowed,'',1,1,0,48,1,$param,$title,'');
     }
     else
diff --git a/htdocs/core/extrafieldsinexport.inc.php b/htdocs/core/extrafieldsinexport.inc.php
index ac22841ad20..7f9cf523105 100644
--- a/htdocs/core/extrafieldsinexport.inc.php
+++ b/htdocs/core/extrafieldsinexport.inc.php
@@ -8,7 +8,7 @@ if (empty($keyforselect) || empty($keyforelement) || empty($keyforaliasextra))
 }
 
 // Add extra fields
-$sql="SELECT name, label, type, param FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = '".$keyforselect."' AND type != 'separate' AND entity IN (0, ".$conf->entity.')';
+$sql="SELECT name, label, type, param, fieldcomputed, fielddefault FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = '".$keyforselect."' AND type != 'separate' AND entity IN (0, ".$conf->entity.')';
 //print $sql;
 $resql=$this->db->query($sql);
 if ($resql)    // This can fail when class is used on old database (during migration for example)
@@ -42,10 +42,23 @@ if ($resql)    // This can fail when class is used on old database (during migra
 				if (preg_match('/[a-z0-9_]+:[a-z0-9_]+:[a-z0-9_]+/', $tmp)) $typeFilter="List:".$tmp;
 				break;
 		}
-		if ($obj->type!='separate') {
-			$this->export_fields_array[$r][$fieldname]=$fieldlabel;
-			$this->export_TypeFields_array[$r][$fieldname]=$typeFilter;
-			$this->export_entities_array[$r][$fieldname]=$keyforelement;
+		if ($obj->type!='separate')
+		{
+		    // If not a computed field
+		    if (empty($obj->fieldcomputed))
+		    {
+    			$this->export_fields_array[$r][$fieldname]=$fieldlabel;
+    			$this->export_TypeFields_array[$r][$fieldname]=$typeFilter;
+    			$this->export_entities_array[$r][$fieldname]=$keyforelement;
+		    }
+			// If this is a computed field
+			else
+			{
+			    $this->export_fields_array[$r][$fieldname]=$fieldlabel;
+			    $this->export_TypeFields_array[$r][$fieldname]=$typeFilter.'Compute';
+			    $this->export_special_array[$r][$fieldname]=$obj->fieldcomputed;
+			    $this->export_entities_array[$r][$fieldname]=$keyforelement;
+			}
 		}
 	}
 }
diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php
index a79f17b1fdc..37e72024e2a 100644
--- a/htdocs/core/modules/DolibarrModules.class.php
+++ b/htdocs/core/modules/DolibarrModules.class.php
@@ -215,6 +215,9 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      */
     public $descriptionlong;
 
+
+    // For exports
+
     /**
      * @var string Module export code
      */
@@ -225,6 +228,19 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      */
     public $export_label;
 
+    public $export_permission;
+    public $export_fields_array;
+    public $export_TypeFields_array;
+    public $export_entities_array;
+    public $export_special_array;           // special or computed field
+    public $export_dependencies_array;
+    public $export_sql_start;
+    public $export_sql_end;
+    public $export_sql_order;
+
+
+    // For import
+
     /**
      * @var string Module import code
      */
@@ -235,6 +251,7 @@ class DolibarrModules           // Can not be abstract, because we need to insta
      */
     public $import_label;
 
+
     /**
      * @var string Module constant name
      */
@@ -343,6 +360,13 @@ class DolibarrModules           // Can not be abstract, because we need to insta
 	public $hidden = false;
 
 
+
+
+
+
+
+
+
 	/**
 	 * Constructor. Define names, constants, directories, boxes, permissions
 	 *
diff --git a/htdocs/core/modules/modProjet.class.php b/htdocs/core/modules/modProjet.class.php
index 071912e1c00..af71ccc4360 100644
--- a/htdocs/core/modules/modProjet.class.php
+++ b/htdocs/core/modules/modProjet.class.php
@@ -116,14 +116,14 @@ class modProjet extends DolibarrModules
 		$this->const[$r][3] = "";
 		$this->const[$r][4] = 0;
 		$r++;
-		                       
+
 		$this->const[$r][0] = "PROJECT_USE_OPPORTUNITIES";
 		$this->const[$r][1] = "chaine";
 		$this->const[$r][2] = "1";
 		$this->const[$r][3] = "";
 		$this->const[$r][4] = 0;
 		$r++;
-		
+
 		$this->const[$r][0] = "MAIN_DELAY_PROJECT_TO_CLOSE";
 		$this->const[$r][1] = "chaine";
 		$this->const[$r][2] = "7";
@@ -136,7 +136,7 @@ class modProjet extends DolibarrModules
 		$this->const[$r][3] = "";
 		$this->const[$r][4] = 0;
 		$r++;
-		
+
 		// Boxes
 		$this->boxes = array();
 		$r=0;
@@ -207,7 +207,7 @@ class modProjet extends DolibarrModules
 		//-------
 		$this->menu = 1;        // This module add menu entries. They are coded into menu manager.
 
-		
+
 		//Exports
 		//--------
 		$r=1;
@@ -240,15 +240,16 @@ class modProjet extends DolibarrModules
 		    unset($this->export_fields_array[$r]['p.opp_amount']);
 		    unset($this->export_fields_array[$r]['cls.code']);
 		}
-		
+
 		// Add fields for project
 		$this->export_fields_array[$r]=array_merge($this->export_fields_array[$r], array());
+		// Add extra fields for project
 		$keyforselect='projet'; $keyforelement='project'; $keyforaliasextra='extra';
 		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
 		// Add fields for tasks
         $this->export_fields_array[$r]=array_merge($this->export_fields_array[$r], array('pt.rowid'=>'RefTask','pt.label'=>'LabelTask','pt.dateo'=>"TaskDateStart",'pt.datee'=>"TaskDateEnd",'pt.duration_effective'=>"DurationEffective",'pt.planned_workload'=>"PlannedWorkload",'pt.progress'=>"Progress",'pt.description'=>"TaskDescription"));
 		$this->export_entities_array[$r]=array_merge($this->export_entities_array[$r], array('pt.rowid'=>'projecttask','pt.label'=>'projecttask','pt.dateo'=>"projecttask",'pt.datee'=>"projecttask",'pt.duration_effective'=>"projecttask",'pt.planned_workload'=>"projecttask",'pt.progress'=>"projecttask",'pt.description'=>"projecttask"));
-        // Add extra fields
+        // Add extra fields for task
 		$keyforselect='projet_task'; $keyforelement='projecttask'; $keyforaliasextra='extra2';
 		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
         // End add extra fields
@@ -264,8 +265,8 @@ class modProjet extends DolibarrModules
 		$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX."projet_task_time as ptt ON pt.rowid = ptt.fk_task";
 		$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe as s ON p.fk_soc = s.rowid';
 		$this->export_sql_end[$r] .=' WHERE p.entity = '.$conf->entity;
-		
-		
+
+
 		// Import list of tasks
 		if (empty($conf->global->PROJECT_HIDE_TASKS))
 		{
@@ -297,7 +298,7 @@ class modProjet extends DolibarrModules
     		//$this->import_convertvalue_array[$r]=array('s.fk_soc'=>array('rule'=>'lastrowid',table='t');
     		$this->import_regex_array[$r]=array('t.dateo'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$','t.datee'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$','t.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?$');
     		$this->import_examplevalues_array[$r]=array('t.fk_projet'=>'MyProjectRef','t.ref'=>"auto or TK2010-1234",'t.label'=>"My task",'t.progress'=>"0 (not started) to 100 (finished)",'t.datec'=>'1972-10-10','t.note_private'=>"My private note",'t.note_public'=>"My public note");
-		}		
+		}
 	}
 
 
diff --git a/htdocs/exports/class/export.class.php b/htdocs/exports/class/export.class.php
index 298950abe8e..4c9d6eaabb4 100644
--- a/htdocs/exports/class/export.class.php
+++ b/htdocs/exports/class/export.class.php
@@ -38,6 +38,7 @@ class Export
 	var $array_export_sql_start=array();        // Tableau des "requetes sql"
 	var $array_export_sql_end=array();          // Tableau des "requetes sql"
 	var $array_export_sql_order=array();        // Tableau des "requetes sql"
+
 	var $array_export_fields=array();           // Tableau des listes de champ+libelle a exporter
 	var $array_export_TypeFields=array();		// Tableau des listes de champ+Type de filtre
 	var $array_export_FilterValue=array();		// Tableau des listes de champ+Valeur a filtrer
@@ -45,7 +46,7 @@ class Export
 	var $array_export_dependencies=array();     // array of list of entities that must take care of the DISTINCT if a field is added into export
 	var $array_export_special=array();          // Tableau des operations speciales sur champ
     var $array_export_examplevalues=array();    // array with examples
-    
+
 	// To store export modules
 	var $hexa;
 	var $hexafiltervalue;
@@ -178,7 +179,7 @@ class Export
 									$this->array_export_special[$i]=(! empty($module->export_special_array[$r])?$module->export_special_array[$r]:'');
             						// Array of examples
             						$this->array_export_examplevalues[$i]=$module->export_examplevalues_array[$r];
-									
+
 									// Requete sql du dataset
 									$this->array_export_sql_start[$i]=$module->export_sql_start[$r];
 									$this->array_export_sql_end[$i]=$module->export_sql_end[$r];
@@ -246,7 +247,7 @@ class Export
 			}
 			$sql.=$sqlWhere;
 		}
-		
+
 		// Add the order
 		$sql.=$this->array_export_sql_order[$indice];
 
@@ -259,7 +260,7 @@ class Export
 		        if (preg_match('/GROUP_CONCAT/i', $key) and $value != '') $sql.=" HAVING ".$this->build_filterQuery($this->array_export_TypeFields[$indice][$key], $key, $array_filterValue[$key]);
 		    }
 		}
-		
+
 		return $sql;
 	}
 
@@ -281,7 +282,7 @@ class Export
 				if (! (strpos($ValueField, '%') === false))
 					$szFilterQuery.=" ".$NameField." LIKE '".$ValueField."'";
 				else
-					$szFilterQuery.=" ".$NameField."='".$ValueField."'";
+					$szFilterQuery.=" ".$NameField." = '".$ValueField."'";
 				break;
 			case 'Date':
 				if (strpos($ValueField, "+") > 0)
@@ -325,8 +326,12 @@ class Export
 			case 'List':
 				if (is_numeric($ValueField))
 					$szFilterQuery=" ".$NameField."=".$ValueField;
-				else
-					$szFilterQuery=" ".$NameField."='".$ValueField."'";
+				else {
+                    if (! (strpos($ValueField, '%') === false))
+                        $szFilterQuery=" ".$NameField." LIKE '".$ValueField."'";
+                    else
+                        $szFilterQuery=" ".$NameField." = '".$ValueField."'";
+				}
 				break;
 			default:
 			    dol_syslog("Error we try to forge an sql export request with a condition on a field with type '".$InfoFieldList[0]."' (defined into module descriptor) but this type is unknown/not supported. It looks like a bug into module descriptor.", LOG_ERR);
@@ -589,10 +594,8 @@ class Export
 
 				$var=true;
 
-				while ($objp = $this->db->fetch_object($resql))
+				while ($obj = $this->db->fetch_object($resql))
 				{
-					
-
 					// Process special operations
 					if (! empty($this->array_export_special[$indice]))
 					{
@@ -604,14 +607,14 @@ class Export
 							{
 								//$alias=$this->array_export_alias[$indice][$key];
 								$alias=str_replace(array('.', '-','(',')'),'_',$key);
-								if ($objp->$alias < 0) $objp->$alias='';
+								if ($obj->$alias < 0) $obj->$alias='';
 							}
 							// Operation ZEROIFNEG
 							elseif ($this->array_export_special[$indice][$key]=='ZEROIFNEG')
 							{
 								//$alias=$this->array_export_alias[$indice][$key];
 								$alias=str_replace(array('.', '-','(',')'),'_',$key);
-								if ($objp->$alias < 0) $objp->$alias='0';
+								if ($obj->$alias < 0) $obj->$alias='0';
 							}
 							// Operation INVOICEREMAINTOPAY
 							elseif ($this->array_export_special[$indice][$key]=='getRemainToPay')
@@ -619,29 +622,34 @@ class Export
 								//$alias=$this->array_export_alias[$indice][$key];
 								$alias=str_replace(array('.', '-','(',')'),'_',$key);
 								$remaintopay='';
-								if ($objp->f_rowid > 0)
+								if ($obj->f_rowid > 0)
 								{
 								    global $tmpobjforcomputecall;
-								    if (! is_object($tmpobjforcomputecall)) 
+								    if (! is_object($tmpobjforcomputecall))
 								    {
 								        include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
 								        $tmpobjforcomputecall=new Facture($this->db);
 								    }
-								    $tmpobjforcomputecall->id = $objp->f_rowid;
-								    $tmpobjforcomputecall->total_ttc = $objp->f_total_ttc;
+								    $tmpobjforcomputecall->id = $obj->f_rowid;
+								    $tmpobjforcomputecall->total_ttc = $obj->f_total_ttc;
 								    $remaintopay=$tmpobjforcomputecall->getRemainToPay();
-								}								
-								$objp->$alias=$remaintopay;
+								}
+								$obj->$alias=$remaintopay;
 							}
 							else
 							{
-							    $this->error='Operation '.$this->array_export_special[$indice][$key].' not supported.';
+							    // TODO FIXME Export of compute field does not work. $obj containt $obj->alias_field and formulat will contains $obj->field
+							    $computestring=$this->array_export_special[$indice][$key];
+							    $tmp=dol_eval($computestring, 1, 0);
+							    $obj->$alias=$tmp;
+
+							    $this->error="ERROPNOTSUPPORTED. Operation ".$this->array_export_special[$indice][$key]." not supported. Export of 'computed' extrafields is not yet supported, please remove field.";
 							    return -1;
 							}
 						}
 					}
 					// end of special operation processing
-					$objmodel->write_record($array_selected,$objp,$outputlangs,$this->array_export_TypeFields[$indice]);
+					$objmodel->write_record($array_selected,$obj,$outputlangs,$this->array_export_TypeFields[$indice]);
 				}
 
 				// Genere en-tete
@@ -732,7 +740,7 @@ class Export
 				$this->id				= $obj->rowid;
 				$this->model_name		= $obj->label;
 				$this->datatoexport		= $obj->type;
-				
+
 				$this->hexa				= $obj->field;
 				$this->hexafiltervalue	= $obj->filter;
 
diff --git a/htdocs/exports/export.php b/htdocs/exports/export.php
index 43453041dfd..909db84fcb4 100644
--- a/htdocs/exports/export.php
+++ b/htdocs/exports/export.php
@@ -168,7 +168,7 @@ if ($action=='selectfield')     // Selection of field at step 2
         $warnings=array();
 
         $array_selected[$field]=count($array_selected)+1;    // We tag the key $field as "selected"
-        // We check if there is a dependency to activate 
+        // We check if there is a dependency to activate
         /*var_dump($field);
         var_dump($fieldsentitiesarray[$field]);
         var_dump($fieldsdependenciesarray);*/
@@ -187,7 +187,7 @@ if ($action=='selectfield')     // Selection of field at step 2
             if (is_array($tmp)) $listofdependencies=$tmp;
             else $listofdependencies=array($tmp);
         }
-        
+
         if (count($listofdependencies))
         {
             foreach($listofdependencies as $fieldid)
@@ -270,7 +270,7 @@ if ($action == 'builddoc')
     {
         @ini_set("max_execution_time", $max_execution_time_for_export); // This work only if safe mode is off. also web servers has timeout of 300
     }
-    
+
     // Build export file
 	$result=$objexport->build_file($user, GETPOST('model','alpha'), $datatoexport, $array_selected, $array_filtervalue);
 	if ($result < 0)
@@ -535,9 +535,9 @@ if ($step == 2 && $datatoexport)
 
     print '</table>';
     print '</div>';
-    
+
     dol_fiche_end();
-    
+
     print '<br>';
 
     // Combo list of export models
@@ -561,7 +561,7 @@ if ($step == 2 && $datatoexport)
     print '<td>'.$langs->trans("ExportableFields").'</td>';
     print '<td width="100" align="center">';
     print '<a class="liste_titre" title='.$langs->trans("All").' alt='.$langs->trans("All").' href="'.$_SERVER["PHP_SELF"].'?step=2&datatoexport='.$datatoexport.'&action=selectfield&field=all">'.$langs->trans("All")."</a>";
-    print '/';
+    print ' / ';
     print '<a class="liste_titre" title='.$langs->trans("None").' alt='.$langs->trans("None").' href="'.$_SERVER["PHP_SELF"].'?step=2&datatoexport='.$datatoexport.'&action=unselectfield&field=all">'.$langs->trans("None")."</a>";
     print '</td>';
     print '<td width="44%">'.$langs->trans("ExportedFields").'</td>';
@@ -585,7 +585,7 @@ if ($step == 2 && $datatoexport)
 
     foreach($fieldsarray as $code=>$label)
     {
-        
+
         print '<tr class="oddeven">';
 
         $i++;
@@ -597,7 +597,7 @@ if ($step == 2 && $datatoexport)
         print '<td class="nowrap">';
         // If value of entityicon=entitylang='icon:Label'
         //print $code.'-'.$label.'-'.$entity;
-        
+
         $tmparray=explode(':',$entityicon);
         if (count($tmparray) >=2)
         {
@@ -606,7 +606,9 @@ if ($step == 2 && $datatoexport)
         }
         print img_object('',$entityicon).' '.$langs->trans($entitylang);
         print '</td>';
-        $text=$langs->trans($label);
+
+        $text=(empty($objexport->array_export_special[0][$code])?'':'<i>').$langs->trans($label).(empty($objexport->array_export_special[0][$code])?'':'</i>');
+
         $tablename=getablenamefromfield($code,$sqlmaxforexport);
         $htmltext ='<b>'.$langs->trans("Name").":</b> ".$text.'<br>';
         if (! empty($objexport->array_export_special[0][$code]))
@@ -617,11 +619,16 @@ if ($step == 2 && $datatoexport)
         {
             $htmltext.='<b>'.$langs->trans("Table")." -> ".$langs->trans("Field").":</b> ".$tablename." -> ".preg_replace('/^.*\./','',$code)."<br>";
         }
-		if (! empty($objexport->array_export_examplevalues[0][$code]))
+   		if (! empty($objexport->array_export_examplevalues[0][$code]))
 		{
 		    $htmltext.=$langs->trans("SourceExample").': <b>'.$objexport->array_export_examplevalues[0][$code].'</b><br>';
 		}
-        if (isset($array_selected[$code]) && $array_selected[$code])
+    	if (! empty($objexport->array_export_TypeFields[0][$code]))
+		{
+		    $htmltext.=$langs->trans("Type").': <b>'.$objexport->array_export_TypeFields[0][$code].'</b><br>';
+		}
+
+		if (isset($array_selected[$code]) && $array_selected[$code])
         {
             // Selected fields
             print '<td>&nbsp;</td>';
@@ -649,7 +656,7 @@ if ($step == 2 && $datatoexport)
 
     print '</table>';
 
-    
+
     /*
      * Barre d'action
      */
@@ -740,7 +747,7 @@ if ($step == 3 && $datatoexport)
 
 	print '</table>';
 	print '</div>';
-	
+
 	print '<br>';
 
 	// Combo list of export models
@@ -772,7 +779,6 @@ if ($step == 3 && $datatoexport)
 	// on boucle sur les champs
 	foreach($fieldsarray as $code => $label)
 	{
-		
 		print '<tr class="oddeven">';
 
 		$i++;
@@ -794,15 +800,27 @@ if ($step == 3 && $datatoexport)
 		// Field name
 		$labelName=(! empty($fieldsarray[$code])?$fieldsarray[$code]:'');
 		$ValueFilter=(! empty($array_filtervalue[$code])?$array_filtervalue[$code]:'');
-		$text=$langs->trans($labelName);
+		$text=(empty($objexport->array_export_special[0][$code])?'':'<i>').$langs->trans($labelName).(empty($objexport->array_export_special[0][$code])?'':'</i>');
 
 		$tablename=getablenamefromfield($code,$sqlmaxforexport);
 		$htmltext ='<b>'.$langs->trans("Name").':</b> '.$text.'<br>';
-		$htmltext.='<b>'.$langs->trans("Table")." -> ".$langs->trans("Field").":</b> ".$tablename." -> ".preg_replace('/^.*\./','',$code)."<br>";
+			if (! empty($objexport->array_export_special[0][$code]))
+		{
+		    $htmltext.='<b>'.$langs->trans("ComputedField")." -> ".$langs->trans("Method")." :</b> ".$objexport->array_export_special[0][$code]."<br>";
+		}
+		else
+		{
+		    $htmltext.='<b>'.$langs->trans("Table")." -> ".$langs->trans("Field").":</b> ".$tablename." -> ".preg_replace('/^.*\./','',$code)."<br>";
+		}
 		if (! empty($objexport->array_export_examplevalues[0][$code]))
 		{
 		    $htmltext.=$langs->trans("SourceExample").': <b>'.$objexport->array_export_examplevalues[0][$code].'</b><br>';
 		}
+		if (! empty($objexport->array_export_TypeFields[0][$code]))
+		{
+		    $htmltext.=$langs->trans("Type").': <b>'.$objexport->array_export_TypeFields[0][$code].'</b><br>';
+		}
+
 		print '<td>';
 		print $form->textwithpicto($text,$htmltext);
 		print '</td>';
@@ -849,7 +867,7 @@ if ($step == 4 && $datatoexport)
         header("Location: ".DOL_URL_ROOT.'/exports/export.php?step=2&datatoexport='.$datatoexport);
         exit;
     }
-    
+
     asort($array_selected);
 
     llxHeader('',$langs->trans("NewExport"),'EN:Module_Exports_En|FR:Module_Exports|ES:M&oacute;dulo_Exportaciones');
@@ -937,7 +955,7 @@ if ($step == 4 && $datatoexport)
 
     print '</table>';
     print '</div>';
-    
+
     print '<br>';
 
     // Select request if all fields are selected
@@ -957,7 +975,6 @@ if ($step == 4 && $datatoexport)
     $var=true;
     foreach($array_selected as $code=>$value)
     {
-        
         print '<tr class="oddeven">';
 
         $entity=(! empty($objexport->array_export_entities[0][$code])?$objexport->array_export_entities[0][$code]:$objexport->array_export_icon[0]);
@@ -975,15 +992,30 @@ if ($step == 4 && $datatoexport)
         print img_object('',$entityicon).' '.$langs->trans($entitylang);
         print '</td>';
 
-        print '<td>';
-        $text=$langs->trans($objexport->array_export_fields[0][$code]);
+        $labelName=$objexport->array_export_fields[0][$code];
+
+		$text=(empty($objexport->array_export_special[0][$code])?'':'<i>').$langs->trans($labelName).(empty($objexport->array_export_special[0][$code])?'':'</i>');
+
         $tablename=getablenamefromfield($code,$sqlmaxforexport);
-        $htmltext ='<b>'.$langs->trans("Name").":</b> ".$text.'<br>';
-        $htmltext.='<b>'.$langs->trans("Table")." -> ".$langs->trans("Field").":</b> ".$tablename." -> ".preg_replace('/^.*\./','',$code)."<br>";
-    	if (! empty($objexport->array_export_examplevalues[0][$code]))
-		{
-		    $htmltext.=$langs->trans("SourceExample").': <b>'.$objexport->array_export_examplevalues[0][$code].'</b><br>';
-		}
+        $htmltext ='<b>'.$langs->trans("Name").':</b> '.$text.'<br>';
+        if (! empty($objexport->array_export_special[0][$code]))
+        {
+            $htmltext.='<b>'.$langs->trans("ComputedField")." -> ".$langs->trans("Method")." :</b> ".$objexport->array_export_special[0][$code]."<br>";
+        }
+        else
+        {
+            $htmltext.='<b>'.$langs->trans("Table")." -> ".$langs->trans("Field").":</b> ".$tablename." -> ".preg_replace('/^.*\./','',$code)."<br>";
+        }
+        if (! empty($objexport->array_export_examplevalues[0][$code]))
+        {
+            $htmltext.=$langs->trans("SourceExample").': <b>'.$objexport->array_export_examplevalues[0][$code].'</b><br>';
+        }
+        if (! empty($objexport->array_export_TypeFields[0][$code]))
+        {
+            $htmltext.=$langs->trans("Type").': <b>'.$objexport->array_export_TypeFields[0][$code].'</b><br>';
+        }
+
+        print '<td>';
         print $form->textwithpicto($text,$htmltext);
 		//print ' ('.$code.')';
         print '</td>';
@@ -1056,7 +1088,7 @@ if ($step == 4 && $datatoexport)
 			$var=false;
 			while ($i < $num)
 			{
-				
+
 				$obj = $db->fetch_object($resql);
 				print '<tr class="oddeven"><td>';
 				print $obj->label;
@@ -1085,7 +1117,7 @@ if ($step == 5 && $datatoexport)
         header("Location: ".DOL_URL_ROOT.'/exports/export.php?step=2&datatoexport='.$datatoexport);
         exit;
     }
-    
+
 	asort($array_selected);
 
     llxHeader('',$langs->trans("NewExport"),'EN:Module_Exports_En|FR:Module_Exports|ES:M&oacute;dulo_Exportaciones');
@@ -1135,7 +1167,7 @@ if ($step == 5 && $datatoexport)
 
     print '<div class="fichecenter">';
     print '<div class="underbanner clearboth"></div>';
-    
+
     print '<table width="100%" class="border">';
 
     // Module
@@ -1186,7 +1218,7 @@ if ($step == 5 && $datatoexport)
 
     print '</table>';
     print '</div>';
-    
+
     print '<br>';
 
     print $langs->trans("NowClickToGenerateToBuildExportFile").'<br>';
@@ -1210,7 +1242,7 @@ if ($step == 5 && $datatoexport)
     		unset($liste[$key]);
     	}
 
-        
+
         print '<tr class="oddeven">';
         print '<td width="16">'.img_picto_common($key,$objmodelexport->getPictoForKey($key)).'</td>';
 	    $text=$objmodelexport->getDriverDescForKey($key);
@@ -1222,7 +1254,7 @@ if ($step == 5 && $datatoexport)
 
     print '</div>';
 
-    
+
     print '<table width="100%">';
 
     if ($sqlusedforexport && $user->admin)
@@ -1233,7 +1265,7 @@ if ($step == 5 && $datatoexport)
     }
 	print '</table>';
 
-	
+
 	print '<div class="fichecenter"><div class="fichehalfleft">';
 
     if (! is_dir($conf->export->dir_temp)) dol_mkdir($conf->export->dir_temp);
@@ -1243,7 +1275,7 @@ if ($step == 5 && $datatoexport)
     print $formfile->showdocuments('export','',$upload_dir,$_SERVER["PHP_SELF"].'?step=5&datatoexport='.$datatoexport,$liste,1,(! empty($_POST['model'])?$_POST['model']:'csv'),1,1);
 
     print '</div><div class="fichehalfright"><div class="ficheaddleft">';
-    
+
     print '</div></div></div>';
 }
 
@@ -1265,11 +1297,11 @@ function getablenamefromfield($code,$sqlmaxforexport)
 {
 	$alias=preg_replace('/\.(.*)$/i','',$code);         // Keep only 'Alias' and remove '.Fieldname'
 	$regexstring='/([a-zA-Z_]+) as '.preg_quote($alias).'[, \)]/i';
-    
+
 	$newsql=$sqlmaxforexport;
 	$newsql=preg_replace('/^(.*) FROM /i','',$newsql);  // Remove part before the FROM
 	$newsql=preg_replace('/WHERE (.*)$/i','',$newsql);	// Remove part after the WHERE so we have now only list of table aliases in a string. We must keep the ' ' before WHERE
-	
+
 	if (preg_match($regexstring,$newsql,$reg))
 	{
 		return $reg[1];   // The tablename
-- 
GitLab