From aff61fad7d8dafff87280a25b87ae0a7685faaa0 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Tue, 25 Jul 2017 01:21:20 +0200
Subject: [PATCH] Fix new generic classes system

---
 .../modulebuilder/template/myobject_card.php  |    5 +-
 .../modulebuilder/template/myobject_list.php  |    2 +-
 htdocs/product/inventory/card.php             | 1134 ++++++++---------
 .../inventory/class/inventory.class.php       |  843 +++---------
 htdocs/product/inventory/list.php             |  695 ++++++++--
 htdocs/product/inventory/listview.class.php   | 1083 ----------------
 6 files changed, 1347 insertions(+), 2415 deletions(-)
 delete mode 100644 htdocs/product/inventory/listview.class.php

diff --git a/htdocs/modulebuilder/template/myobject_card.php b/htdocs/modulebuilder/template/myobject_card.php
index b5de4c0226c..e8cc7e33735 100644
--- a/htdocs/modulebuilder/template/myobject_card.php
+++ b/htdocs/modulebuilder/template/myobject_card.php
@@ -18,9 +18,8 @@
 
 /**
  *   	\file       htdocs/modulebuilder/template/myobject_card.php
- *		\ingroup    mymodule othermodule1 othermodule2
- *		\brief      This file is an example of a php page
- *					Put here some comments
+ *		\ingroup    mymodule
+ *		\brief      Page to create/edit/view myobject
  */
 
 //if (! defined('NOREQUIREUSER'))          define('NOREQUIREUSER','1');
diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php
index fb26f9dde0e..68a8d30afbe 100644
--- a/htdocs/modulebuilder/template/myobject_list.php
+++ b/htdocs/modulebuilder/template/myobject_list.php
@@ -19,7 +19,7 @@
 /**
  *   	\file       htdocs/modulebuilder/template/myobject_list.php
  *		\ingroup    mymodule
- *		\brief      List page for monmodule
+ *		\brief      List page for myobject
  */
 
 //if (! defined('NOREQUIREUSER'))          define('NOREQUIREUSER','1');
diff --git a/htdocs/product/inventory/card.php b/htdocs/product/inventory/card.php
index e47891a6d08..5506bad0fbb 100644
--- a/htdocs/product/inventory/card.php
+++ b/htdocs/product/inventory/card.php
@@ -1,5 +1,6 @@
 <?php
-/* Copyright (C) 2016		ATM Consulting			<support@atm-consulting.fr>
+/* Copyright (C) 2007-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) ---Put here your own copyright and developer email---
  *
  * 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
@@ -16,48 +17,78 @@
  */
 
 /**
- *	\file       htdocs/inventory/card.php
- *	\ingroup    product
- *	\brief      File of class to manage inventory
+ *   	\file       product/inventory/card.php
+ *		\ingroup    inventory
+ *		\brief      This file is an example of a php page
+ *					Put here some comments
  */
- 
-require_once '../../main.inc.php';
-
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/listview.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
-include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/class/inventory.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/lib/inventory.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
-
-
-$langs->load('stock');
-$langs->load('inventory');
-
-$id=GETPOST('id', 'int');
-$ref=GETPOST('ref', 'alpha');
-$action=(GETPOST('action','alpha') ? GETPOST('action','alpha') : 'view');
-$cancel=GETPOST('cancel');
-$confirm=GETPOST('confirm','alpha');
-$socid=GETPOST('socid','int');
-if (! empty($user->societe_id)) $socid=$user->societe_id;
+
+//if (! defined('NOREQUIREUSER'))          define('NOREQUIREUSER','1');
+//if (! defined('NOREQUIREDB'))            define('NOREQUIREDB','1');
+//if (! defined('NOREQUIRESOC'))           define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))          define('NOREQUIRETRAN','1');
+//if (! defined('NOSCANGETFORINJECTION'))  define('NOSCANGETFORINJECTION','1');			// Do not check anti CSRF attack test
+//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION','1');			// Do not check anti CSRF attack test
+//if (! defined('NOCSRFCHECK'))            define('NOCSRFCHECK','1');			// Do not check anti CSRF attack test
+//if (! defined('NOSTYLECHECK'))           define('NOSTYLECHECK','1');			// Do not check style html tag into posted data
+//if (! defined('NOTOKENRENEWAL'))         define('NOTOKENRENEWAL','1');		// Do not check anti POST attack test
+//if (! defined('NOREQUIREMENU'))          define('NOREQUIREMENU','1');			// If there is no need to load and show top and left menu
+//if (! defined('NOREQUIREHTML'))          define('NOREQUIREHTML','1');			// If we don't need to load the html.form.class.php
+//if (! defined('NOREQUIREAJAX'))          define('NOREQUIREAJAX','1');         // Do not load ajax.lib.php library
+//if (! defined("NOLOGIN"))                define("NOLOGIN",'1');				// If this page is public (can be called outside logged session)
+
+// Load Dolibarr environment
+$res=0;
+// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
+if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include($_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php");
+// Try main.inc.php into web root detected using web root caluclated from SCRIPT_FILENAME
+$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;
+while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; }
+if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include(substr($tmp, 0, ($i+1))."/main.inc.php");
+if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php");
+// Try main.inc.php using relative path
+if (! $res && file_exists("../main.inc.php")) $res=@include("../main.inc.php");
+if (! $res && file_exists("../../main.inc.php")) $res=@include("../../main.inc.php");
+if (! $res && file_exists("../../../main.inc.php")) $res=@include("../../../main.inc.php");
+if (! $res) die("Include of main fails");
+
+include_once(DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php');
+dol_include_once('/inventory/class/inventory.class.php');
+
+// Load traductions files requiredby by page
+$langs->loadLangs(array("inventory","other"));
+
+// Get parameters
+$id			= GETPOST('id', 'int');
+$action		= GETPOST('action', 'alpha');
+$cancel     = GETPOST('cancel', 'aZ09');
+$backtopage = GETPOST('backtopage', 'alpha');
+
+// Initialize technical objects
+$object=new Inventory($db);
+$extrafields = new ExtraFields($db);
+$diroutputmassaction=$conf->inventory->dir_output . '/temp/massgeneration/'.$user->id;
+$hookmanager->initHooks(array('inventorycard'));     // Note that conf->hooks_modules contains array
+// Fetch optionals attributes and labels
+$extralabels = $extrafields->fetch_name_optionals_label('inventory');
+$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
+
+// Initialize array of search criterias
+$search_all=trim(GETPOST("search_all",'alpha'));
+$search=array();
+foreach($object->fields as $key => $val)
+{
+    if (GETPOST('search_'.$key,'alpha')) $search[$key]=GETPOST('search_'.$key,'alpha');
+}
 
 if (empty($action) && empty($id) && empty($ref)) $action='view';
 
 // Protection if external user
 if ($user->societe_id > 0)
 {
-    //accessforbidden();
+	//accessforbidden();
 }
-$result = restrictedArea($user, 'stock', $id);
-
-
-$object = new Inventory($db);
-$extrafields = new ExtraFields($db);
+//$result = restrictedArea($user, 'inventory', $id);
 
 // fetch optionals attributes and labels
 $extralabels = $extrafields->fetch_name_optionals_label($object->table_element);
@@ -65,623 +96,526 @@ $extralabels = $extrafields->fetch_name_optionals_label($object->table_element);
 // Load object
 include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php';  // Must be include, not include_once  // Must be include, not include_once. Include fetch and fetch_thirdparty but not fetch_optionals
 
-// Initialize technical object to manage hooks of modules. Note that conf->hooks_modules contains array array
-$hookmanager->initHooks(array('inventorycard'));
-
 
 
 /*
- * Actions
+ * ACTIONS
+ *
+ * Put here all code to do according to value of "action" parameter
  */
 
-$parameters=array('id'=>$id, 'ref'=>$ref, 'objcanvas'=>$objcanvas);
+$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))
 {
-    if ($cancel)
-    {
-        if ($action != 'addlink')
+	$error=0;
+
+	if ($cancel)
+	{
+		if ($action != 'addlink')
+		{
+			$urltogo=$backtopage?$backtopage:dol_buildpath('/inventory/inventory_list.php',1);
+			header("Location: ".$urltogo);
+			exit;
+		}
+		if ($id > 0 || ! empty($ref)) $ret = $object->fetch($id,$ref);
+		$action='';
+	}
+
+	// Action to add record
+	if ($action == 'add' && ! empty($user->rights->inventory->create))
+	{
+        foreach ($object->fields as $key => $val)
         {
-            $urltogo=$backtopage?$backtopage:dol_buildpath('/product/inventory/list.php',1);
-            header("Location: ".$urltogo);
-            exit;
+            if (in_array($key, array('rowid', 'entity', 'date_creation', 'tms', 'import_key'))) continue;	// Ignore special fields
+
+            $object->$key=GETPOST($key,'alpha');
+            if ($val['notnull'] && $object->$key == '')
+            {
+                $error++;
+                setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv($val['label'])), null, 'errors');
+            }
         }
-        if ($id > 0 || ! empty($ref)) $ret = $object->fetch($id,$ref);
-        $action='';
-    }
-    
-    if ($action == 'confirmCreate')
-    {
-		if (empty($user->rights->stock->creer)) accessforbidden();
-	
-		if ($cancel)
+
+		if (! $error)
 		{
-		    $urltogo=$backtopage?$backtopage:dol_buildpath('/product/inventory/list.php',1);
-		    header("Location: ".$urltogo);
-		    exit;
+			$result=$object->createCommon($user);
+			if ($result > 0)
+			{
+				// Creation OK
+				$urltogo=$backtopage?$backtopage:dol_buildpath('/inventory/inventory_list.php',1);
+				header("Location: ".$urltogo);
+				exit;
+			}
+			else
+			{
+				// Creation KO
+				if (! empty($object->errors)) setEventMessages(null, $object->errors, 'errors');
+				else  setEventMessages($object->error, null, 'errors');
+				$action='create';
+			}
 		}
-		
-		$error=0;
-		
-		$object->setValues($_POST);
-		
-        $fk_inventory = $object->create($user);
-		if ($fk_inventory>0)
+		else
 		{
-        	$fk_category = (int) GETPOST('fk_category');
-        	$fk_supplier = (int) GETPOST('fk_supplier');
-        	$fk_warehouse = (int) GETPOST('fk_warehouse');
-        	$only_prods_in_stock = (int) GETPOST('OnlyProdsInStock');
-        	
-        	$object->addProductsFor($fk_warehouse,$fk_category,$fk_supplier,$only_prods_in_stock);
-        	$object->update($user);
-        	
-        	header('Location: '.dol_buildpath('/product/inventory/card.php?id='.$object->id.'&action=edit', 1));
-            exit;        	
-        }
-        else
+			$action='create';
+		}
+	}
+
+	// Action to update record
+	if ($action == 'update' && ! empty($user->rights->inventory->create))
+	{
+	    foreach ($object->fields as $key => $val)
         {
-        	setEventMessage($object->error,'errors');
-        	header('Location: '.dol_buildpath('/product/inventory/card.php?action=create', 1));
-        	exit;
-        }
-    }
-    
-    switch($action) {
-    	case 'save':
-    		if (!$user->rights->stock->creer) accessforbidden();
-    		
-    		
-    		$id = GETPOST('id');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch($id);
-    		
-    		$object->setValues($_REQUEST);
-    		
-    		if ($object->errors)
-    		{
-    			setEventMessage($object->errors, 'errors');
-    			$action = 'edit';
-    		}
-    		else 
-    		{
-    			$object->udpate($user);
-    			header('Location: '.dol_buildpath('/product/inventory/card.php?id='.$object->getId().'&action=view', 1));
-    			exit;
-    		}
-    		
-    		break;
-    		
-    	case 'confirm_regulate':
-    		if (!$user->rights->stock->creer) accessforbidden();
-    		$id = GETPOST('id');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch($id);
-            
-            if($object->status == 0) {
-                $object->status = 1;
-                $object->update($user);
-                
-                $action='view';
-            }
-            else {
-               $action='view';
+            $object->$key=GETPOST($key,'alpha');
+            if (in_array($key, array('rowid', 'entity', 'date_creation', 'tms', 'import_key'))) continue;
+            if ($val['notnull'] && $object->$key == '')
+            {
+                $error++;
+                setEventMessages($langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv($val['label'])), null, 'errors');
             }
-            
-    		break;
-    		
-    	case 'confirm_changePMP':
-    		
-    		$id = GETPOST('id');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch( $id );
-    		
-    		$object->changePMP($user);
-    		
-    		$action='view';
-    		
-    		break;
-    		
-    	case 'add_line':
-    		if (!$user->rights->stock->creer) accessforbidden();
-    		
-    		$id = GETPOST('id');
-    		$fk_warehouse = GETPOST('fk_warehouse');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch( $id );
-    		
-    		$fk_product = GETPOST('fk_product');
-    		if ($fk_product>0)
-    		{
-    			$product = new Product($db);
-    			if($product->fetch($fk_product)<=0 || $product->type != 0) {
-    				setEventMessage($langs->trans('ThisIsNotAProduct'),'errors');
-    			}
-    			else{
-    				
-    				//Check product not already exists
-    				$alreadyExists = false;
-    				if(!empty($object->Inventorydet)) {
-    					foreach ($object->Inventorydet as $invdet)
-    					{
-    						if ($invdet->fk_product == $product->id
-    							&& $invdet->fk_warehouse == $fk_warehouse)
-    						{
-    							$alreadyExists = true;
-    							break;
-    						}
-    					}
-    				}
-    				if (!$alreadyExists)
-    				{
-    				    if($object->addProduct($product->id, $fk_warehouse)) {
-    				    	setEventMessage($langs->trans('ProductAdded'));
-    				    }
-    				}
-    				else
-    				{
-    					setEventMessage($langs->trans('inventoryWarningProductAlreadyExists'), 'warnings');
-    				}
-    				
-    			}
-    			
-    			$object->update($user);
-    			$object->sortDet();
-    		}
-    		
-    		$action='edit';
-    		
-    		break;
-    		
-    	case 'confirm_delete_line':
-    		if (!$user->rights->stock->creer) accessforbidden();
-    		
-    		
-    		//Cette action devrais se faire uniquement si le status de l'inventaire est à 0 mais aucune vérif
-    		$rowid = GETPOST('rowid');
-    		$objectdet = new Inventorydet($db);
-    		if($objectdet->fetch($rowid)>0) {
-    			$objectdet->delete($user);
-    			setEventMessage("ProductDeletedFromInventory");
-    		}
-    		$id = GETPOST('id');
-    		$object = new Inventory($db);
-    		$object->fetch( $id);
-    		
-    		$action='edit';
-    		
-    		break;
-        case 'confirm_flush':
-            if (!$user->rights->stock->creer) accessforbidden();
-            
-            
-            $id = GETPOST('id');
-            
-            $object = new Inventory($db);
-            $object->fetch($id);
-            
-            $object->deleteAllLine($user);
-            
-            setEventMessage($langs->trans('InventoryFlushed'));
-            
-            $action='edit';
-            
-            break;
-    	case 'confirm_delete':
-    		if (!$user->rights->stock->supprimer) accessforbidden();
-            
-    		$id = GETPOST('id');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch($id);
-    		
-    		$object->delete($user);
-    		
-    		setEventMessage($langs->trans('InventoryDeleted'));
-    		
-    		header('Location: '.dol_buildpath('/inventory/list.php', 1));
-    		exit;
-    		
-    		break;
-    	/*case 'exportCSV':
-    		
-    		$id = GETPOST('id');
-    		
-    		$object = new Inventory($db);
-    		$object->fetch($id);
-    		
-    		_exportCSV($object);
-    		
-    		exit;
-    		break;
-    		*/
-    }
+        }
+
+		if (! $error)
+		{
+			$result=$object->updateCommon($user);
+			if ($result > 0)
+			{
+				$action='view';
+			}
+			else
+			{
+				// Creation KO
+				if (! empty($object->errors)) setEventMessages(null, $object->errors, 'errors');
+				else setEventMessages($object->error, null, 'errors');
+				$action='edit';
+			}
+		}
+		else
+		{
+			$action='edit';
+		}
+	}
+
+	// Action to delete
+	if ($action == 'confirm_delete' && ! empty($user->rights->inventory->delete))
+	{
+		$result=$object->deleteCommon($user);
+		if ($result > 0)
+		{
+			// Delete OK
+			setEventMessages("RecordDeleted", null, 'mesgs');
+			header("Location: ".dol_buildpath('/inventory/inventory_list.php',1));
+			exit;
+		}
+		else
+		{
+			if (! empty($object->errors)) setEventMessages(null, $object->errors, 'errors');
+			else setEventMessages($object->error, null, 'errors');
+		}
+	}
 }
 
 
+
+
 /*
- * Views
+ * VIEW
+ *
+ * Put here all code to build page
  */
 
 $form=new Form($db);
 
-llxHeader('',$langs->trans('Inventory'),'','');
-	
+llxHeader('','Inventory','');
+
+// Example : Adding jquery code
+print '<script type="text/javascript" language="javascript">
+jQuery(document).ready(function() {
+	function init_myfunc()
+	{
+		jQuery("#myid").removeAttr(\'disabled\');
+		jQuery("#myid").attr(\'disabled\',\'disabled\');
+	}
+	init_myfunc();
+	jQuery("#mybutton").click(function() {
+		init_myfunc();
+	});
+});
+</script>';
+
+
+// Part to create
 if ($action == 'create')
 {
-    if (empty($user->rights->stock->creer)) accessforbidden();
+	print load_fiche_titre($langs->trans("NewObject", $langs->transnoentitiesnoconv("Inventory")));
+
+	print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
+	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
+	print '<input type="hidden" name="action" value="add">';
+	print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
+
+	dol_fiche_head(array(), '');
+
+	print '<table class="border centpercent">'."\n";
+	foreach($object->fields as $key => $val)
+	{
+	    if (in_array($key, array('rowid', 'entity', 'date_creation', 'tms', 'import_key'))) continue;
+    	print '<tr><td';
+    	print ' class="titlefieldcreate';
+    	if ($val['notnull']) print ' fieldrequired';
+    	print '"';
+    	print '>'.$langs->trans($val['label']).'</td><td><input class="flat" type="text" name="'.$key.'" value="'.(GETPOST($key,'alpha')?GETPOST($key,'alpha'):'').'"></td></tr>';
+	}
+	print '</table>'."\n";
+
+	dol_fiche_end();
+
+	print '<div class="center"><input type="submit" class="button" name="add" value="'.dol_escape_htmltag($langs->trans("Create")).'"> &nbsp; <input type="submit" class="button" name="cancel" value="'.dol_escape_htmltag($langs->trans("Cancel")).'"></div>';
+
+	print '</form>';
+}
+
+
+
+// Part to edit record
+if (($id || $ref) && $action == 'edit')
+{
+	print load_fiche_titre($langs->trans("Inventory"));
+
+	print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
+	print '<input type="hidden" name="action" value="update">';
+	print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
+	print '<input type="hidden" name="id" value="'.$object->id.'">';
 
-    print load_fiche_titre($langs->trans("NewInventory"));
-	
-    echo '<form name="confirmCreate" action="'.$_SERVER['PHP_SELF'].'" method="post" />';
-	echo '<input type="hidden" name="action" value="confirmCreate" />';
-	
 	dol_fiche_head();
-	
-    $formproduct = new FormProduct($db);
-    
-    ?>
-    <table class="border" width="100%" >
-        <tr>
-            <td><?php echo $langs->trans('Title') ?></td>
-            <td><input type="text" name="title" value="" size="50" /></td> 
-        </tr>
-        <tr>
-            <td><?php echo $langs->trans('Date') ?></td>
-            <td><?php echo $form->select_date(time(),'date_inventory'); ?></td> 
-        </tr>
-        
-        <tr>
-            <td><?php echo $langs->trans('inventorySelectWarehouse') ?></td>
-            <td><?php echo $formproduct->selectWarehouses('', 'fk_warehouse') ?></td> 
-        </tr>
-        
-        <tr>
-            <td><?php echo $langs->trans('SelectCategory') ?></td>
-            <td><?php echo $form->select_all_categories(0,'', 'fk_category') ?></td> 
-        </tr>
-        <tr>
-            <td><?php echo $langs->trans('SelectFournisseur') ?></td>
-            <td><?php echo $form->select_thirdparty('','fk_supplier','s.fournisseur = 1') ?></td> 
-        </tr>
-        <tr>
-            <td><?php echo $langs->trans('OnlyProdsInStock') ?></td>
-            <td><input type="checkbox" name="OnlyProdsInStock" value="1"></td> 
-        </tr>
-        
-    </table>
-    <?php
-    
-    dol_fiche_end();
-    
-    print '<div class="center">';
-    print '<input type="submit" class="button" name="create" value="'.$langs->trans('inventoryConfirmCreate').'" />';
-    print ' &nbsp; &nbsp; ';
-    print '<input type="submit" class="button" name="cancel" value="'.$langs->trans('Cancel').'" />';
-    print '</div>';
-    
-	echo '</form>';
-	
+
+	print '<table class="border centpercent">'."\n";
+	// print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td><input class="flat" type="text" size="36" name="label" value="'.$label.'"></td></tr>';
+	// LIST_OF_TD_LABEL_FIELDS_EDIT
+	print '</table>';
+
+	dol_fiche_end();
+
+	print '<div class="center"><input type="submit" class="button" name="save" value="'.$langs->trans("Save").'">';
+	print ' &nbsp; <input type="submit" class="button" name="cancel" value="'.$langs->trans("Cancel").'">';
+	print '</div>';
+
+	print '</form>';
 }
 
-if ($action == 'view' || $action == 'edit' ||  empty($action))
+
+
+// Part to show record
+if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'create')))
 {
-    $object = new Inventory($db);
-    $result = $object->fetch($id);
-    if ($result < 0) dol_print_error($db, $object->error, $object->errors);
-    
-    $warehouse = new Entrepot($db);
-    $warehouse->fetch($object->fk_warehouse);
-    
-    
-    
-	if($action == 'changePMP')
-	{
-		print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ApplyNewPMP'), $langs->trans('ConfirmApplyNewPMP', $object->getTitle()), 'confirm_changePMP', array(),'no',1);
-	}
-	else if($action == 'flush')
-	{
-		print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('FlushInventory'),$langs->trans('ConfirmFlushInventory',$object->getTitle()),'confirm_flush',array(),'no',1);
+    $res = $object->fetch_optionals($object->id, $extralabels);
+
+	$head = inventory_prepare_head($object);
+	dol_fiche_head($head, 'order', $langs->trans("CustomerOrder"), -1, 'order');
+
+	$formconfirm = '';
+
+	// Confirmation to delete
+	if ($action == 'delete') {
+	    $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?id=' . $object->id, $langs->trans('DeleteOrder'), $langs->trans('ConfirmDeleteOrder'), 'confirm_delete', '', 0, 1);
 	}
-	else if($action == 'delete')
+
+	// Confirmation of action xxxx
+	if ($action == 'xxx')
 	{
-		print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('Delete'),$langs->trans('ConfirmDelete',$object->getTitle()),'confirm_delete',array(),'no',1);
+	    $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);
 	}
-	else if($action == 'delete_line')
-	{
-		print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&rowid='.GETPOST('rowid'),$langs->trans('DeleteLine'),$langs->trans('ConfirmDeleteLine',$object->getTitle()),'confirm_delete_line',array(),'no',1);
+
+	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;
 	}
-	else if($action == 'regulate')
+
+	// Print form confirm
+	print $formconfirm;
+
+
+
+	// Object card
+	// ------------------------------------------------------------
+
+	$linkback = '<a href="' . DOL_URL_ROOT . '/inventory/inventory_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->inventory->creer, 'string', '', 0, 1);
+	$morehtmlref.=$form->editfieldval("RefBis", 'ref_client', $object->ref_client, $object, $user->rights->inventory->creer, 'string', '', null, null, '', 1);
+	// Thirdparty
+	$morehtmlref.='<br>'.$langs->trans('ThirdParty') . ' : ' . $soc->getNomUrl(1);
+	// Project
+	if (! empty($conf->projet->enabled))
 	{
-		print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('RegulateStock'),$langs->trans('ConfirmRegulateStock',$object->getTitle()),'confirm_regulate',array(),'no',1);
+	    $langs->load("projects");
+	    $morehtmlref.='<br>'.$langs->trans('Project') . ' ';
+	    if ($user->rights->inventory->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.='';
+	        }
+	    }
 	}
-	
-	print dol_get_fiche_head(inventoryPrepareHead($object, $langs->trans('inventoryOfWarehouse', $warehouse->libelle), empty($action) ? '': '&action='.$action));
-	
-	$lines = array();
-	card_line($object, $lines, $action);
-	
-	print $langs->trans('Ref')." ".$object->ref.'<br>';
-	print $langs->trans('Date')." ".$object->getDate('date_inventory').'<br><br>';
-	
-	$objectTPL = array(
-	    'id'=> $object->id
-	    ,'ref'=> $object->ref
-		,'date_cre' => $object->getDate('date_cre', 'd/m/Y')
-		,'date_maj' => $object->getDate('date_maj', 'd/m/Y H:i')
-		,'fk_warehouse' => $object->fk_warehouse
-		,'status' => $object->status
-		,'entity' => $object->entity
-		,'amount' => price( round($object->amount,2) )
-		,'amount_actual'=>price (round($object->amount_actual,2))
-		
-	);
-	
-	$can_validate = !empty($user->rights->stock->validate);
-	$view_url = dol_buildpath('/product/inventory/card.php', 1);
-	
-	$view = array(
-		'mode' => $action
-		,'url' => dol_buildpath('/product/inventory/card.php', 1)
-		,'can_validate' => (int) $user->rights->stock->validate
-		,'is_already_validate' => (int) $object->status
-		,'token'=>$_SESSION['newtoken']
-	);
-	
-	include './tpl/inventory.tpl.php';
-}
+	*/
+	$morehtmlref.='</div>';
 
-// End of page
-llxFooter();
-$db->close();
 
+	dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
 
 
-function card_line(&$inventory, &$lines, $mode)
-{
-	global $db,$langs,$user,$conf;
-	$inventory->amount_actual = 0;
-	
-	$TCacheEntrepot = array();
+	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
 
-	foreach ($inventory->Inventorydet as $k => $Inventorydet)
-	{
-        $product = & $Inventorydet->product;
-		$stock = $Inventorydet->qty_stock;
-	
-        $pmp = $Inventorydet->pmp;
-		$pmp_actual = $pmp * $stock;
-		$inventory->amount_actual+=$pmp_actual;
-
-        $last_pa = $Inventorydet->pa;
-		$current_pa = $Inventorydet->current_pa;
-        
-		$e = new Entrepot($db);
-		if(!empty($TCacheEntrepot[$Inventorydet->fk_warehouse])) $e = $TCacheEntrepot[$Inventorydet->fk_warehouse];
-		elseif($e->fetch($Inventorydet->fk_warehouse) > 0) $TCacheEntrepot[$e->id] = $e;
-		
-		$qtytoadd = GETPOST('qty_to_add', 'array');
-		$qty = (float) $qtytoadd[$k];
-		
-		$lines[]=array(
-			'produit' => $product->getNomUrl(1).'&nbsp;-&nbsp;'.$product->label,
-			'entrepot'=>$e->getNomUrl(1),
-			'barcode' => $product->barcode,
-			'qty' =>($mode == 'edit' ? '<input type="text" name="qty_to_add['.$k.']" value="'.$qty.'" size="8" style="text-align:center;" /> <a id="a_save_qty_'.$k.'" href="javascript:save_qty('.$k.')">'.img_picto($langs->trans('Add'), 'edit_add').'</a>' : '' ),
-			'qty_view' => ($Inventorydet->qty_view ? $Inventorydet->qty_view : 0),
-			'qty_stock' => $stock,
-			'qty_regulated' => ($Inventorydet->qty_regulated ? $Inventorydet->qty_regulated : 0),
-			'action' => ($user->rights->stock->write && $mode=='edit' ? '<a href="'.dol_buildpath('/product/inventory/card.php?id='.$inventory->id.'&action=delete_line&rowid='.$Inventorydet->id, 1).'">'.img_picto($langs->trans('inventoryDeleteLine'), 'delete').'</a>' : ''),
-			'pmp_stock'=>round($pmp_actual,2),
-            'pmp_actual'=> round($pmp * $Inventorydet->qty_view,2),
-			'pmp_new'=>(!empty($user->rights->stock->changePMP) && $mode == 'edit' ? '<input type="text" name="new_pmp['.$k.']" value="'.$Inventorydet->new_pmp.'" size="8" style="text-align:right;" /> <a id="a_save_new_pmp_'.$k.'" href="javascript:save_pmp('.$k.')">'.img_picto($langs->trans('Save'), 'bt-save.png@inventory').'</a>' :  price($Inventorydet->new_pmp)),
-            'pa_stock'=>round($last_pa * $stock,2),
-            'pa_actual'=>round($last_pa * $Inventorydet->qty_view,2),
-			'current_pa_stock'=>round($current_pa * $stock,2),
-			'current_pa_actual'=>round($current_pa * $Inventorydet->qty_view,2),
-            'k'=>$k,
-            'id'=>$Inventorydet->id
-		);
+
+	// Other attributes
+	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 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))
+    	{
+    	    // Send
+            print '<div class="inline-block divButAction"><a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendByMail') . '</a></div>'."\n";
+
+    		if ($user->rights->inventory->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->inventory->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';
+	}
 
-/*
-function _exportCSV(&$inventory) 
-{
-	global $conf;
-	
-	header('Content-Type: application/octet-stream');
-    header('Content-disposition: attachment; filename=inventory-'. $inventory->getId().'-'.date('Ymd-His').'.csv');
-    header('Pragma: no-cache');
-    header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
-    header('Expires: 0');
-	
-	echo 'Ref;Label;barcode;qty theorique;PMP;dernier PA;';
-	if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) echo 'PA courant;';
-	echo 'qty réelle;PMP;dernier PA;';
-	if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) echo 'PA courant;';
-	echo 'qty regulée;'."\r\n";
-	
-	foreach ($inventory->Inventorydet as $k => $Inventorydet)
+	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->inventory->dir_output . '/' . $comref;
+	    $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
+	    $genallowed = $user->rights->inventory->creer;
+	    $delallowed = $user->rights->inventory->supprimer;
+	    print $formfile->showdocuments('inventory', $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>';
+	}
+
+
+	/*
+	 * Action presend
+	 */
+    /*
+	if ($action == 'presend')
 	{
-		$product = & $Inventorydet->product;
-		$stock = $Inventorydet->qty_stock;
-	
-        $pmp = $Inventorydet->pmp;
-		$pmp_actual = $pmp * $stock;
-		$inventory->amount_actual+=$pmp_actual;
-
-        $last_pa = $Inventorydet->pa;
-        $current_pa = $Inventorydet->current_pa;
-		
-		if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) {
-			$row=array(
-				'produit' => $product->ref
-				,'label'=>$product->label
-				,'barcode' => $product->barcode
-				,'qty_stock' => $stock
-				,'pmp_stock'=>round($pmp_actual,2)
-	            ,'pa_stock'=>round($last_pa * $stock,2)
-				,'current_pa_stock'=>round($current_pa * $stock,2)
-			    ,'qty_view' => $Inventorydet->qty_view ? $Inventorydet->qty_view : 0
-				,'pmp_actual'=>round($pmp * $Inventorydet->qty_view,2)
-	            ,'pa_actual'=>round($last_pa * $Inventorydet->qty_view,2)
-	        	,'current_pa_actual'=>round($current_pa * $Inventorydet->qty_view,2)    
-				,'qty_regulated' => $Inventorydet->qty_regulated ? $Inventorydet->qty_regulated : 0
-				
-			);
-			
+		$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))
+		{
+			$outputlangs = new Translate('', $conf);
+			$outputlangs->setDefaultLang($newlang);
+			$outputlangs->load('commercial');
 		}
-		else{
-			$row=array(
-				'produit' => $product->ref
-				,'label'=>$product->label
-				,'barcode' => $product->barcode
-				,'qty_stock' => $stock
-				,'pmp_stock'=>round($pmp_actual,2)
-	            ,'pa_stock'=>round($last_pa * $stock,2)
-	            ,'qty_view' => $Inventorydet->qty_view ? $Inventorydet->qty_view : 0
-				,'pmp_actual'=>round($pmp * $Inventorydet->qty_view,2)
-	            ,'pa_actual'=>round($last_pa * $Inventorydet->qty_view,2)
-	            
-				,'qty_regulated' => $Inventorydet->qty_regulated ? $Inventorydet->qty_regulated : 0
-				
-		);
-			
+
+		// 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'];
 		}
-		
-		
-		echo '"'.implode('";"', $row).'"'."\r\n";
-		
-	}
-	
-	exit;
-}
-*/
 
-function _footerList($view,$total_pmp,$total_pmp_actual,$total_pa,$total_pa_actual, $total_current_pa,$total_current_pa_actual) 
-{
-	global $conf,$user,$langs;
-	
-	    if ($view['can_validate'] == 1) { ?>
-        <tr style="background-color:#dedede;">
-            <th colspan="3">&nbsp;</th>
-            <?php if (! empty($conf->barcode->enabled)) { ?>
-					<th align="center">&nbsp;</td>
-			<?php } ?>
-            <th align="right"><?php echo price($total_pmp) ?></th>
-            <th align="right"><?php echo price($total_pa) ?></th>
-            <?php
-	                 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)){
-	              		echo '<th align="right">'.price($total_current_pa).'</th>';   	
-					 }
-			?>
-            <th>&nbsp;</th>
-            <th align="right"><?php echo price($total_pmp_actual) ?></th>
-            <?php
-            if(!empty($user->rights->stock->changePMP)) {
-               	echo '<th>&nbsp;</th>';	
+		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
+		{
+			include DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
+			$formmail->frommail=dolAddEmailTrackId($formmail->frommail, 'ord'.$object->id);
+		}
+		$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);
+				}
 			}
-			?>
-            <th align="right"><?php echo price($total_pa_actual) ?></th>
-            <?php
-	                 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)){
-	              		echo '<th align="right">'.price($total_current_pa_actual).'</th>';   	
-					 }
-			?>
-
-            <th>&nbsp;</th>
-            <?php if ($view['is_already_validate'] != 1) { ?>
-            <th>&nbsp;</th>
-            <?php } ?>
-        </tr>
-        <?php } 
-}
 
+			if (! empty($custcontact)) {
+				$formmail->substit['__CONTACTCIVNAME__'] = $custcontact;
+			}
+		}
 
-function _headerList($view) 
-{
-	global $conf,$user,$langs;
-	
-	?>
-			<tr style="background-color:#dedede;">
-				<th class="titlefield"><?php echo $langs->trans('Product'); ?></th>
-				<th><?php echo $langs->trans('Warehouse'); ?></th>
-				<?php if (! empty($conf->barcode->enabled)) { ?>
-					<th align="center"><?php echo $langs->trans('Barcode'); ?></th>
-				<?php } ?>
-				<?php if ($view['can_validate'] == 1) { ?>
-					<th align="center" width="20%"><?php echo $langs->trans('TheoricalQty'); ?></th>
-					<?php
-	                 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)){
-	              		echo '<th align="center" width="20%" colspan="3">'.$langs->trans('TheoricalValue').'</th>';   	
-					 }
-					 else {
-					 	echo '<th align="center" width="20%" colspan="2">'.$langs->trans('TheoricalValue').'</th>';
-					 }
-					 
-					?>
-					
-				<?php } ?>
-				    <th align="center" width="20%"><?php echo $langs->trans('RealQty'); ?></th>
-				<?php if ($view['can_validate'] == 1) { ?>
-				    
-				    <?php
-				    
-				     $colspan = 2;
-					 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) $colspan++;
-				     if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) $colspan++;
-					
-	                 echo '<th align="center" width="20%" colspan="'.$colspan.'">'.$langs->trans('RealValue').'</th>';
-					 
-					?>
-						
-					<th align="center" width="15%"><?php echo $langs->trans('RegulatedQty'); ?></th>
-				<?php } ?>
-				<?php if ($view['is_already_validate'] != 1) { ?>
-					<th align="center" width="5%">#</th>
-				<?php } ?>
-				
-			</tr>
-			<?php if ($view['can_validate'] == 1) { ?>
-	    	<tr style="background-color:#dedede;">
-	    	    <th colspan="<?php echo empty($conf->barcode->enabled) ? 3 : 4;  ?>">&nbsp;</th>
-	    	    <th><?php echo $langs->trans('PMP'); ?></th>
-	    	    <th><?php echo $langs->trans('LastPA'); ?></th>
-	    	    <?php
-	                 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)){
-	              		echo '<th>'.$langs->trans('CurrentPA').'</th>';   	
-					 }
-					 
-				?>
-	    	    <th>&nbsp;</th>
-	    	    <th><?php echo $langs->trans('PMP'); ?></th>
-	    	    <?php
-	    	    if(!empty($user->rights->stock->changePMP)) {
-	    	    	echo '<th rel="newPMP">'.$langs->trans('ColumnNewPMP').'</th>';
-	    	    }
-	    	    ?>
-	            <th><?php echo $langs->trans('LastPA'); ?></th>
-	            <?php
-	                 if(!empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)){
-	              		echo '<th>'.$langs->trans('CurrentPA').'</th>';   	
-					 }
-					 
-				?>
-	            <th>&nbsp;</th>
-	            <?php if ($view['is_already_validate'] != 1) { ?>
-	            <th>&nbsp;</th>
-	            <?php } ?>
-	    	</tr>
-	    	<?php 
-	} 
-	
+		// 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));
+		}
+
+		// Show form
+		print $formmail->get_form();
+
+		dol_fiche_end();
+	}*/
 }
+
+
+// End of page
+llxFooter();
+$db->close();
diff --git a/htdocs/product/inventory/class/inventory.class.php b/htdocs/product/inventory/class/inventory.class.php
index dc79dac28e5..3fc42f15f70 100644
--- a/htdocs/product/inventory/class/inventory.class.php
+++ b/htdocs/product/inventory/class/inventory.class.php
@@ -1,5 +1,9 @@
 <?php
-/* Copyright (C) 2016		ATM Consulting			<support@atm-consulting.fr>
+/* Copyright (C) 2007-2017  Laurent Destailleur <eldy@users.sourceforge.net>
+ * Copyright (C) 2014-2016  Juanjo Menent       <jmenent@2byte.es>
+ * Copyright (C) 2015       Florian Henry       <florian.henry@open-concept.pro>
+ * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
+ * Copyright (C) ---Put here your own copyright and developer email---
  *
  * 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
@@ -16,698 +20,271 @@
  */
 
 /**
- *	\file       htdocs/inventory/class/product.class.php
- *	\ingroup    product
- *	\brief      File of class to manage predefined products stock
+ * \file        product/inventory/class/inventory.class.php
+ * \ingroup     inventory
+ * \brief       This file is a CRUD class file for Inventory (Create/Read/Update/Delete)
  */
- 
-require_once DOL_DOCUMENT_ROOT.'/core/class/coreobject.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
+
+// Put here all includes required by your class file
+require_once DOL_DOCUMENT_ROOT . '/core/class/commonobject.class.php';
+//require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
+//require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
 
 /**
- *	Class to manage inventories
+ * Class for Inventory
  */
-class Inventory extends CoreObject
+class Inventory extends CommonObject
 {
-	public $element='inventory';
-	public $table_element='inventory';
-	public $fk_element='fk_inventory';
-	protected $childtables=array('inventorydet');    // To test if we can delete object
-	protected $isnolinkedbythird = 1;     // No field fk_soc
-	protected $ismultientitymanaged = 1;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
-	
 	/**
-	 * Warehouse Id
-	 * @var int
+	 * @var string ID to identify managed object
 	 */
-	public $fk_warehouse;
+	public $element = 'inventory';
 	/**
-	 * Entity Id
-	 * @var int
+	 * @var string Name of table without prefix where object is stored
 	 */
-	public $entity;
-	
+	public $table_element = 'inventory';
+
 	/**
-	 * Status
-	 * @var int
+	 * @var array  Does this field is linked to a thirdparty ?
 	 */
-	public $status;
+	protected $isnolinkedbythird = 1;
 	/**
-	 * Inventory Date
-	 * @var date
+	 * @var array  Does inventory support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
 	 */
-	public $date_inventory;
+	protected $ismultientitymanaged = 1;
 	/**
-	 * Inventory Title
-	 * @var string
+	 * @var string String with name of icon for inventory
 	 */
-	public $title;
+	public $picto = 'inventory';
+
 
-    /**
-     * Attribute object linked with database
-     * @var array
-     */
-	protected $fields=array(
-		'fk_warehouse'=>array('type'=>'integer','index'=>true)
-	    ,'ref'=>array('type'=>'string','index'=>true)
-		,'entity'=>array('type'=>'integer','index'=>true)
-		,'status'=>array('type'=>'integer','index'=>true)
-		,'date_inventory'=>array('type'=>'date')
-		,'title'=>array('type'=>'string')
+	/**
+	 *             'type' if the field format, 'label' the translation key, 'enabled' is a condition when the filed must be managed,
+	 *             'visible' says if field is visible in list (-1 means not shown by default but can be aded into list to be viewed)
+	 *             'notnull' if not null in database
+	 *             'index' if we want an index in database
+	 *             'position' is the sort order of field
+	 *             'searchall' is 1 if we want to search in this field when making a search from the quick search button
+	 *             'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
+	 *             'comment' is not used. You can store here any text of your choice.
+	 */
+
+	// BEGIN MODULEBUILDER PROPERTIES
+	/**
+	 * @var array  Array with all fields and their property
+	 */
+	public $fields=array(
+		'rowid' => array('type'=>'integer', 'label'=>'TechnicalID', 'visible'=>-1, 'enabled'=>1, 'position'=>1, 'notnull'=>1, 'index'=>1, 'comment'=>'Id',),
+		'ref' => array('type'=>'varchar(64)', 'label'=>'Ref', 'visible'=>1, 'enabled'=>1, 'position'=>10, 'notnull'=>1, 'index'=>1, 'searchall'=>1, 'comment'=>'Reference of object',),
+		'entity' => array('type'=>'integer', 'label'=>'Entity', 'visible'=>0, 'enabled'=>1, 'position'=>20, 'notnull'=>1, 'index'=>1,),
+		'fk_warehouse' => array('type'=>'integer', 'label'=>'', 'visible'=>1, 'enabled'=>1, 'index'=>1,),
+		'date_inventory' => array('type'=>'date', 'label'=>'', 'visible'=>1, 'enabled'=>1,),
+		'title' => array('type'=>'varchar(255)', 'label'=>'', 'visible'=>1, 'enabled'=>1,),
+		'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>1, 'enabled'=>1, 'position'=>1000, 'index'=>1,),
+		'date_creation' => array('type'=>'datetime', 'label'=>'DateCreation', 'visible'=>-1, 'enabled'=>1, 'position'=>500,),
+		'date_validation' => array('type'=>'datetime', 'label'=>'DateValidation', 'visible'=>-1, 'enabled'=>1, 'position'=>500,),
+		'tms' => array('type'=>'timestamp', 'label'=>'DateModification', 'visible'=>-1, 'enabled'=>1, 'position'=>500, 'notnull'=>1,),
+		'fk_user_creat' => array('type'=>'integer', 'label'=>'UserAuthor', 'visible'=>-1, 'enabled'=>1, 'position'=>500,),
+		'fk_user_modif' => array('type'=>'integer', 'label'=>'UserModif', 'visible'=>-1, 'enabled'=>1, 'position'=>500,),
+		'fk_user_valid' => array('type'=>'integer', 'label'=>'UserValid', 'visible'=>-1, 'enabled'=>1, 'position'=>500,),
+		'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'visible'=>-1, 'enabled'=>1, 'position'=>1000, 'index'=>1,),
 	);
 
-    /**
-     *  Constructor
-     *
-     *  @param      DoliDB		$db      Database handler
-     */
-	public function __construct(DoliDB &$db) 
-	{
-		global $conf;
+	public $rowid;
+	public $ref;
+	public $entity;
+	public $fk_warehouse;
+	public $date_inventory;
+	public $title;
+	public $status;
+	public $date_creation;
+	public $date_validation;
+	public $tms;
+	public $fk_user_creat;
+	public $fk_user_modif;
+	public $fk_user_valid;
+	public $import_key;
+	// END MODULEBUILDER PROPERTIES
 
-        parent::__construct($db);
-		parent::init();
-		
-       	$this->status = 0;
-		$this->entity = $conf->entity;
-		$this->errors = array();
-		$this->amount = 0;
-	}
 
-    /**
-     * Function to sort children object
-     */
-	public function sortDet()
-	{
-		if(!empty($this->Inventorydet))	usort($this->Inventorydet, array('Inventory', 'customSort'));
-	}
 
-    /**
-     *	Get object and children from database
-     *
-     *	@param      int			$id       		Id of object to load
-     * 	@param		bool		$loadChild		used to load children from database
-     *	@return     int         				>0 if OK, <0 if KO, 0 if not found
-     */
-	public function fetch($id, $loadChild = true)
-	{
-        if(!$loadChild) $this->withChild = false;
-        
-		$res = parent::fetch($id, $loadChild);
+	// If this object has a subtable with lines
+
+	/**
+	 * @var int    Name of subtable line
+	 */
+	//public $table_element_line = 'inventorydet';
+	/**
+	 * @var int    Field with ID of parent key if this field has a parent
+	 */
+	//public $fk_element = 'fk_inventory';
+	/**
+	 * @var int    Name of subtable class that manage subtable lines
+	 */
+	//public $class_element_line = 'Inventoryline';
+	/**
+	 * @var array  Array of child tables (child tables to delete before deleting a record)
+	 */
+	//protected $childtables=array('inventorydet');
+	/**
+	 * @var InventoryLine[]     Array of subtable lines
+	 */
+	//public $lines = array();
+
 
-		if ($res > 0)
-		{
-			$this->sortDet();
-			$this->amount = 0;
-			if(!empty($this->Inventorydet ))
-			{
-				foreach($this->Inventorydet as &$det)
-				{
-					$this->amount += $det->qty_view * $det->pmp;
-				}
-			}
-		}
-				
-		return $res;
-	}
 
-    /**
-     * Custom function call by usort
-     *
-     * @param   Inventorydet    $objA   first Inventorydet object
-     * @param   Inventorydet    $objB   second Inventorydet object
-     * @return                          int
-     */
-	private function customSort(&$objA, &$objB)
+	/**
+	 * Constructor
+	 *
+	 * @param DoliDb $db Database handler
+	 */
+	public function __construct(DoliDB $db)
 	{
-		$r = strcmp(strtoupper(trim($objA->product->ref)), strtoupper(trim($objB->product->ref)));
-		
-		if ($r < 0) $r = -1;
-		elseif ($r > 0) $r = 1;
-		else $r = 0;
-		
-		return $r;
+		$this->db = $db;
 	}
 
-    /**
-     * @param   User    $user   user object
-     * @return                  int
-     */
-    public function changePMP(User &$user)
-    {
-        $error = 0;
-        $this->db->begin();
 
-		if(!empty($this->Inventorydet))
-		{
-			foreach ($this->Inventorydet as $k => &$Inventorydet)
-			{
-				if($Inventorydet->new_pmp>0)
-				{
-					$Inventorydet->pmp = $Inventorydet->new_pmp; 
-					$Inventorydet->new_pmp = 0;
-				
-					$res = $this->db->query('UPDATE '.MAIN_DB_PREFIX.'product as p SET pmp = '.$Inventorydet->pmp.' WHERE rowid = '.$Inventorydet->fk_product );
-					if (!$res)
-                    {
-                        $error++;
-                        $this->error = $this->db->lasterror();
-                        $this->errors[] = $this->db->lasterror();
-                    }
-				}
-			}
-		}
-		
-		$res = parent::update($user);
-        if (!$res)
-        {
-            $error++;
-            $this->error = $this->db->lasterror();
-            $this->errors[] = $this->db->lasterror();
-        }
+	/**
+	 *  Return a link to the object card (with optionaly the picto)
+	 *
+	 *	@param	int		$withpicto			Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
+	 *	@param	string	$option				On what the link point to
+     *  @param	int  	$notooltip			1=Disable tooltip
+     *  @param  string  $morecss            Add more css on link
+	 *	@return	string						String with URL
+	 */
+	function getNomUrl($withpicto=0, $option='', $notooltip=0, $morecss='')
+	{
+		global $db, $conf, $langs;
+        global $dolibarr_main_authentication, $dolibarr_main_demo;
+        global $menumanager;
 
+        if (! empty($conf->dol_no_mouse_hover)) $notooltip=1;   // Force disable tooltips
 
-        if (!$error)
-        {
-            $this->db->commit();
-            return 1;
-        }
-        else
-        {
-            $this->db->rollback();
-            return -1;
-        }
-	}
+        $result = '';
+        $companylink = '';
 
-    /**
-     * Function to update object or create or delete if needed
-     *
-     * @param   User    $user   user object
-     * @return                  < 0 if ko, > 0 if ok
-     */
-	public function update(User &$user)
-	{
-		$error = 0;
-		$this->db->begin();
+        $label = '<u>' . $langs->trans("Inventory") . '</u>';
+        $label.= '<br>';
+        $label.= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref;
 
-        // if we valid the inventory we save the stock at the same time
-		if ($this->status)
-		{
-		    $res = $this->regulate();
-            if ($res < 0)
-            {
-                $error++;
-                $this->error = $this->db->lasterror();
-                $this->errors[] = $this->db->lasterror();
-            }
-		}
+        $url = $url = dol_buildpath('/inventory/m_card.php',1).'?id='.$this->id;
 
-        $res = parent::update($user);
-        if (!$res)
+        $linkclose='';
+        if (empty($notooltip))
         {
-            $error++;
-            $this->error = $this->db->lasterror();
-            $this->errors[] = $this->db->lasterror();
+            if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
+            {
+                $label=$langs->trans("ShowInventory");
+                $linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
+            }
+            $linkclose.=' title="'.dol_escape_htmltag($label, 1).'"';
+            $linkclose.=' class="classfortooltip'.($morecss?' '.$morecss:'').'"';
         }
+        else $linkclose = ($morecss?' class="'.$morecss.'"':'');
 
-		if (!$error)
-        {
-            $this->db->commit();
-            return $this->id;
-        }
-        else
+		$linkstart = '<a href="'.$url.'"';
+		$linkstart.=$linkclose.'>';
+		$linkend='</a>';
+
+        if ($withpicto)
         {
-            $this->db->rollback();
-            return -1;
-        }
+            $result.=($linkstart.img_object(($notooltip?'':$label), 'label', ($notooltip?'':'class="classfortooltip"')).$linkend);
+            if ($withpicto != 2) $result.=' ';
+		}
+		$result.= $linkstart . $this->ref . $linkend;
+		return $result;
 	}
 
-    /**
-     * Function to update current object
-     *
-     * @param   array   $Tab    Array of values
-     * @return                  int
-     */
-	public function setValues(&$Tab)
+	/**
+	 *  Retourne le libelle du status d'un user (actif, inactif)
+	 *
+	 *  @param	int		$mode          0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
+	 *  @return	string 			       Label of status
+	 */
+	function getLibStatut($mode=0)
 	{
-		global $langs;
-		
-		if (isset($Tab['qty_to_add']))
-		{
-			foreach ($Tab['qty_to_add'] as $k => $qty)
-			{
-				$qty = (float) price2num($qty);
-				
-				if ($qty < 0) 
-				{
-					$this->errors[] = $langs->trans('inventoryErrorQtyAdd');
-					return -1;
-				} 
-				
-				$product = new Product($this->db);
-				$product->fetch($this->Inventorydet[$k]->fk_product);
-				
-				$this->Inventorydet[$k]->pmp = $product->pmp;
-				$this->Inventorydet[$k]->qty_view += $qty;
-			}	
-		}
-		
-		return parent::setValues($Tab);
+		return $this->LibStatut($this->status,$mode);
 	}
 
-    /**
-     * Function to delete all Inventorydet
-     *
-     * @param   User    $user   user object
-     * @return                  < 0 if ko, > 0 if ok
-     */
-    public function deleteAllLine(User &$user)
-    {
-        foreach($this->Inventorydet as &$det)
-        {
-            $det->to_delete = true;
-        }
-        
-        $res = $this->update($user);
-
-        if ($res > 0) $this->Inventorydet = array();
-        else return -1;
-    }
-
-    /**
-     * Function to add Inventorydet
-     *
-     * @param   int     $fk_product     fk_product of Inventorydet
-     * @param   int     $fk_warehouse   fk_warehouse target
-     * @return                          bool
-     */
-    public function addProduct($fk_product, $fk_warehouse=0)
-    {
-        $k = $this->addChild('Inventorydet');
-        $det =  &$this->Inventorydet[$k];
-        
-        $det->fk_inventory = $this->id;
-        $det->fk_product = $fk_product;
-		$det->fk_warehouse = empty($fk_warehouse) ? $this->fk_warehouse : $fk_warehouse;
-        
-        $det->load_product();
-                
-        $date = $this->getDate('date_inventory', 'Y-m-d');
-        if(empty($date)) $date = $this->getDate('datec', 'Y-m-d');
-        $det->setStockDate($date, $fk_warehouse);
-        
-        return true;
-    }
-
-    /**
-     *  Duplication method product to add datem
-     *  Adjust stock in a warehouse for product
-     *
-     *  @param  	int     $fk_product     id of product
-     *  @param  	int		$fk_warehouse   id of warehouse
-     *  @param  	double	$nbpiece        nb of units
-     *  @param  	int		$movement       0 = add, 1 = remove
-     * 	@param		string	$label			Label of stock movement
-     * 	@param		double	$price			Unit price HT of product, used to calculate average weighted price (PMP in french). If 0, average weighted price is not changed.
-     *  @param		string	$inventorycode	Inventory code
-     * 	@return     int     				<0 if KO, >0 if OK
-     */
-    public function correctStock($fk_product, $fk_warehouse, $nbpiece, $movement, $label='', $price=0, $inventorycode='')
+	/**
+	 *  Return the status
+	 *
+	 *  @param	int		$status        	Id status
+	 *  @param  int		$mode          	0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 5=Long label + Picto
+	 *  @return string 			       	Label of status
+	 */
+	static function LibStatut($status,$mode=0)
 	{
-		global $conf, $user;
+		global $langs;
 
-		if ($fk_warehouse)
+		if ($mode == 0)
 		{
-			$this->db->begin();
-
-			require_once DOL_DOCUMENT_ROOT .'/product/stock/class/mouvementstock.class.php';
-
-			$op[0] = "+".trim($nbpiece);
-			$op[1] = "-".trim($nbpiece);
-
-			$datem = empty($conf->global->INVENTORY_USE_INVENTORY_DATE_FROM_DATEMVT) ? dol_now() : $this->date_inventory;
-
-			$movementstock=new MouvementStock($this->db);
-			$movementstock->origin = new stdClass();
-			$movementstock->origin->element = 'inventory';
-			$movementstock->origin->id = $this->id;
-			$result=$movementstock->_create($user,$fk_product,$fk_warehouse,$op[$movement],$movement,$price,$label,$inventorycode, $datem);
-			
-			if ($result >= 0)
-			{
-				$this->db->commit();
-				return 1;
-			}
-			else
-			{
-			    $this->error=$movementstock->error;
-			    $this->errors=$movementstock->errors;
-
-				$this->db->rollback();
-				return -1;
-			}
+			$prefix='';
+			if ($status == 1) return $langs->trans('Enabled');
+			if ($status == 0) return $langs->trans('Disabled');
 		}
-	}
-
-    /**
-     * Function to regulate stock
-     *
-     * @return      int
-     */
-	public function regulate()
-	{
-		global $langs,$conf;
-		
-		if($conf->global->INVENTORY_DISABLE_VIRTUAL)
+		if ($mode == 1)
 		{
-			$pdt_virtuel = false;
-			// Test if virtual product is enabled
-			if($conf->global->PRODUIT_SOUSPRODUITS)
-			{
-				$pdt_virtuel = true;
-				$conf->global->PRODUIT_SOUSPRODUITS = 0;
-			}
+			if ($status == 1) return $langs->trans('Enabled');
+			if ($status == 0) return $langs->trans('Disabled');
 		}
-		
-		foreach ($this->Inventorydet as $k => $Inventorydet)
+		if ($mode == 2)
 		{
-			$product = new Product($this->db);
-			$product->fetch($Inventorydet->fk_product);
-
-			if ($Inventorydet->qty_view != $Inventorydet->qty_stock)
-			{
-				$Inventorydet->qty_regulated = $Inventorydet->qty_view - $Inventorydet->qty_stock;
-				$nbpiece = abs($Inventorydet->qty_regulated);
-				$movement = (int) ($Inventorydet->qty_view < $Inventorydet->qty_stock); // 0 = add ; 1 = remove
-						
-				//$href = dol_buildpath('/inventory/inventory.php?id='.$this->id.'&action=view', 1);
-				
-				$res = $this->correctStock($product->id, $Inventorydet->fk_warehouse, $nbpiece, $movement, $langs->trans('inventoryMvtStock'));
-				if ($res < 0) return -1;
-			}
+			if ($status == 1) return img_picto($langs->trans('Enabled'),'statut4').' '.$langs->trans('Enabled');
+			if ($status == 0) return img_picto($langs->trans('Disabled'),'statut5').' '.$langs->trans('Disabled');
 		}
-
-		if($conf->global->INVENTORY_DISABLE_VIRTUAL)
+		if ($mode == 3)
 		{
-            // Test if virtual product was enabled before regulate
-			if($pdt_virtuel) $conf->global->PRODUIT_SOUSPRODUITS = 1;
+			if ($status == 1) return img_picto($langs->trans('Enabled'),'statut4');
+			if ($status == 0) return img_picto($langs->trans('Disabled'),'statut5');
 		}
-		
-		return 1;
-	}
-
-    /**
-     * Get the title
-     * @return  string
-     */
-	public function getTitle()
-    {
-		global $langs;
-		
-		return !empty($this->title) ? $this->title : $langs->trans('inventoryTitle').' '.$this->id;
-	}
-
-
-    /**
-     * Return clicable link of object (with eventually picto)
-     *
-     * @param   int     $withpicto  Add picto into link
-     * @return                      string
-     */
-	public function getNomUrl($withpicto = 1)
-    {
-        return '<a href="'.DOL_URL_ROOT.'/product/inventory/card.php?id='.$this->id.'">'.($withpicto ? img_picto('','object_list.png','',0).' ' : '').$this->getTitle().'</a>';
-	}
-
-    /**
-     * Function to add products by default from warehouse and children
-     *
-     * @param int $fk_warehouse         id of warehouse
-     * @param int $fk_category          id of category
-     * @param int $fk_supplier          id of supplier
-     * @param int $only_prods_in_stock  only product with stock
-     *
-     * @return int
-     */
-	public function addProductsFor($fk_warehouse,$fk_category=0,$fk_supplier=0,$only_prods_in_stock=0)
-    {
-        $warehouse = new Entrepot($this->db);
-        $warehouse->fetch($fk_warehouse);
-		$TChildWarehouses = array($fk_warehouse);
-        $warehouse->get_children_warehouses($fk_warehouse, $TChildWarehouses);
-			
-		$sql = 'SELECT ps.fk_product, ps.fk_entrepot';
-		$sql.= ' FROM '.MAIN_DB_PREFIX.'product_stock ps';
-        $sql.= ' INNER JOIN '.MAIN_DB_PREFIX.'product p ON (p.rowid = ps.fk_product)';
-        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product cp ON (cp.fk_product = p.rowid)';
-        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_fournisseur_price pfp ON (pfp.fk_product = p.rowid)';
-        $sql.= ' WHERE ps.fk_entrepot IN ('.implode(', ', $TChildWarehouses).')';
-			
-		if ($fk_category>0) $sql.= ' AND cp.fk_categorie='.$fk_category;
-		if ($fk_supplier>0) $sql.= ' AND pfp.fk_soc = '.$fk_supplier;
-		if (!empty($only_prods_in_stock)) $sql.= ' AND ps.reel > 0';
-			
-		$sql.=' GROUP BY ps.fk_product, ps.fk_entrepot ORDER BY p.ref ASC,p.label ASC';
-		 
-		$res = $this->db->query($sql);
-		if($res)
+		if ($mode == 4)
 		{
-			while($obj = $this->db->fetch_object($res))
-            {
-				$this->addProduct($obj->fk_product, $obj->fk_entrepot);
-			}
-
-			return 1;
+			if ($status == 1) return img_picto($langs->trans('Enabled'),'statut4').' '.$langs->trans('Enabled');
+			if ($status == 0) return img_picto($langs->trans('Disabled'),'statut5').' '.$langs->trans('Disabled');
 		}
-		else
-        {
-            $this->error = $this->db->lasterror();
-            $this->errors[] = $this->db->lasterror();
-            return -1;
-        }
-	}
-
-    /**
-     * Return clicable link of inventory object
-     *
-     * @param   int     $id         id of inventory
-     * @param   int     $withpicto  Add picto into link
-     * @return  string
-     */
-    static function getLink($id, $withpicto=1)
-    {
-        global $langs,$db;
-        
-        $inventory = new Inventory($db);
-        if($inventory->fetch($id, false) > 0) return $inventory->getNomUrl($withpicto);
-        else return $langs->trans('InventoryUnableToFetchObject');
-    }
-
-    /**
-     * Function to get the sql select of inventory
-     * 
-     * @param   string  $type   'All' to get all data
-     * @return  string
-     */
-	static function getSQL($type)
-    {
-		global $conf;
-
-        $sql = '';
-		if($type == 'All')
+		if ($mode == 5)
 		{
-			$sql = 'SELECT i.rowid,i.title, e.label, i.date_inventory, i.fk_warehouse, i.datec, i.tms, i.status';
-            $sql.= ' FROM '.MAIN_DB_PREFIX.'inventory i';
-            $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'entrepot e ON (e.rowid = i.fk_warehouse)';
-            $sql.= ' WHERE i.entity IN ('.getEntity('inventory').')';
+			if ($status == 1) return $langs->trans('Enabled').' '.img_picto($langs->trans('Enabled'),'statut4');
+			if ($status == 0) return $langs->trans('Disabled').' '.img_picto($langs->trans('Disabled'),'statut5');
 		}
-	
-		return $sql;	
-	}
-}
-
-class Inventorydet extends CoreObject
-{
-	public $element='inventorydet';
-	public $table_element='inventorydet';
-	protected $isnolinkedbythird = 1;     // No field fk_soc
-	protected $ismultientitymanaged = 0;	// 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
-	
-	public $fk_inventory;
-	public $fk_warehouse;
-	public $fk_product;
-	public $entity;
-	public $qty_view;
-	public $qty_stock;
-	public $qty_regulated;
-	public $pmp;
-	public $pa;
-	public $new_pmp;
-	
-	protected $fields=array(
-		'fk_inventory'=>array('type'=>'int')
-		,'fk_warehouse'=>array('type'=>'int')
-		,'fk_product'=>array('type'=>'int')
-		,'entity'=>array('type'=>'int')
-		,'qty_view'=>array('type'=>'float')
-		,'qty_stock'=>array('type'=>'float')
-		,'qty_regulated'=>array('type'=>'float')
-		,'pmp'=>array('type'=>'float')
-		,'pa'=>array('type'=>'float')
-		,'new_pmp'=>array('type'=>'float')
-	);
-
-    /**
-     *  Constructor
-     *
-     *  @param      DoliDB		$db      Database handler
-     */
-	function __construct(DoliDB &$db)
-	{
-		global $conf;
-
-		parent::__construct($db);
-		parent::init();
-				
-		$this->entity = $conf->entity;
-		$this->errors = array();
-		
-		$this->product = null;
-		$this->current_pa = 0;
-	}
-
-    /**
-     * Get object and children from database
-     *
-     * @param   int   $id           id of inventorydet object
-     * @param   bool  $loadChild    load children
-     * @return  int
-     */
-	function fetch($id, $loadChild = true)
-	{
-		$res = parent::fetch($id);
-		$this->load_product();
-        $this->fetch_current_pa();
-			
-		return $res;
-	}
-
-    /**
-     * Function to get the unit buy price
-     *
-     * @return bool
-     */
-    function fetch_current_pa()
-    {
-		global $db,$conf;
-		
-		if(empty($conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA)) return false;
-		
-		if($this->pa > 0)
+		if ($mode == 6)
 		{
-			$this->current_pa = $this->pa;
-		}
-		else
-        {
-			dol_include_once('/fourn/class/fournisseur.product.class.php');
-			$p= new ProductFournisseur($db);
-			$p->find_min_price_product_fournisseur($this->fk_product);
-			
-			if($p->fourn_qty>0)	$this->current_pa = $p->fourn_price / $p->fourn_qty;
+			if ($status == 1) return $langs->trans('Enabled').' '.img_picto($langs->trans('Enabled'),'statut4');
+			if ($status == 0) return $langs->trans('Disabled').' '.img_picto($langs->trans('Disabled'),'statut5');
 		}
-
-		return true;
 	}
 
-    /**
-     * Function to set pa attribute from date en fk_warehouse
-     *
-     * @param   date    $date           date value
-     * @param   int     $fk_warehouse   fk_warehouse target
-     */
-    function setStockDate($date, $fk_warehouse)
-    {
-		list($pmp, $stock) = $this->getPmpStockFromDate($date, $fk_warehouse);
-
-        $this->qty_stock = $stock;
-        $this->pmp = $pmp;
-
-        $last_pa = 0;
-        $sql = 'SELECT price FROM '.MAIN_DB_PREFIX.'stock_mouvement';
-        $sql.= ' WHERE fk_entrepot = '.$fk_warehouse;
-        $sql.= ' AND fk_product = '.$this->fk_product;
-        $sql.= ' AND (origintype=\'order_supplier\' || origintype=\'invoice_supplier\')';
-        $sql.= ' AND price > 0';
-        $sql.= ' AND datem <= \''.$date.' 23:59:59\'';
-        $sql.= ' ORDER BY datem DESC LIMIT 1';
-
-        $res = $this->db->query($sql);
-        if($res && $obj = $this->db->fetch_object($res))
-        {
-            $last_pa = $obj->price;
-        }
-
-        $this->pa = $last_pa;
-    }
-
-
-    /**
-     * Get the last pmp and last stock from date and warehouse
-     *
-     * @param   date    $date           date to check
-     * @param   int     $fk_warehouse   id of warehouse
-     * @return array
-     */
-    function getPmpStockFromDate($date, $fk_warehouse)
-    {
-		$res = $this->product->load_stock();
-		
-		if($res>0)
-		{
-			$stock = isset($this->product->stock_warehouse[$fk_warehouse]->real) ? $this->product->stock_warehouse[$fk_warehouse]->real : 0;
-            $pmp = $this->product->pmp;
-		}
-		
-		//All Stock mouvement between now and inventory date
-		$sql = 'SELECT value, price';
-        $sql.= ' FROM '.MAIN_DB_PREFIX.'stock_mouvement';
-        $sql.= ' WHERE fk_product = '.$this->product->id;
-        $sql.= ' AND fk_entrepot = '.$fk_warehouse;
-        $sql.= ' AND datem > \''.date('Y-m-d 23:59:59', strtotime($date)).'\'';
-        $sql.= ' ORDER BY datem DESC';
-
-		$res = $this->db->query($sql);
-		
-		$laststock = $stock;
-		$lastpmp = $pmp;
-		
-		if($res)
-		{
-			while($mouvement = $this->db->fetch_object($res))
-            {
-				$price = ($mouvement->price > 0 && $mouvement->value > 0) ? $mouvement->price : $lastpmp;
-				$stock_value = $laststock * $lastpmp;
-				$laststock -= $mouvement->value;
-				$last_stock_value = $stock_value - ($mouvement->value * $price);
-				$lastpmp = ($laststock != 0) ? $last_stock_value / $laststock : $lastpmp;
-			}
-		}
-		
-		return array($lastpmp, $laststock);
-	}
 
-    /**
-     * Fetch the product linked with the line
-     * @return  void
-     */
-	function load_product() 
+	/**
+	 * Initialise object with example values
+	 * Id must be 0 if object instance is a specimen
+	 *
+	 * @return void
+	 */
+	public function initAsSpecimen()
 	{
-		global $db;
-		
-		if($this->fk_product>0)
-		{
-			$this->product = new Product($db);
-			$this->product->fetch($this->fk_product);
-		}
+		$this->initAsSpecimenCommon();
 	}
+
+}
+
+/**
+ * Class InventoryObjectLine
+ */
+class InventoryObjectLine
+{
+	/**
+	 * @var int ID
+	 */
+	public $id;
+	/**
+	 * @var mixed Sample line property 1
+	 */
+	public $prop1;
+	/**
+	 * @var mixed Sample line property 2
+	 */
+	public $prop2;
 }
diff --git a/htdocs/product/inventory/list.php b/htdocs/product/inventory/list.php
index c8d570a6fd7..2a8d9861e5a 100644
--- a/htdocs/product/inventory/list.php
+++ b/htdocs/product/inventory/list.php
@@ -1,5 +1,6 @@
 <?php
-/* Copyright (C) 2016		ATM Consulting			<support@atm-consulting.fr>
+/* Copyright (C) 2007-2017 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) ---Put here your own copyright and developer email---
  *
  * 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
@@ -16,119 +17,623 @@
  */
 
 /**
- *	\file       htdocs/inventory/list.php
- *	\ingroup    product
- *	\brief      File of class to manage inventory
+ *   	\file       product/inventory/list.php
+ *		\ingroup    inventory
+ *		\brief      List page for monmodule
  */
- 
-require_once '../../main.inc.php';
-
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/listview.class.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
-require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
-include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/class/inventory.class.php';
-require_once DOL_DOCUMENT_ROOT.'/product/inventory/lib/inventory.lib.php';
-
-$langs->load("stock");
-$langs->load("inventory");
 
+//if (! defined('NOREQUIREUSER'))          define('NOREQUIREUSER','1');
+//if (! defined('NOREQUIREDB'))            define('NOREQUIREDB','1');
+//if (! defined('NOREQUIRESOC'))           define('NOREQUIRESOC','1');
+//if (! defined('NOREQUIRETRAN'))          define('NOREQUIRETRAN','1');
+//if (! defined('NOSCANGETFORINJECTION'))  define('NOSCANGETFORINJECTION','1');			// Do not check anti CSRF attack test
+//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION','1');			// Do not check anti CSRF attack test
+//if (! defined('NOCSRFCHECK'))            define('NOCSRFCHECK','1');			// Do not check anti CSRF attack test
+//if (! defined('NOSTYLECHECK'))           define('NOSTYLECHECK','1');			// Do not check style html tag into posted data
+//if (! defined('NOTOKENRENEWAL'))         define('NOTOKENRENEWAL','1');		// Do not check anti POST attack test
+//if (! defined('NOREQUIREMENU'))          define('NOREQUIREMENU','1');			// If there is no need to load and show top and left menu
+//if (! defined('NOREQUIREHTML'))          define('NOREQUIREHTML','1');			// If we don't need to load the html.form.class.php
+//if (! defined('NOREQUIREAJAX'))          define('NOREQUIREAJAX','1');         // Do not load ajax.lib.php library
+//if (! defined("NOLOGIN"))                define("NOLOGIN",'1');				// If this page is public (can be called outside logged session)
+
+
+// Load Dolibarr environment
+$res=0;
+// Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
+if (! $res && ! empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res=@include($_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php");
+// Try main.inc.php into web root detected using web root caluclated from SCRIPT_FILENAME
+$tmp=empty($_SERVER['SCRIPT_FILENAME'])?'':$_SERVER['SCRIPT_FILENAME'];$tmp2=realpath(__FILE__); $i=strlen($tmp)-1; $j=strlen($tmp2)-1;
+while($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i]==$tmp2[$j]) { $i--; $j--; }
+if (! $res && $i > 0 && file_exists(substr($tmp, 0, ($i+1))."/main.inc.php")) $res=@include(substr($tmp, 0, ($i+1))."/main.inc.php");
+if (! $res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php")) $res=@include(dirname(substr($tmp, 0, ($i+1)))."/main.inc.php");
+// Try main.inc.php using relative path
+if (! $res && file_exists("../main.inc.php")) $res=@include("../main.inc.php");
+if (! $res && file_exists("../../main.inc.php")) $res=@include("../../main.inc.php");
+if (! $res && file_exists("../../../main.inc.php")) $res=@include("../../../main.inc.php");
+if (! $res) die("Include of main fails");
+
+require_once(DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php');
+require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
+dol_include_once('/inventory/class/inventory.class.php');
+
+// Load traductions files requiredby by page
+$langs->loadLangs(array("inventory","other"));
+
+$action     = GETPOST('action','alpha');
+$massaction = GETPOST('massaction','alpha');
+$show_files = GETPOST('show_files','int');
+$confirm    = GETPOST('confirm','alpha');
+$cancel     = GETPOST('cancel', 'alpha');
+$toselect   = GETPOST('toselect', 'array');
+$contextpage= GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'inventorylist';   // To manage different context of search
+
+$id			= GETPOST('id','int');
+$backtopage = GETPOST('backtopage');
+$optioncss  = GETPOST('optioncss','alpha');
+
+// Load variable for pagination
 $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit;
-$sortfield = GETPOST("sortfield",'alpha');
-$sortorder = GETPOST("sortorder",'alpha');
-$page = (GETPOST("page",'int')?GETPOST("page", 'int'):0);
+$sortfield = GETPOST('sortfield','alpha');
+$sortorder = GETPOST('sortorder','alpha');
+$page = GETPOST('page','int');
 if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined, or '' or -1
 $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortfield) $sortfield="i.title";
+
+// Initialize technical objects
+$object=new Inventory($db);
+$extrafields = new ExtraFields($db);
+$diroutputmassaction=$conf->inventory->dir_output . '/temp/massgeneration/'.$user->id;
+$hookmanager->initHooks(array('inventorylist'));     // Note that conf->hooks_modules contains array
+// Fetch optionals attributes and labels
+$extralabels = $extrafields->fetch_name_optionals_label('inventory');
+$search_array_options=$extrafields->getOptionalsFromPost($extralabels,'','search_');
+
+// Default sort order (if not yet defined by previous GETPOST)
+if (! $sortfield) $sortfield="t.".key($object->fields);   // Set here default search field. By default 1st field in definition.
 if (! $sortorder) $sortorder="ASC";
 
-if (empty($user->rights->stock->lire)) accessforbidden();
+// Protection if external user
+$socid=0;
+if ($user->societe_id > 0)
+{
+    //$socid = $user->societe_id;
+	accessforbidden();
+}
+
+// Initialize array of search criterias
+$search_all=trim(GETPOST("search_all",'alpha'));
+$search=array();
+foreach($object->fields as $key => $val)
+{
+    if (GETPOST('search_'.$key,'alpha')) $search[$key]=GETPOST('search_'.$key,'alpha');
+}
+
+// List of fields to search into when doing a "search in all"
+$fieldstosearchall = array();
+foreach($object->fields as $key => $val)
+{
+    if ($val['searchall']) $fieldstosearchall['t.'.$key]=$val['label'];
+}
+
+// Definition of fields for list
+$arrayfields=array();
+foreach($object->fields as $key => $val)
+{
+	// If $val['visible']==0, then we never show the field
+    if (! empty($val['visible'])) $arrayfields['t.'.$key]=array('label'=>$val['label'], 'checked'=>(($val['visible']<0)?0:1), 'enabled'=>$val['enabled']);
+}
+// 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
+ * ACTIONS
+ *
+ * Put here all code to do according to value of "$action" parameter
  */
 
-// None
+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','alpha') || GETPOST('button_removefilter.x','alpha') ||GETPOST('button_removefilter','alpha')) // All tests are required to be compatible with all browsers
+    {
+        foreach($object->fields as $key => $val)
+        {
+            $search[$key]='';
+        }
+        $toselect='';
+        $search_array_options=array();
+    }
+    if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha')
+        || GETPOST('button_search_x','alpha') || GETPOST('button_search.x','alpha') || GETPOST('button_search','alpha'))
+    {
+        $massaction='';     // Protection to avoid mass action if we force a new search during a mass action confirmation
+    }
+
+    // Mass actions
+    $objectclass='Inventory';
+    $objectlabel='Inventory';
+    $permtoread = $user->rights->inventory->read;
+    $permtodelete = $user->rights->inventory->delete;
+    $uploaddir = $conf->inventory->dir_output;
+    include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
+}
+
 
 
 /*
- * View
+ * VIEW
+ *
+ * Put here all code to build page
  */
 
-llxHeader('',$langs->trans('inventoryListTitle'),'','');
-
-echo '<form name="formListInvetory" action="'.$_SERVER['PHP_SELF'].'" method="post" >';
-
-$inventory = new Inventory($db);
-$list = new ListView($db, 'listInventory');
-
-$THide = array('label','title');
-
-echo $list->render(Inventory::getSQL('All'), array(
-    'param' => array(
-        'limit' => $limit,
-        'offset' => $offset,
-        'sortfield' => $sortfield,
-        'sortorder'=> $sortorder,
-        'page'=>$page
-    ),
-    'limit' => array(
-	    'nbLine' => $limit,
-	),
-	'allow-field-select' => true,
-    'link'=>array(
-        'fk_warehouse'=>'<a href="'.DOL_URL_ROOT.'/product/stock/card.php?id=@val@">'.img_picto('','object_stock.png','',0).' @label@</a>'
-    ),
-    'translate'=>array(),
-    'hide'=>$THide,
-    'type'=>array(
-        'datec'=>'date',
-        'tms'=>'datetime',
-        'date_inventory'=>'date'
-    ),
-    'list'=>array(
-        'title'=>$langs->trans('inventoryListTitle'),
-        'messageNothing'=>$langs->trans('inventoryListEmpty'),
-		'image' => 'title_products.png'
-    ),
-    'title'=>array(
-        'rowid'=>$langs->trans('Title'),
-		'date_inventory'=>$langs->trans('InventoryDate'),
-        'fk_warehouse'=>$langs->trans('Warehouse'),
-        'datec'=>$langs->trans('DateCreation'),
-        'tms'=>$langs->trans('DateModification'),
-        'status'=>$langs->trans('Status')
-    ),
-    'eval'=>array(
-        'status' => '(@val@ ? img_picto("'.$langs->trans("inventoryValidate").'", "statut4") : img_picto("'.$langs->trans("inventoryDraft").'", "statut3"))',
-        'rowid'=>'Inventory::getLink(@val@)'
-    ),
-	'position' => array(
-		'text-align' => array('status' => 'right')
-		
-	),
-    'search'=>array(
-		'rowid' => array('search_type' => true, 'table' => array('i'), 'field' => array('title')),
-		'date_inventory'=>array('search_type' => 'calendars', 'table' => array('i'), 'field' => array('date_inventory')),
-		'status'=>array('search_type' => array(1=>$langs->trans("inventoryValidate"), 0=>$langs->trans("inventoryDraft")))
-    )
-));
-
-
-/*if (!empty($user->rights->stock->create))
-{
-    print '<div class="tabsAction">';
-    print '<a class="butAction" href="inventory.php?action=create">'.$langs->trans('inventoryCreate').'</a>';
+$form=new Form($db);
+
+$now=dol_now();
+
+//$help_url="EN:Module_Inventory|FR:Module_Inventory_FR|ES:Módulo_Inventory";
+$help_url='';
+$title = $langs->trans('ListOf', $langs->transnoentitiesnoconv("Inventorys"));
+
+
+// Build and execute select
+// --------------------------------------------------------------------
+$sql = 'SELECT ';
+foreach($object->fields as $key => $val)
+{
+    $sql.='t.'.$key.', ';
+}
+// 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=preg_replace('/, $/','', $sql);
+$sql.= " FROM ".MAIN_DB_PREFIX."inventory as t";
+if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."inventory_extrafields as ef on (t.rowid = ef.fk_object)";
+$sql.= " WHERE t.entity IN (".getEntity('inventory').")";
+foreach($search as $key => $val)
+{
+    if ($search[$key] != '') $sql.=natural_search($key, $search[$key], (($key == 'status')?2:($object->fields[$key]['type'] == 'integer'?1:0)));
+}
+if ($search_all) $sql.= natural_search(array_keys($fieldstosearchall), $search_all);
+// 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','real'))) $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 = '';
+if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
+{
+	$result = $db->query($sql);
+	$nbtotalofrecords = $db->num_rows($result);
+}
+
+$sql.= $db->plimit($limit+1, $offset);
+
+dol_syslog($script_file, LOG_DEBUG);
+$resql=$db->query($sql);
+if (! $resql)
+{
+    dol_print_error($db);
+    exit;
+}
+
+$num = $db->num_rows($resql);
+
+// Direct jump if only one record found
+if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all)
+{
+    $obj = $db->fetch_object($resql);
+    $id = $obj->rowid;
+    header("Location: ".DOL_URL_ROOT.'/inventory/inventory_card.php?id='.$id);
+    exit;
+}
+
+
+// Output page
+// --------------------------------------------------------------------
+
+llxHeader('', $title, $help_url);
+
+// Example : Adding jquery code
+print '<script type="text/javascript" language="javascript">
+jQuery(document).ready(function() {
+	function init_myfunc()
+	{
+		jQuery("#myid").removeAttr(\'disabled\');
+		jQuery("#myid").attr(\'disabled\',\'disabled\');
+	}
+	init_myfunc();
+	jQuery("#mybutton").click(function() {
+		init_myfunc();
+	});
+});
+</script>';
+
+$arrayofselected=is_array($toselect)?$toselect:array();
+
+$param='';
+if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
+if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
+foreach($search as $key => $val)
+{
+    $param.= '&search_'.$key.'='.urlencode($search[$key]);
+}
+if ($optioncss != '')     $param.='&optioncss='.$optioncss;
+// 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);
+}
+
+$arrayofmassactions =  array(
+    'presend'=>$langs->trans("SendByMail"),
+    'builddoc'=>$langs->trans("PDFMerge"),
+);
+if ($user->rights->inventory->delete) $arrayofmassactions['delete']=$langs->trans("Delete");
+if ($massaction == 'presend') $arrayofmassactions=array();
+$massactionbutton=$form->selectMassAction('', $arrayofmassactions);
+
+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="page" value="'.$page.'">';
+print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
+
+print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_companies', 0, '', '', $limit);
+
+if ($sall)
+{
+    foreach($fieldstosearchall as $key => $val) $fieldstosearchall[$key]=$langs->trans($val);
+    print $langs->trans("FilterOnInto", $sall) . join(', ',$fieldstosearchall);
+}
+
+$moreforfilter = '';
+$moreforfilter.='<div class="divsearchfield">';
+$moreforfilter.= $langs->trans('MyFilter') . ': <input type="text" name="search_myfield" value="'.dol_escape_htmltag($search_myfield).'">';
+$moreforfilter.= '</div>';
+
+$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))
+{
+	print '<div class="liste_titre liste_titre_bydiv centpercent">';
+	print $moreforfilter;
     print '</div>';
-}*/
+}
+
+$varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
+$selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
+$selectedfields.=$form->showCheckAddButtons('checkforselect', 1);
+
+print '<div class="div-table-responsive">';
+print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
+
+
+// Fields title search
+// --------------------------------------------------------------------
+print '<tr class="liste_titre">';
+foreach($object->fields as $key => $val)
+{
+    if (in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+    $align='';
+    if (in_array($val['type'], array('date','datetime','timestamp'))) $align='center';
+    if (in_array($val['type'], array('timestamp'))) $align.=' nowrap';
+    if (! empty($arrayfields['t.'.$key]['checked'])) print '<td class="liste_titre'.($align?' '.$align:'').'"><input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'"></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')) && empty($extrafields->attribute_computed[$key]))
+            {
+                $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;
+// Rest of fields search
+foreach($object->fields as $key => $val)
+{
+    if (! in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+    $align='';
+    if (in_array($val['type'], array('date','datetime','timestamp'))) $align='center';
+    if (in_array($val['type'], array('timestamp'))) $align.=' nowrap';
+    if (! empty($arrayfields['t.'.$key]['checked'])) print '<td class="liste_titre'.($align?' '.$align:'').'"><input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'"></td>';
+}
+// Action column
+print '<td class="liste_titre" align="right">';
+$searchpicto=$form->showFilterButtons();
+print $searchpicto;
+print '</td>';
+print '</tr>'."\n";
+
+
+// Fields title label
+// --------------------------------------------------------------------
+print '<tr class="liste_titre">';
+foreach($object->fields as $key => $val)
+{
+    if (in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+    $align='';
+    if (in_array($val['type'], array('date','datetime','timestamp'))) $align='center';
+    if (in_array($val['type'], array('timestamp'))) $align.='nowrap';
+    if (! empty($arrayfields['t.'.$key]['checked'])) print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align?'class="'.$align.'"':''), $sortfield, $sortorder, $align.' ')."\n";
+}
+// 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);
+			$sortonfield = "ef.".$key;
+			if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+			print getTitleFieldOfList($langs->trans($extralabels[$key]), 0, $_SERVER["PHP_SELF"], $sortonfield, "", $param, ($align?'align="'.$align.'"':''), $sortfield, $sortorder)."\n";
+       }
+   }
+}
+// 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;
+// Rest of fields title
+foreach($object->fields as $key => $val)
+{
+    if (! in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+    $align='';
+    if (in_array($val['type'], array('date','datetime','timestamp'))) $align='center';
+    if (in_array($val['type'], array('timestamp'))) $align.=' nowrap';
+    if (! empty($arrayfields['t.'.$key]['checked'])) print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align?'class="'.$align.'"':''), $sortfield, $sortorder, $align.' ')."\n";
+}
+print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch ')."\n";
+print '</tr>'."\n";
+
+
+// Detect if we need a fetch on each output line
+$needToFetchEachLine=0;
+foreach ($extrafields->attribute_computed as $key => $val)
+{
+    if (preg_match('/\$object/',$val)) $needToFetchEachLine++;  // There is at least one compute field that use $object
+}
+
+
+// Loop on record
+// --------------------------------------------------------------------
+$i=0;
+$totalarray=array();
+while ($i < min($num, $limit))
+{
+    $obj = $db->fetch_object($resql);
+    if ($obj)
+    {
+    	// Store properties in $object
+    	$object->id = $obj->rowid;
+    	foreach($object->fields as $key => $val)
+    	{
+    		if (isset($obj->$key)) $object->$key = $obj->$key;
+    	}
+
+        // Show here line of result
+        print '<tr class="oddeven">';
+        foreach($object->fields as $key => $val)
+        {
+            if (in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+            $align='';
+            if (in_array($val['type'], array('date','datetime','timestamp'))) $align='center';
+            if (in_array($val['type'], array('timestamp'))) $align.='nowrap';
+            if ($key == 'status') $align.=($align?' ':'').'center';
+            if (! empty($arrayfields['t.'.$key]['checked']))
+            {
+                print '<td'.($align?' class="'.$align.'"':'').'>';
+                if (in_array($val['type'], array('date','datetime','timestamp'))) print dol_print_date($db->jdate($obj->$key), 'dayhour');
+                elseif ($key == 'ref') print $object->getNomUrl(1);
+                elseif ($key == 'status') print $object->getLibStatut(3);
+                else print $obj->$key;
+                print '</td>';
+                if (! $i) $totalarray['nbfield']++;
+                if (! empty($val['isameasure']))
+                {
+                	if (! $i) $totalarray['pos'][$totalarray['nbfield']]='t.'.$key;
+                	$totalarray['val']['t.'.$key] += $obj->$key;
+                }
+            }
+        }
+    	// 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']))
+				{
+					print '<td';
+					$align=$extrafields->getAlignFlag($key);
+					if ($align) print ' align="'.$align.'"';
+					print '>';
+					$tmpkey='options_'.$key;
+					print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1);
+					print '</td>';
+		            if (! $i) $totalarray['nbfield']++;
+		            if (! empty($val['isameasure']))
+		            {
+		            	if (! $i) $totalarray['pos'][$totalarray['nbfield']]='ef.'.$tmpkey;
+		            	$totalarray['val']['ef.'.$tmpkey] += $obj->$tmpkey;
+		            }
+				}
+		   }
+		}
+        // Fields from hook
+	    $parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj);
+		$reshook=$hookmanager->executeHooks('printFieldListValue',$parameters);    // Note that $action and $object may have been modified by hook
+        print $hookmanager->resPrint;
+        // Rest of fields
+        foreach($object->fields as $key => $val)
+        {
+            if (! in_array($key, array('date_creation', 'tms', 'import_key', 'status'))) continue;
+            $align='';
+            if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center';
+            if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap';
+            if ($key == 'status') $align.=($align?' ':'').'center';
+            if (! empty($arrayfields['t.'.$key]['checked']))
+            {
+                print '<td'.($align?' class="'.$align.'"':'').'>';
+                if (in_array($val['type'], array('date','datetime','timestamp'))) print dol_print_date($db->jdate($obj->$key), 'dayhour');
+                elseif ($key == 'status') print $object->getLibStatut(3);
+                else print $obj->$key;
+                print '</td>';
+                if (! $i) $totalarray['nbfield']++;
+                if (! empty($val['isameasure']))
+                {
+	                if (! $i) $totalarray['pos'][$totalarray['nbfield']]='t.'.$key;
+	               	$totalarray['val']['t.'.$key] += $obj->$key;
+                }
+            }
+        }
+        // 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>';
+    }
+    $i++;
+}
+
+// Show total line
+if (isset($totalarray['pos']))
+{
+    print '<tr class="liste_total">';
+    $i=0;
+    while ($i < $totalarray['nbfield'])
+    {
+        $i++;
+        if (! empty($totalarray['pos'][$i]))  print '<td align="right">'.price($totalarray['val'][$totalarray['pos'][$i]]).'</td>';
+        else
+        {
+            if ($i == 1)
+	        {
+	            if ($num < $limit) print '<td align="left">'.$langs->trans("Total").'</td>';
+	            else print '<td align="left">'.$langs->trans("Totalforthispage").'</td>';
+	        }
+        	print '<td></td>';
+        }
+    }
+    print '</tr>';
+}
+
+// If no record found
+if ($num == 0)
+{
+    $colspan=1;
+    foreach($arrayfields as $key => $val) { if (! empty($val['checked'])) $colspan++; }
+    print '<tr><td colspan="'.$colspan.'" class="opacitymedium">'.$langs->trans("NoRecordFound").'</td></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>'."\n";
+
+print '</form>'."\n";
+
+if ($nbtotalofrecords === '' || $nbtotalofrecords)
+{
+    if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files)
+    {
+        require_once(DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php');
+        $formfile = new FormFile($db);
+
+        // Show list of available documents
+        $urlsource=$_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
+        $urlsource.=str_replace('&amp;','&',$param);
+
+        $filedir=$diroutputmassaction;
+        $genallowed=$user->rights->inventory->read;
+        $delallowed=$user->rights->inventory->read;
 
-echo '</form>';
+        print $formfile->showdocuments('massfilesarea_inventory','',$filedir,$urlsource,0,$delallowed,'',1,1,0,48,1,$param,$title,'');
+    }
+    else
+    {
+        print '<br><a name="show_files"></a><a href="'.$_SERVER["PHP_SELF"].'?show_files=1'.$param.'#show_files">'.$langs->trans("ShowTempMassFilesArea").'</a>';
+    }
+}
 
-llxFooter('');
-$db->close();
\ No newline at end of file
+// End of page
+llxFooter();
+$db->close();
diff --git a/htdocs/product/inventory/listview.class.php b/htdocs/product/inventory/listview.class.php
deleted file mode 100644
index 3dddac44516..00000000000
--- a/htdocs/product/inventory/listview.class.php
+++ /dev/null
@@ -1,1083 +0,0 @@
-<?php
-/*
- EXPERIMENTAL
- 
- Copyright (C) 2016 ATM Consulting <support@atm-consulting.fr>
-
- This program and all files within this directory and sub directory
- 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 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/>.
- */
-
-/**
- *	Class to manage the lists view
- */
-class Listview
-{
-    /**
-     *  Constructor
-     *
-     *  @param      DoliDB		$db      Database handler
-     *  @param      string		$id      html id
-     */
-	function __construct(&$db, $id)
-    {
-		$this->db = &$db;
-		$this->id = $id;
-		$this->TTotalTmp=array();
-		$this->sql = '';
-		$this->form = null;
-		$this->totalRowToShow=0;
-		$this->totalRow=0;
-		
-		$this->TField=array();
-		
-		require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
-		$this->extrafields = new ExtraFields($this->db);
-		$this->extralabels = $this->extrafields->fetch_name_optionals_label('product');
-		$this->search_array_options=$this->extrafields->getOptionalsFromPost($this->extralabels,'','search_');
-	}
-
-    /**
-     * Function to init fields
-     *
-     * @param   array   $TParam     array of configuration of list
-     * @return bool
-     */
-	private function init(&$TParam)
-    {
-		global $conf, $langs, $user;
-		
-		if(!isset($TParam['hide'])) $TParam['hide']=array();
-		if(!isset($TParam['link'])) $TParam['link']=array();
-		if(!isset($TParam['type'])) $TParam['type']=array();
-		if(!isset($TParam['orderby']['noOrder'])) $TParam['orderby']['noOrder']=array();
-		if(!isset($TParam['allow-fields-select'])) $TParam['allow-fields-select'] = 0;
-		
-		if(!isset($TParam['list']))$TParam['list']=array();
-		$TParam['list'] = array_merge(array(
-			'messageNothing'=>$langs->trans('ListMessageNothingToShow')
-			,'noheader'=>0
-			,'useBottomPagination'=>0
-			,'image'=>''
-			,'title'=>$langs->trans('List')
-			,'orderDown'=>''
-			,'orderUp'=>''
-			,'id'=>$this->id
-			,'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;
-		
-		$TParam['limit'] = array_merge(array('page'=>0, 'nbLine' => $conf->liste_limit, 'global'=>0), $TParam['limit']);
-		
-		if (GETPOST('sortfield'))
-		{
-			$TParam['sortfield'] = GETPOST('sortfield');
-			$TParam['sortorder'] = GETPOST('sortorder');
-		}
-		
-		include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
-		$this->form = new Form($this->db);
-	}
-
-
-    /**
-     * Function to know if we can search on null value
-     * @param   string  $key    field name
-     * @param   array   $TParam array of configuration
-     * @return bool
-     */
-    private function getSearchNull($key, &$TParam)
-    {
-		return !empty($TParam['search'][$key]['allow_is_null']);
-	}
-
-    /**
-     * @param string    $key    field name
-     * @param string     $TParam array of configuration
-     * @return array
-     */
-	private function getSearchKey($key, &$TParam)
-    {
-		$TPrefixe = array();
-		if(!empty($TParam['search'][$key]['table']))
-		{
-			if (!is_array($TParam['search'][$key]['table'])) $TParam['search'][$key]['table'] = array($TParam['search'][$key]['table']);
-			
-			foreach ($TParam['search'][$key]['table'] as $prefix_table)
-			{
-				$TPrefixe[] = $prefix_table.'.'; 
-			}
-		}
-		
-		$TKey=array();
-		if(!empty($TParam['search'][$key]['field']))
-		{
-			if (!is_array($TParam['search'][$key]['field'])) $TParam['search'][$key]['field'] = array($TParam['search'][$key]['field']);
-			
-			foreach ($TParam['search'][$key]['field'] as $i => $field)
-			{
-				$prefixe = !empty($TPrefixe[$i]) ? $TPrefixe[$i] : $TPrefixe[0];
-				$TKey[] = $prefixe. $field ;
-			}
-		}
-		else
-		{
-			$TKey[] = $TPrefixe[0].$key;
-		}
-		
-		return $TKey;
-	}
-    /**
-     * @param string     $TSQLMore   contain some additional sql instructions
-     * @param string    $value      date with read format
-     * @param string    $sKey       field name
-     */
-    private function addSqlFromTypeDate(&$TSQLMore, &$value, $sKey)
-	{
-		if(is_array($value))
-		{
-			$TSQLDate=array();
-			if(!empty($value['start']))
-			{
-				$TSQLDate[]=$sKey." >= '".$value['start']."'" ;
-			}
-
-			if(!empty($value['end']))
-			{
-				$TSQLDate[]=$sKey." <= '".$value['end']."'" ;
-			}
-
-			if(!empty($TSQLDate)) $TSQLMore[] = implode(' AND ', $TSQLDate);
-		}
-		else
-		{
-			$TSQLMore[]=$sKey." LIKE '".$value."%'" ;
-		}
-	}
-
-
-    /**
-     * @param string     $TSQLMore   contain some additional sql instructions
-     * @param string    $value      value to filter
-     * @param string     $TParam     array of configuration
-     * @param string    $sKey       field name
-     * @param string    $key        reference of sKey to find value into TParam
-     * @return bool
-     */
-    private function addSqlFromOther(&$TSQLMore, &$value, &$TParam, $sKey, $key)
-	{
-		// Do not use empty() function, statut 0 exist
-		if ($value == '') return false;
-		elseif($value==-1) return false;
-			
-		if(isset($TParam['operator'][$key]))
-		{
-			if($TParam['operator'][$key] == '<' || $TParam['operator'][$key] == '>' || $TParam['operator'][$key]=='=')
-			{
-				$TSQLMore[] = $sKey . ' ' . $TParam['operator'][$key] . ' "' . $value . '"';
-			}
-			elseif ($TParam['operator'][$key]=='IN')
-			{
-				$TSQLMore[] = $sKey . ' ' . $TParam['operator'][$key] . ' (' . $value . ')';
-			}
-			else
-			{
-				if(strpos($value,'%')===false) $value = '%'.$value.'%';
-				$TSQLMore[]=$sKey." LIKE '".addslashes($value)."'" ;
-			}
-		}
-		else
-		{
-            if(strpos($value,'%')===false) $value = '%'.$value.'%';
-            $TSQLMore[]=$sKey." LIKE '".addslashes($value)."'" ;
-		}
-		
-		return true;
-	}
-
-
-    /**
-     * @param string    $sql    standard select sql
-     * @param string     $TParam array of configuration
-     * @return string
-     */
-    private function search($sql, &$TParam)
-    {
-		if (empty($TParam['no-auto-sql-search']) && !GETPOST('button_removefilter_x','alpha') && !GETPOST('button_removefilter.x','alpha') && !GETPOST('button_removefilter','alpha'))
-		{
-			foreach ($TParam['search'] as $field => $info)
-			{
-				$TsKey = $this->getSearchKey($field, $TParam);
-				$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 = GETPOST($fieldname);
-					$value_null = GETPOST('Listview_'.$this->id.'_search_on_null_'.$field);
-					
-					if ($allow_is_null && !empty($value_null))
-					{
-						$TSQLMore[] = $sKey.' IS NULL ';
-						$value = '';
-					}
-					
-					if (isset($TParam['type'][$field]) && ($TParam['type'][$field]==='date' || $TParam['type'][$field]==='datetime'))
-					{
-						$k = $fieldname;
-						if ($info['search_type'] === 'calendars')
-						{
-							$value = array();
-							
-							$timestart = dol_mktime(0, 0, 0, GETPOST($k.'_startmonth'), GETPOST($k.'_startday'), GETPOST($k.'_startyear'));
-							if ($timestart) $value['start'] = date('Y-m-d', $timestart);
-							
-							$timeend = dol_mktime(23, 59, 59, GETPOST($k.'_endmonth'), GETPOST($k.'_endday'), GETPOST($k.'_endyear'));
-							if ($timeend) $value['end'] = date('Y-m-d', $timeend);
-						}
-						else
-						{
-							$time = dol_mktime(12, 0, 0, GETPOST($k.'month'), GETPOST($k.'day'), GETPOST($k.'year'));
-							if ($time) $value = date('Y-m-d', $time);
-						}
-						
-						if (!empty($value)) $this->addSqlFromTypeDate($TSQLMore, $value, $sKey);
-					}
-					else
-					{
-						$this->addSqlFromOther($TSQLMore, $value, $TParam, $sKey, $field);
-					}
-				}
-				
-				if (!empty($TSQLMore))
-				{
-					$sql.=' AND ( '.implode(' OR ',$TSQLMore).' ) ';
-				}
-			}
-		}
-		
-		if ($sqlGROUPBY!='') $sql.=' GROUP BY '.$sqlGROUPBY;
-
-		return $sql;
-	}
-
-    /**
-     * @param string    $sql    standard select sql
-     * @param string     $TParam array of configuration
-     * @return string
-     */
-    public function render($sql, $TParam=array())
-    {
-        global $conf;
-        
-        $TField= & $this->TField;
-		
-		$this->init($TParam);
-
-        $THeader = $this->initHeader($TParam);
-		
-		$sql = $this->search($sql,$TParam);
-		$sql.= $this->db->order($TParam['sortfield'], $TParam['sortorder']);
-	
-		if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
-		{
-		    $result = $this->db->query($sql);
-		    $this->totalRow = $this->db->num_rows($result);
-		}
-		
-		$this->parse_sql($THeader, $TField, $TParam, $sql);
-		list($TTotal, $TTotalGroup)=$this->get_total($TField, $TParam);
-		
-		return $this->renderList($THeader, $TField, $TTotal, $TTotalGroup, $TParam);
-	}
-
-    /**
-     * @param string     $THeader    the configuration of header
-     * @param string     $TParam     array of configuration
-     * @return array
-     */
-    private function setSearch(&$THeader, &$TParam)
-    {
-		global $langs, $form;
-		
-		if(empty($TParam['search'])) return array();
-		
-		$TSearch=array();
-		
-		$nb_search_in_bar = 0;
-		
-		foreach($THeader as $key => $libelle)
-		{
-			if(empty($TSearch[$key]))$TSearch[$key]='';
-		}
-		
-		$removeFilter = (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') || GETPOST('button_removefilter','alpha'));
-		foreach($TParam['search'] as $key => $param_search)
-		{
-			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($fieldname, $typeRecherche,$value,1);
-			}
-			else if($typeRecherche==='calendar')
-			{
-				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, $fieldname,0, 0, 1, "", 1, 0, 1);
-			}
-			else if($typeRecherche==='calendars')
-			{
-				$value_start = $value_end = '';
-				if (!$removeFilter)
-				{
-					$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,$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))
-			{
-				$fsearch=$TParam['search'][$key];	
-			}
-			else
-            {
-            	$fsearch='<input type="text" name="'.$fieldname.'" id="'.$fieldname.'" value="'.$value.'" size="10" />';
-			}
-
-			if(!empty($param_search['allow_is_null']))
-			{
-				$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]))
-			{
-				$TSearch[$key] = $fsearch;
-				$nb_search_in_bar++;
-			}
-		}
-		
-		$search_button = ' <a href="#" onclick="Listview_submitSearch(this);" class="list-search-link">'.img_search().'</a>';
-		$search_button .= ' <a href="#" onclick="Listview_clearSearch(this);" class="list-search-link">'.img_searchclear().'</a>';
-		
-		if($nb_search_in_bar>0)
-		{
-			end($TSearch);
-			list($key,$v) = each($TSearch);
-			$TSearch[$key].=$search_button;
-		}
-		else
-        {
-			$TSearch=array();
-		}
-		
-		return $TSearch;
-	}
-
-    /**
-     * Function to analyse and calculate the total from a column
-     *
-     * @param string $TField    TField
-     * @param string $TParam    TParam
-     * @return array
-     */
-    private function get_total(&$TField, &$TParam)
-    {
-		$TTotal=$TTotalGroup=array();	
-		
-		if(!empty($TParam['math']) && !empty($TField[0]))
-		{
-			foreach($TField[0] as $field=>$value)
-			{
-				$TTotal[$field]='';	
-				$TTotalGroup[$field] = '';
-			}
-		
-			foreach($TParam['math'] as $field=>$typeMath)
-			{
-				if(is_array($typeMath))
-				{
-					$targetField = $typeMath[1];
-					$typeMath = $typeMath[0];
-				}
-				else
-                {
-					$targetField = $field;
-				}
-
-				if($typeMath == 'groupsum')
-				{
-					$TTotalGroup[$field] = array('target'=>$targetField, 'values'=> $this->TTotalTmp['@groupsum'][$targetField]);
-				}
-				else if($typeMath=='average')
-				{
-					$TTotal[$field]=array_sum($this->TTotalTmp[$targetField]) / count($this->TTotalTmp[$targetField]);
-				}
-				elseif($typeMath=='count')
-                {
-					$TTotal[$field]=count($this->TTotalTmp[$targetField]);
-				}
-				else
-                {
-					$TTotal[$field]=array_sum($this->TTotalTmp[$targetField]);
-				}
-			}
-		}
-		
-		return array($TTotal,$TTotalGroup);
-	}
-
-    /**
-     * @return string
-     */
-	/*
-    private function getJS()
-    {
-		$javaScript = '<script language="javascript">
-		if(typeof(Listview_include)=="undefined") {
-			document.write("<script type=\"text/javascript\" src=\"'.DOL_URL_ROOT.'/core/js/listview.js?version='.DOL_VERSION.'\"></scr");
-	  		document.write("ipt>");
-		}
-		</script>';
-
-		return $javaScript;
-	}
-    */
-	
-    /**
-     * @param string $TParam    TParam
-     * @param string $TField    TField
-     * @param string $THeader   THeader
-     * @return array
-     */
-    private function setExport(&$TParam, $TField, $THeader)
-    {
-		global $langs;
-		
-		$Tab=array();
-		if(!empty($TParam['export']))
-		{
-			$token = GETPOST('token');
-			if(empty($token)) $token = md5($this->id.time().rand(1,9999));
-
-            $_SESSION['token_list_'.$token] = gzdeflate( serialize( array(
-                'title'=>$this->title,
-                'sql'=>$this->sql,
-                'TBind'=>$this->TBind,
-                'TChamps'=>$TField,
-                'TEntete'=>$THeader
-            )));
-
-            foreach($TParam['export'] as $mode_export)
-            {
-                $Tab[] = array(
-                    'label'=>$langs->trans('Export'.$mode_export),
-                    'url'=>dol_buildpath('/abricot/downlist.php',1),
-                    'mode'=>$mode_export,
-                    'token'=>$token,
-                    'session_name'=>session_name()
-                );
-			}
-			
-		}
-		
-		return $Tab;
-	}
-
-    /**
-     * @param string $TField        TField
-     * @param string $TTotalGroup   TTotalGroup
-     * @return array
-     */
-    private function addTotalGroup($TField, $TTotalGroup)
-    {
-		global $langs;
-		
-		$Tab=array();
-		$proto_total_line = array();
-		$tagbase = $old_tagbase = null;
-		$addGroupLine = false;
-		
-		foreach($TField as $k=>&$line)
-		{
-			if(empty($proto_total_line))
-			{
-				foreach($line as $field=>$value)
-				{
-					$proto_total_line[$field] = '';
-				}
-				$group_line = $proto_total_line;	
-			}
-			
-			$addGroupLine = false;
-			
-			$tagbase = '';
-			foreach($line as $field=>$value)
-			{
-				if(!empty($TTotalGroup[$field]))
-				{
-					$tagbase.=$value.'|';
-					$group_line[$field] = '<div style="text-align:right; font-weight:bold; color:#552266;">'.(empty($value) ? $langs->trans('Empty') : $value ).' : </div>';
-					$group_line[$TTotalGroup[$field]['target']] = '<div style="text-align:right; font-weight:bold; color:#552266;">'.price($TTotalGroup[$field]['values'][$value]).'</div>';
-					$addGroupLine = true;
-				}
-			}
-			
-			if(!is_null($old_tagbase) && $old_tagbase!=$tagbase && $addGroupLine)
-			{
-				$Tab[] = $previous_group_line;
-			}
-			
-			$old_tagbase = $tagbase;
-			$previous_group_line = $group_line;
-			$group_line = $proto_total_line;
-			
-			$Tab[] = $line;
-		}
-
-		if($addGroupLine)
-		{
-			$Tab[] = $previous_group_line;
-		}
-		
-		return $Tab;
-	}
-
-    /**
-     * @param string $THeader   THeader
-     * @param string $TField    TField
-     * @param string $TTotal    TTotal
-     * @param string $TTotalGroup   TTotalGroup
-     * @param string $TParam        TParam
-     * @return string
-     */
-    private function renderList(&$THeader, &$TField, &$TTotal, &$TTotalGroup, &$TParam)
-    {
-		global $bc,$form;
-		
-		$TSearch = $this->setSearch($THeader, $TParam);
-		$TExport = $this->setExport($TParam, $TField, $THeader);
-		$TField = $this->addTotalGroup($TField,$TTotalGroup);
-		
-		//$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'], $_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.= '<div class="div-table-responsive">';
-		$out.= '<table id="'.$this->id.'" class="'.$classliste.'" width="100%"><thead>';
-			
-    	if(count($TSearch)>0)
-		{
-			$out.='<tr class="liste_titre liste_titre_search barre-recherche">';
-			
-			foreach ($THeader as $field => $head)
-			{
-				if ($field === 'selectedfields')
-				{
-					$out.= '<th class="liste_titre" align="right">'.$this->form->showFilterAndCheckAddButtons(0).'</th>';
-				}
-				else
-				{
-					$moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"';
-					$out .= '<th class="liste_titre" '.$moreattrib.'>'.$TSearch[$field].'</th>';
-				}
-			}
-			
-			$out.='</tr>';
-		}
-				
-		$out.= '<tr class="liste_titre">';
-		foreach($THeader as $field => $head)
-		{
-			$moreattrib = '';
-			$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';
-			if (!empty($head['width']) && !empty($head['text-align'])) $moreattrib .= 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"';
-
-			if (isset($TParam['search'][$field]['search_type']) && $TParam['search'][$field]['search_type'] !== false)
-			{
-				$TsKey = $this->getSearchKey($field, $TParam);
-				if (!empty($TsKey)) $search = implode(',', $TsKey);
-				else $search = $field;
-			}
-
-			$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>';
-		
-		$out.='</thead><tbody>';
-		
-		if(empty($TField))
-		{
-			if (!empty($TParam['list']['messageNothing'])) $out .= '<tr class="oddeven"><td colspan="'.(count($THeader)+1).'"><span class="opacitymedium">'.$TParam['list']['messageNothing'].'</span></td></tr>';
-		}
-		else
-        {
-			$line_number = 0;
-			foreach($TField as $fields)
-			{
-				if($this->in_view($TParam, $line_number))
-				{
-					$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.'>'.$value_aff.'</td>';
-					}
-
-					$out.='</tr>';
-				}
-				
-				$line_number++;
-			}
-			
-			$out.='</tbody>';
-			
-			if (!empty($TParam['list']['haveTotal']))
-			{
-				$out.='<tfoot><tr class="liste_total">';
-			
-				foreach ($THeader as $field => $head)
-				{
-					if (isset($TTotal[$field]))
-					{
-						$moreattrib = 'style="width:'.$head['width'].';text-align:'.$head['text-align'].'"';
-						$out.='<td align="right" class="'.$field.'" '.$moreattrib.'>'.price($TTotal[$field]).'</td>';
-					}
-				}
-					
-				$out.='</tr></tfoot>';
-			}
-		}
-
-		$out .= '</table>';
-		$out .= '</div>';
-		
-		return $out;
-	}
-
-    /**
-     * @param string $db        Db
-     * @param string $TField    TField
-     * @param string $TParam    TParam
-     */
-    public function renderArray(&$db, $TField, $TParam=array())
-    {
-		$this->typeRender = 'array';
-
-		$TField=array();	
-		
-		$this->init($TParam);
-		$THeader = $this->initHeader($TParam);
-		
-		$this->parse_array($THeader, $TField, $TParam);
-		list($TTotal, $TTotalGroup)=$this->get_total($TField, $TParam);
-		
-		$this->renderList($THeader, $TField, $TTotal, $TTotalGroup, $TParam);
-	}
-
-
-    /**
-     * @param string $THeader   THeader
-     * @param string $TField    TField
-     * @param string $TParam    TParam
-     * @return bool
-     */
-    private function parse_array(&$THeader, &$TField, &$TParam)
-    {
-		$this->totalRow = count($TField);
-		
-		$this->THideFlip = array_flip($TParam['hide']);
-		$this->TTotalTmp=array();
-		
-		if (empty($TField)) return false;
-		
-		foreach($TField as $row)
-		{
-			$this->set_line($THeader, $TField, $TParam, $row);
-		}
-	}
-
-	
-	private function initHeader(&$TParam)
-	{
-		global $user,$conf;
-		
-		$THeader = array();
-		
-		$TField=$TFieldVisibility=array();
-		foreach ($TParam['title'] as $field => $value)
-		{
-			$TField[$field]=true;
-		}
-		
-		$contextpage=md5($_SERVER['PHP_SELF']);
-		if(!empty($TParam['allow-fields-select']))
-		{
-			$selectedfields = GETPOST('Listview'.$this->id.'_selectedfields');
-			
-			if(!empty($selectedfields))
-			{
-				include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
-				$tabparam['MAIN_SELECTEDFIELDS_'.$contextpage] = $selectedfields;
-	    		$result=dol_set_user_param($this->db, $conf, $user, $tabparam);
-			}
-			
-			$tmpvar='MAIN_SELECTEDFIELDS_'.$contextpage;
-			if (! empty($user->conf->{$tmpvar}))
-			{
-				$tmparray = explode(',', $user->conf->{$tmpvar});
-				$TParam['hide'] = array();
-		        foreach($TField as $field => $dummy)
-		        {
-		          	$label = $TParam['title'][$field];
-					if(!in_array($field, $tmparray))
-					{
-				  		$TParam['hide'][] = $field;
-						$visible = 0;
-				  	}
-					else
-					{
-						// Overrive search from extrafields
-						// for the type as 'checkbox', 'chkbxlst', 'sellist' we should use code instead of id (example: I declare a 'chkbxlst' to have a link with dictionnairy, I have to extend it with the 'code' instead 'rowid')
-						if (isset($this->extralabels[$field])) $TParam['search'][$field] = $this->extrafields->showInputField($field, $this->search_array_options['search_options_'.$field], '', '', 'search_');
-						$visible = 1;
-					}
-		            
-					$TFieldVisibility[$field] = array(
-						'label'=>$label
-						,'checked'=>$visible
-					);
-		        }
-			}
-			else
-            {
-				foreach($TField as $field=>$dummy)
-		        {
-		        	$label = isset($TParam['title'][$field]) ? $TParam['title'][$field] : $field;
-					$visible = (!in_array($field, $TParam['hide'])) ? 1 : 0;
-					$TFieldVisibility[$field]=array(
-						'label'=>$label,
-						'checked'=>$visible
-					);
-				}
-			}	
-
-			$selectedfields = $this->form->multiSelectArrayWithCheckbox('Listview'.$this->id.'_selectedfields', $TFieldVisibility, $contextpage);	// This also change content of $arrayfields_0
-		}
-
-		foreach ($TParam['title'] as $field => $label)
-		{
-			$visible = (!in_array($field, $TParam['hide'])) ? 1 : 0;
-			if($visible)
-			{
-				$THeader[$field] = array(
-					'label'=>$label,
-					'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'=>''
-				);
-			}
-		}
-		
-		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
-     * @param string $line_number   aaa
-     * @return bool
-     */
-    private function in_view(&$TParam, $line_number)
-    {
-		global $conf;
-
-		if(!empty($_REQUEST['get-all-for-export'])) return true;
-
-		$page_number = !empty($TParam['limit']['page']) ? $TParam['limit']['page'] : 1;
-		$line_per_page = !empty($TParam['limit']['nbLine']) ? $TParam['limit']['nbLine'] : $conf->liste_limit;
-		
-		$start = ($page_number-1) * $line_per_page;
-		$end = ($page_number* $line_per_page) -1;
-		
-		if($line_number>=$start && $line_number<=$end) return true;
-		else return false;
-	}
-
-    /**
-     * 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(&$THeader, &$TField, &$TParam, $currentLine)
-    {
-        global $conf;
-
-        $line_number = count($TField);
-
-        if($this->in_view($TParam,$line_number))
-        {
-			$this->totalRowToShow++;
-            $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.'@'] = addslashes($value);
-
-                if(!empty($TParam['math'][$field]))
-                {
-                    $float_value = (double) strip_tags($value);
-                    $this->TTotalTmp[$field][] = $float_value;
-                }
-
-                if(!in_array($field,$TParam['hide']))
-                {
-                    $row[$field]=$value;
-
-                    if(isset($TParam['eval'][$field]) && in_array($field,array_keys($row)))
-                    {
-                        $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]),'dayhour');
-                                else $row[$field] = dol_print_date(strtotime($row[$field]),'day');
-                            }
-                            else
-                            {
-                                $row[$field] = '';
-                            }
-                        }
-
-                        if($TParam['type'][$field]=='hour') { $row[$field] = date('H:i', strtotime($row[$field])); }
-                        if($TParam['type'][$field]=='money') { $row[$field] = '<div align="right">'.price($row[$field],0,'',1,-1,2).'</div>'; }
-                        if($TParam['type'][$field]=='number') { $row[$field] = '<div align="right">'.price($row[$field]).'</div>'; }
-                        if($TParam['type'][$field]=='integer') { $row[$field] = '<div align="right">'.((int) $row[$field]).'</div>'; }
-                    }
-
-                    if(isset($TParam['link'][$field]))
-                    {
-                        if(empty($row[$field]) && $row[$field]!==0 && $row[$field]!=='0')$row[$field]='(vide)';
-                        $row[$field]= strtr( $TParam['link'][$field],  array_merge( $trans, array('@val@'=>$row[$field]))) ;
-                    }
-
-                    if(isset($TParam['translate'][$field]))
-                    {
-                        if(isset($TParam['translate'][$field][''])) unset($TParam['translate'][$field]['']);
-
-                        $row[$field] = strtr( $row[$field], $TParam['translate'][$field]);
-                    }
-                }
-            }
-        }
-        else
-        {
-            $row = array();
-
-            foreach($currentLine as $field=>&$value)
-            {
-                if(!isset($this->THideFlip[$field]))
-                {
-                    if(isset($TParam['math'][$field]) && !empty($TParam['math'][$field]))
-                    {
-                        $float_value = (double) strip_tags($value);
-                        $this->TTotalTmp[$field][] = $float_value;
-                    }
-
-                    $row[$field] = $value;
-                }
-            }
-        }
-
-        if(!empty($TParam['math'][$field]))
-        {
-            foreach($row as $field=>$value)
-            {
-                if(!empty($TParam['math'][$field]) && is_array($TParam['math'][$field]))
-                {
-                    $toField = $TParam['math'][$field][1];
-                    $float_value = (double) strip_tags($row[$toField]);
-                    $this->TTotalTmp['@groupsum'][$toField][ $row[$field]  ] += $float_value;
-                }
-            }
-        }
-
-        $TField[] = $row;
-	}
-
-    /**
-     * @param string $sql       sql
-     * @param string $TParam    TParam
-     * @return string
-     */
-    private function limitSQL($sql, &$TParam)
-    {
-		if(!empty($TParam['limit']['global']) && strpos($sql,'LIMIT ')===false )
-		{
-			$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;
-	}
-
-    /**
-     * @param string $THeader   THeader
-     * @param string $TField    TField
-     * @param string $TParam    TParam
-     * @param string $sql       sql
-     */
-    private function parse_sql(&$THeader, &$TField, &$TParam, $sql)
-    {
-    	$this->sql = $this->limitSQL($sql, $TParam);
-		
-		$this->TTotalTmp=array();
-		$this->THideFlip = array_flip($TParam['hide']);
-		
-		$res = $this->db->query($this->sql);
-		if($res!==false)
-		{
-			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($THeader, $TField, $TParam, $currentLine);
-			}
-		}
-		else
-        {
-			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];
-	}
-	
-}
-- 
GitLab