소스 검색

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

Alexandre SPANGARO 8 년 전
부모
커밋
e89c4e9f41
100개의 변경된 파일1831개의 추가작업 그리고 1385개의 파일을 삭제
  1. 6 131
      COPYRIGHT
  2. 1 1
      htdocs/adherents/card.php
  3. 1 1
      htdocs/adherents/subscription.php
  4. 1 1
      htdocs/api/admin/index.php
  5. 2 1
      htdocs/api/class/api.class.php
  6. 26 11
      htdocs/api/class/api_documents.class.php
  7. 4 2
      htdocs/categories/class/api_categories.class.php
  8. 4 2
      htdocs/categories/class/api_deprecated_category.class.php
  9. 18 8
      htdocs/categories/class/categorie.class.php
  10. 2 1
      htdocs/comm/action/class/api_agendaevents.class.php
  11. 1 1
      htdocs/comm/card.php
  12. 2 1
      htdocs/comm/propal/class/api_proposals.class.php
  13. 2 1
      htdocs/commande/class/api_deprecated_commande.class.php
  14. 2 1
      htdocs/commande/class/api_orders.class.php
  15. 2 1
      htdocs/compta/bank/class/api_bankaccounts.class.php
  16. 2 1
      htdocs/compta/facture/class/api_deprecated_invoice.class.php
  17. 2 1
      htdocs/compta/facture/class/api_invoices.class.php
  18. 1 1
      htdocs/contact/agenda.php
  19. 1 1
      htdocs/contact/card.php
  20. 1 1
      htdocs/contact/document.php
  21. 1 1
      htdocs/contact/info.php
  22. 1 1
      htdocs/contact/ldap.php
  23. 75 34
      htdocs/contact/list.php
  24. 1 49
      htdocs/contact/note.php
  25. 1 1
      htdocs/contact/perso.php
  26. 34 33
      htdocs/contrat/card.php
  27. 58 50
      htdocs/core/actions_extrafields.inc.php
  28. 69 28
      htdocs/core/class/extrafields.class.php
  29. 1 1
      htdocs/core/class/html.form.class.php
  30. 4 1
      htdocs/core/class/html.formactions.class.php
  31. 3 3
      htdocs/core/lib/ajax.lib.php
  32. 10 0
      htdocs/core/lib/files.lib.php
  33. 19 6
      htdocs/core/lib/functions.lib.php
  34. 52 15
      htdocs/core/tpl/admin_extrafields_add.tpl.php
  35. 52 7
      htdocs/core/tpl/admin_extrafields_edit.tpl.php
  36. 5 1
      htdocs/core/tpl/admin_extrafields_view.tpl.php
  37. 2 1
      htdocs/expensereport/class/api_expensereports.class.php
  38. 1 1
      htdocs/fourn/card.php
  39. 2 1
      htdocs/fourn/class/api_supplier_invoices.class.php
  40. 12 31
      htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css
  41. BIN
      htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png
  42. BIN
      htdocs/includes/restler/framework/Luracast/Restler/explorer/images/pet_store_api.png
  43. BIN
      htdocs/includes/restler/framework/Luracast/Restler/explorer/images/wordnik_api.png
  44. 25 9
      htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html
  45. 54 61
      htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/swagger-oauth.js
  46. 269 154
      htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/swagger.js
  47. 190 141
      htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.js
  48. 0 0
      htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.min.js
  49. 3 3
      htdocs/install/default.css
  50. 23 1
      htdocs/install/mysql/migration/5.0.0-6.0.0.sql
  51. 4 2
      htdocs/install/mysql/tables/llx_extrafields.sql
  52. 1 1
      htdocs/install/mysql/tables/llx_opensurvey_sondage.sql
  53. 4 4
      htdocs/install/step5.php
  54. 7 5
      htdocs/langs/en_US/admin.lang
  55. 2 1
      htdocs/langs/en_US/main.lang
  56. 14 14
      htdocs/langs/en_US/other.lang
  57. 1 1
      htdocs/langs/en_US/stocks.lang
  58. 1 2
      htdocs/main.inc.php
  59. 12 8
      htdocs/modulebuilder/skeletons/skeleton_list.php
  60. 15 18
      htdocs/opensurvey/card.php
  61. 13 12
      htdocs/opensurvey/class/opensurveysondage.class.php
  62. 17 16
      htdocs/opensurvey/results.php
  63. 2 2
      htdocs/product/ajax/products.php
  64. 2 1
      htdocs/product/card.php
  65. 4 2
      htdocs/product/class/api_deprecated_product.class.php
  66. 2 1
      htdocs/product/class/api_products.class.php
  67. 41 16
      htdocs/product/class/product.class.php
  68. 41 42
      htdocs/product/composition/card.php
  69. 44 24
      htdocs/product/list.php
  70. 319 282
      htdocs/product/stats/card.php
  71. 1 1
      htdocs/product/stats/commande.php
  72. 1 1
      htdocs/product/stats/commande_fournisseur.php
  73. 1 1
      htdocs/product/stats/contrat.php
  74. 1 1
      htdocs/product/stats/facture.php
  75. 1 1
      htdocs/product/stats/facture_fournisseur.php
  76. 1 1
      htdocs/product/stats/propal.php
  77. 2 1
      htdocs/product/stock/class/api_stockmovements.class.php
  78. 2 1
      htdocs/product/stock/class/api_warehouses.class.php
  79. 1 1
      htdocs/projet/admin/project.php
  80. 1 1
      htdocs/projet/admin/project_extrafields.php
  81. 1 1
      htdocs/projet/admin/project_task_extrafields.php
  82. 2 1
      htdocs/projet/class/api_projects.class.php
  83. 2 1
      htdocs/projet/class/api_tasks.class.php
  84. 25 25
      htdocs/projet/list.php
  85. 20 17
      htdocs/projet/tasks/list.php
  86. 2 2
      htdocs/projet/tasks/time.php
  87. 3 0
      htdocs/public/opensurvey/studs.php
  88. 28 11
      htdocs/resource/card.php
  89. 39 12
      htdocs/resource/class/dolresource.class.php
  90. 21 12
      htdocs/resource/contact.php
  91. 18 10
      htdocs/resource/document.php
  92. 21 10
      htdocs/resource/note.php
  93. 5 3
      htdocs/societe/card.php
  94. 2 1
      htdocs/societe/class/api_contacts.class.php
  95. 2 1
      htdocs/societe/class/api_deprecated_contact.class.php
  96. 2 1
      htdocs/societe/class/api_deprecated_thirdparty.class.php
  97. 22 2
      htdocs/societe/class/api_thirdparties.class.php
  98. 0 2
      htdocs/societe/class/societe.class.php
  99. 9 5
      htdocs/societe/list.php
  100. 1 1
      htdocs/theme/eldy/style.css.php

+ 6 - 131
COPYRIGHT

@@ -21,13 +21,13 @@ GeoIP                  1.4           LGPL-2.1+                   Yes
 Mobiledetect           2.8.17        MIT License                 Yes             Detect mobile devices browsers
 NuSoap                 0.9.5         LGPL 2.1+                   Yes             Library to develop SOAP Web services (not into rpm and deb package)
 PEAR Mail_MIME         1.8.9         BSD                         Yes             NuSoap dependency
-odtPHP                 1.0.1         GPL-2+  b                   Yes             Library to build/edit ODT files
+odtPHP                 1.0.1         GPL-2+                      Yes             Library to build/edit ODT files
 ParseDown              1.6           MIT License                 Yes             Markdown parser
 PHPExcel               1.8.1         LGPL-2.1+                   Yes             Read/Write XLS files, read ODS files
 php-iban               1.4.7         LGPL-3+                     Yes             Parse and validate IBAN (and IIBAN) bank account information in PHP
 PHPoAuthLib            0.8.2         MIT License                 Yes             Library to provide oauth1 and oauth2 to different service
 PHPPrintIPP            1.3           GPL-2+                      Yes             Library to send print IPP requests
-Restler                3.0.0RC6      LGPL-3+                     Yes             Library to develop REST Web services
+Restler                3.0.0RC6      LGPL-3+                     Yes             Library to develop REST Web services (+ swagger-ui js lib into dir explorer)
 TCPDF                  6.2.12        LGPL-3+                     Yes             PDF generation
 TCPDI                  1.0.0         LGPL-3+ / Apache 2.0        Yes             FPDI replacement
 Swift Mailer           5.4.2-DEV     MIT license                 Yes             Comprehensive mailing tools for PHP
@@ -52,138 +52,13 @@ jQuery Timepicker      1.1.0         GPL and MIT License         Yes
 jQuery Tiptip          1.3           GPL and MIT License         Yes             JS library for tooltips
 jsGanttImproved        1.7.5.2       BSD License                 Yes             JS library (to build Gantt reports)
 JsTimezoneDetect       1.0.6         MIT License                 Yes             JS library to detect user timezone
+SwaggerUI			   2.0.24		 GPL-2+                      Yes             JS library to offer the REST API explorer
 
 For licenses compatibility informations:
 http://www.gnu.org/licenses/licenses.en.html
 
 
-Copyright
----------
-
-Copyright (C) 2016
-
-Copyright (C) 2015
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Marcos García <marcosgdf@gmail.com>
-- Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
-- Frederic France <frederic.france@free.fr>
-- Regis Houssin <regis.houssin@capnetworks.com>
-
-Copyright (C) 2014
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
-- Jean-François Ferry <jfefe@aternatik.fr>
-- Marcos García <marcosgdf@gmail.com>
-- Philippe Grand <philippe.grand@atoo-net.com>
-- Florian Henry <florian.henry@open-concept.pro>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Maxime Kohlhaas <mko@atm-consulting.fr>
-- Juanjo Menent <jmenent@2byte.es>
-- Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
-- Frederic France <frederic.france@free.fr>
-
-Copyright (C) 2013
-- Christophe Battarel <christophe.battarel@altairis.fr>
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Jean-François Ferry <jfefe@aternatik.fr>
-- Marcos García <marcosgdf@gmail.com>
-- Philippe Grand <philippe.grand@atoo-net.com>
-- Florian Henry <florian.henry@open-concept.pro>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Maxime Kohlhaas <mko@atm-consulting.fr>
-- Juanjo Menent <jmenent@2byte.es>
-- Adolfo Segura <adolfo.segura@gmail.com>
-- Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
-
-Copyright (C) 2012
-- Christophe Battarel <christophe.battarel@altairis.fr>
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Jean-François Ferry <jfefe@aternatik.fr>
-- Marcos García <marcosgdf@gmail.com>
-- Philippe Grand <philippe.grand@atoo-net.com>
-- Jean Heimburger <jean@tiaris.info>
-- Florian Henry <florian.henry@open-concept.pro>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Maxime Kohlhaas <mko@atm-consulting.fr>
-- Juanjo Menent <jmenent@2byte.es>
-- Nicolas Péré <nicolas@amarok2.net>
-- Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
-
-Copyright (C) 2011
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Juanjo Menent <jmenent@2byte.es>
-- Philippe Grand <philippe.grand@atoo-net.com>
-- Jean Heimburger <jean@tiaris.info>
-
-Copyright (C) 2010
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Juanjo Menent <jmenent@2byte.es>
-- r2gnl
-- meos
-
-Copyright (C) 2009
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Juanjo Menent <jmenent@2byte.es>
-
-Copyright (C) 2008
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Jeremie Ollivier <jeremie.o@laposte.net>
-
-Copyright (C) 2007
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Auguria SARL <info@auguria.org>
-- Jean Heimburger <jean@tiaris.info>
-- Jeremie Ollivier <jeremie.o@laposte.net>
-
-Copyright (C) 2006
-- Auguria SARL <info@auguria.org>
-- Marc Barilley/Ocebo <marc@ocebo.com>
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Regis Houssin <regis.houssin@capnetworks.com>
-- Andre Cianfarani <acianfa@free.fr>
-- Yannick Warnier <ywarnier@beeznest.org>
-- Jean Heimburger <jean@tiaris.info>
-
-Copyright (C) 2005
-- Brice Davoleau <brice.davoleau@gmail.com>
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Benoit Mortier <benoit.mortier@opensides.be>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Eric Seigne <erics@rycks.com>
-- Matthieu Valleton <mv@seeschloss.org>
-- Regis Houssin <regis.houssin@capnetworks.com>
-
-Copyright (C) 2004
-- Laurent Destailleur <eldy@users.sourceforge.net>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Eric Seigne <erics@rycks.com>
-- Benoit Mortier <benoit.mortier@opensides.be>
-- Christophe Combelles <ccomb@free.fr>
-- Sebastien Di Cintio <sdicintio@ressource-toi.org>
-
-Copyright (C) 2003
-- Jean-Louis Bergamo <jlb@j1b.org>
-- Xavier Dutoit <doli@sydesy.com>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-- Emmanuel Raviart <eraviart@entrouvert.com>
-- Eric Seigne <erics@rycks.com>
-
-Copyright (C) 2002
-- Jean-Louis Bergamo <jlb@j1b.org>
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-
-Copyright (C) 2001
-- Rodolphe Quiedeville <rodolphe@quiedeville.org>
-
-
-
-
+Copyright / Authors
+-------------------
 
+See page https://github.com/Dolibarr/dolibarr/graphs/contributors

+ 1 - 1
htdocs/adherents/card.php

@@ -1273,7 +1273,7 @@ else
 		 */
 		$head = member_prepare_head($object);
 
-		dol_fiche_head($head, 'general', $langs->trans("Member"), 0, 'user');
+		dol_fiche_head($head, 'general', $langs->trans("Member"), -1, 'user');
 
 		// Confirm create user
 		if ($action == 'create_user')

+ 1 - 1
htdocs/adherents/subscription.php

@@ -578,7 +578,7 @@ if ($rowid > 0)
     print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
     print '<input type="hidden" name="rowid" value="'.$object->id.'">';
 
-    dol_fiche_head($head, 'subscription', $langs->trans("Member"), 0, 'user');
+    dol_fiche_head($head, 'subscription', $langs->trans("Member"), -1, 'user');
 
     $linkback = '<a href="'.DOL_URL_ROOT.'/adherents/list.php">'.$langs->trans("BackToList").'</a>';
     

+ 1 - 1
htdocs/api/admin/index.php

@@ -111,7 +111,7 @@ $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain
 
 // Show message
 $message='';
-$url='<a href="'.$urlwithroot.'/api/index.php/login?login='.urlencode($user->login).'&password=yourpassword" target="_blank">'.$urlwithroot.'/api/index.php/login?login='.urlencode($user->login).'&password=yourpassword[&reset=1]</a>';
+$url=$urlwithroot.'/api/index.php/login?login=<strong>auserlogin</strong>&userpassword=<strong>thepassword</strong>[&reset=1]';
 $message.=$langs->trans("UrlToGetKeyToUseAPIs").':<br>';
 $message.=img_picto('','object_globe.png').' '.$url;
 print $message;

+ 2 - 1
htdocs/api/class/api.class.php

@@ -66,6 +66,7 @@ class DolibarrApi
      *
      * @return array
      */
+    /* Disabled, most APIs does not share same signature for method index 
     function index()
     {
         return array(
@@ -74,7 +75,7 @@ class DolibarrApi
                 'message' => __class__.' is up and running!'
             )
         );
-    }
+    }*/
 
 
     /**

+ 26 - 11
htdocs/api/class/api_documents.class.php

@@ -36,8 +36,7 @@ class Documents extends DolibarrApi
      * @var array   $DOCUMENT_FIELDS     Mandatory fields, checked when create and update object
      */
     static $DOCUMENT_FIELDS = array(
-        'modulepart',
-        'filename'
+        'modulepart'
     );
 
     /**
@@ -49,20 +48,36 @@ class Documents extends DolibarrApi
         $this->db = $db;
     }
 
+    
     /**
-     * Return a document
+     * Return list of documents.
      *
-     * @param   string  $module_part    Module part for file
-     * @param   string  $filename       File name
+     * @param   string  $module_part    Name of module or area concerned by file download ('facture', ...)
+     * @param   string  $ref            Reference of object (This will define subdir automatically)
+     * @param   string  $subdir         Subdirectory (Only if ref not provided)
+     * @return  array                   List of documents
      *
-     * @return  array                   Array with data of file
      * @throws RestException
      */
-     public function index($module_part, $filename) {
-            return array('note'=>'FeatureNotYetAvailable');
-     }
-
-
+    public function index($module_part, $ref='', $subdir='') {
+        return array('note'=>'FeatureNotYetAvailable');
+    }
+    
+    
+    /**
+     * Return a document.
+     *
+     * @param   int         $id          ID of document
+     * @return  array                    Array with data of file
+     *
+     * @throws RestException
+     */
+    /*
+    public function get($id) {
+        return array('note'=>'xxx');
+    }*/
+    
+    
     /**
      * Push a file. 
      * Test sample 1: { "filename": "mynewfile.txt", "modulepart": "facture", "ref": "FA1701-001", "subdir": "", "filecontent": "content text", "fileencoding": "", "overwriteifexists": "0" }.

+ 4 - 2
htdocs/categories/class/api_categories.class.php

@@ -146,7 +146,8 @@ class Categories extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $category_static = new Categorie($db);
@@ -232,7 +233,8 @@ class Categories extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $category_static = new Categorie($db);

+ 4 - 2
htdocs/categories/class/api_deprecated_category.class.php

@@ -147,7 +147,8 @@ class CategoryApi extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $category_static = new Categorie($db);
@@ -228,7 +229,8 @@ class CategoryApi extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $category_static = new Categorie($db);

+ 18 - 8
htdocs/categories/class/categorie.class.php

@@ -792,11 +792,12 @@ class Categorie extends CommonObject
 	/**
 	 * Return list of fetched instance of elements having this category
 	 *
-	 * @param   string $type Type of category ('customer', 'supplier', 'contact', 'product', 'member')
-	 *
-	 * @return  mixed        -1 if KO, array of instance of object if OK
+	 * @param   string     $type       Type of category ('customer', 'supplier', 'contact', 'product', 'member')
+	 * @param   int        $onlyids    Return only ids of objects (consume less memory)
+	 * @return  mixed                  -1 if KO, array of instance of object if OK
+	 * @see containsObject
 	 */
-	function getObjectsInCateg($type)
+	function getObjectsInCateg($type, $onlyids=0)
 	{
 		$objs = array();
 
@@ -813,10 +814,18 @@ class Categorie extends CommonObject
 		$resql = $this->db->query($sql);
 		if ($resql)
 		{
-			while ($rec = $this->db->fetch_array($resql)) {
-				$obj = new $this->MAP_OBJ_CLASS[$type]( $this->db );
-				$obj->fetch( $rec['fk_' . $this->MAP_CAT_FK[$type]]);
-				$objs[] = $obj;
+			while ($rec = $this->db->fetch_array($resql)) 
+			{
+			    if ($onlyids)
+			    {
+			        $objs[] = $rec['fk_' . $this->MAP_CAT_FK[$type]];
+			    }
+			    else
+			    {
+				    $obj = new $this->MAP_OBJ_CLASS[$type]( $this->db );
+				    $obj->fetch( $rec['fk_' . $this->MAP_CAT_FK[$type]]);
+				    $objs[] = $obj;
+			    }
 			}
 			return $objs;
 		}
@@ -834,6 +843,7 @@ class Categorie extends CommonObject
 	 * @param   int    $object_id id of the object to search
 	 *
 	 * @return  int                        number of occurrences
+	 * @see getObjectsInCateg
 	 */
 	function containsObject($type, $object_id )
 	{

+ 2 - 1
htdocs/comm/action/class/api_agendaevents.class.php

@@ -147,7 +147,8 @@ class AgendaEvents extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $actioncomm_static = new ActionComm($db);

+ 1 - 1
htdocs/comm/card.php

@@ -204,7 +204,7 @@ if ($id > 0)
 {
 	$head = societe_prepare_head($object);
 
-	dol_fiche_head($head, 'customer', $langs->trans("ThirdParty"),0,'company');
+	dol_fiche_head($head, 'customer', $langs->trans("ThirdParty"), -1, 'company');
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/societe/list.php">'.$langs->trans("BackToList").'</a>';
 	

+ 2 - 1
htdocs/comm/propal/class/api_proposals.class.php

@@ -148,7 +148,8 @@ class Proposals extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $propal_static = new Propal($db);

+ 2 - 1
htdocs/commande/class/api_deprecated_commande.class.php

@@ -163,7 +163,8 @@ class CommandeApi extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $commande_static = new Commande($db);

+ 2 - 1
htdocs/commande/class/api_orders.class.php

@@ -152,7 +152,8 @@ class Orders extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $commande_static = new Commande($db);

+ 2 - 1
htdocs/compta/bank/class/api_bankaccounts.class.php

@@ -98,7 +98,8 @@ class BankAccounts extends DolibarrApi
 
         if ($result) {
             $num = $this->db->num_rows($result);
-            for ($i = 0; $i < min($num, ($limit <= 0 ? $num : $limit)); $i++) {
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            for ($i = 0; $i < $min; $i++) {
                 $obj = $this->db->fetch_object($result);
                 $account = new Account($this->db);
                 if ($account->fetch($obj->rowid) > 0) {

+ 2 - 1
htdocs/compta/facture/class/api_deprecated_invoice.class.php

@@ -161,7 +161,8 @@ class InvoiceApi extends DolibarrApi
         {
             $i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $invoice_static = new Facture($db);

+ 2 - 1
htdocs/compta/facture/class/api_invoices.class.php

@@ -155,7 +155,8 @@ class Invoices extends DolibarrApi
         {
             $i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $invoice_static = new Facture($db);

+ 1 - 1
htdocs/contact/agenda.php

@@ -208,7 +208,7 @@ else
 
         dol_htmloutput_errors($error,$errors);
 
-        dol_fiche_head($head, 'agenda', $title, 0, 'contact');
+        dol_fiche_head($head, 'agenda', $title, -1, 'contact');
 
         $linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php">'.$langs->trans("BackToList").'</a>';
         

+ 1 - 1
htdocs/contact/card.php

@@ -1021,7 +1021,7 @@ else
 
         dol_htmloutput_errors($error,$errors);
 
-        dol_fiche_head($head, 'card', $title, 0, 'contact');
+        dol_fiche_head($head, 'card', $title, -1, 'contact');
 
         if ($action == 'create_user')
         {

+ 1 - 1
htdocs/contact/document.php

@@ -96,7 +96,7 @@ if ($object->id)
     $head = contact_prepare_head($object);
 	$title = (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("Contacts") : $langs->trans("ContactsAddresses"));
 
-    dol_fiche_head($head, 'documents', $title, 0, 'contact');
+    dol_fiche_head($head, 'documents', $title, -1, 'contact');
 
 
     // Construit liste des fichiers

+ 1 - 1
htdocs/contact/info.php

@@ -59,7 +59,7 @@ if ($id > 0)
 
 	$head = contact_prepare_head($object);
 
-	dol_fiche_head($head, 'info', $title, 0, 'contact');
+	dol_fiche_head($head, 'info', $title, -1, 'contact');
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php">'.$langs->trans("BackToList").'</a>';
 

+ 1 - 1
htdocs/contact/ldap.php

@@ -88,7 +88,7 @@ $form = new Form($db);
 
 $head = contact_prepare_head($object);
 
-dol_fiche_head($head, 'ldap', $title, 0, 'contact');
+dol_fiche_head($head, 'ldap', $title, -1, 'contact');
 
 dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', '');
     

+ 75 - 34
htdocs/contact/list.php

@@ -32,8 +32,13 @@ require '../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
 
-$langs->load("companies");
-$langs->load("suppliers");
+$langs->loadLangs(array("companies", "suppliers"));
+
+$action=GETPOST('action','alpha');
+$massaction=GETPOST('massaction','alpha');
+$show_files=GETPOST('show_files','int');
+$confirm=GETPOST('confirm','alpha');
+$toselect = GETPOST('toselect', 'array');
 
 // Security check
 $id = GETPOST('id','int');
@@ -177,7 +182,7 @@ if (empty($reshook))
     // Selection of new fields
     include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
 
-    // Purge search criteria
+    // Did we click on purge search criteria ?
     if (GETPOST('button_removefilter_x') || GETPOST('button_removefilter.x') || GETPOST('button_removefilter'))	// All tests are required to be compatible with all browsers
     {
         $sall="";
@@ -198,6 +203,7 @@ if (empty($reshook))
         $search_categ='';
         $search_categ_thirdparty='';
         $search_categ_supplier='';
+        $toselect='';
         $search_array_options=array();
     }
 
@@ -205,7 +211,7 @@ if (empty($reshook))
     $objectclass='Contact';
     $objectlabel='Contact';
     $permtoread = $user->rights->societe->lire;
-    $permtodelete = $user->rights->societe->delete;
+    $permtodelete = $user->rights->societe->supprimer;
     $uploaddir = $conf->societe->dir_output;
     include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
 }
@@ -224,7 +230,7 @@ $contactstatic=new Contact($db);
 $title = (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("Contacts") : $langs->trans("ContactsAddresses"));
 
 $sql = "SELECT s.rowid as socid, s.nom as name,";
-$sql.= " p.rowid as cidp, p.lastname as lastname, p.statut, p.firstname, p.zip, p.town, p.poste, p.email, p.skype,";
+$sql.= " p.rowid, p.lastname as lastname, p.statut, p.firstname, p.zip, p.town, p.poste, p.email, p.skype,";
 $sql.= " p.phone as phone_pro, p.phone_mobile, p.phone_perso, p.fax, p.fk_pays, p.priv, p.datec as date_creation, p.tms as date_update,";
 $sql.= " co.code as country_code";
 // Add fields from extrafields
@@ -374,8 +380,6 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 
 $sql.= $db->plimit($limit+1, $offset);
 
-//print $sql;
-dol_syslog("contact/list.php", LOG_DEBUG);
 $result = $db->query($sql);
 if (! $result)
 {
@@ -385,15 +389,18 @@ if (! $result)
 
 $num = $db->num_rows($result);
 
+$arrayofselected=is_array($toselect)?$toselect:array();
+
 if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
 {
     $obj = $db->fetch_object($resql);
-    $id = $obj->cidp;
+    $id = $obj->rowid;
     header("Location: ".DOL_URL_ROOT.'/contact/card.php?id='.$id);
     exit;
 }
 
-llxHeader('',$title,'EN:Module_Third_Parties|FR:Module_Tiers|ES:M&oacute;dulo_Empresas');
+$help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:M&oacute;dulo_Empresas';
+llxHeader('',$title,$help_url);
 
 $param='';
 if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
@@ -426,16 +433,26 @@ foreach ($search_array_options as $key => $val)
     if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
 }
 
-print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
+// List of mass actions available
+$arrayofmassactions =  array(
+//    'presend'=>$langs->trans("SendByMail"),
+//    'builddoc'=>$langs->trans("PDFMerge"),
+);
+//if($user->rights->societe->creer) $arrayofmassactions['createbills']=$langs->trans("CreateInvoiceForThisCustomer");
+if ($user->rights->societe->supprimer) $arrayofmassactions['delete']=$langs->trans("Delete");
+if ($massaction == 'presend') $arrayofmassactions=array();
+$massactionbutton=$form->selectMassAction('', $arrayofmassactions);
+
+print '<form method="post" action="'.$_SERVER["PHP_SELF"].'" name="formfilter">';
 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="view" value="'.dol_escape_htmltag($view).'">';
 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="view" value="'.dol_escape_htmltag($view).'">';
 
-print_barre_liste($titre, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_companies.png', 0, '', '', $limit);
+print_barre_liste($titre, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_companies.png', 0, '', '', $limit);
 
 if ($sall)
 {
@@ -447,6 +464,7 @@ if ($search_firstlast_only)
     print $langs->trans("FilterOnInto", $search_firstlast_only) . $langs->trans("Lastname").", ".$langs->trans("Firstname");
 }
 
+$moreforfilter='';
 if (! empty($conf->categorie->enabled))
 {
 	require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
@@ -483,6 +501,7 @@ if ($moreforfilter)
 
 $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage;
 $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage);	// This also change content of $arrayfields
+if ($massactionbutton) $selectedfields.=$form->showCheckAddButtons('checkforselect', 1);
 
 print '<div class="div-table-responsive">';
 print '<table class="tagtable liste'.($moreforfilter?" listwithfilterbefore":"").'">'."\n";
@@ -575,7 +594,18 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
    {
 		if (! empty($arrayfields["ef.".$key]['checked']))
 		{
-			print '<td class="liste_titre">';
+            $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>';
 		}
    }
@@ -596,15 +626,17 @@ if (! empty($arrayfields['p.tms']['checked']))
     print '<td class="liste_titre">';
     print '</td>';
 }
+// Status
 if (! empty($arrayfields['p.statut']['checked']))
 {
     print '<td class="liste_titre" align="center">';
     print $form->selectarray('search_status', array('-1'=>'', '0'=>$langs->trans('ActivityCeased'),'1'=>$langs->trans('InActivity')),$search_status);
     print '</td>';
 }
+// Action column
 print '<td class="liste_titre" align="right">';
-print '<input type="image" name="button_search" class="liste_titre" src="'.img_picto($langs->trans("Search"),'search.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("Search")).'" title="'.dol_escape_htmltag($langs->trans("Search")).'">';
-print '<input type="image" name="button_removefilter" class="liste_titre" src="'.img_picto($langs->trans("RemoveFilter"),'searchclear.png','','',1).'" value="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'" title="'.dol_escape_htmltag($langs->trans("RemoveFilter")).'">';
+$searchpicto=$form->showFilterButtons();
+print $searchpicto;
 print '</td>';
 
 print '</tr>';
@@ -632,7 +664,9 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
        if (! empty($arrayfields["ef.".$key]['checked']))
        {
 			$align=$extrafields->getAlignFlag($key);
-			print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+			$sortonfield = "ef.".$key;
+			if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+			print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
        }
    }
 }
@@ -656,7 +690,7 @@ while ($i < min($num,$limit))
 
 	$contactstatic->lastname=$obj->lastname;
 	$contactstatic->firstname='';
-	$contactstatic->id=$obj->cidp;
+	$contactstatic->id=$obj->rowid;
 	$contactstatic->statut=$obj->statut;
 	$contactstatic->poste=$obj->poste;
 	$contactstatic->email=$obj->email;
@@ -696,32 +730,32 @@ while ($i < min($num,$limit))
     // Phone
     if (! empty($arrayfields['p.phone']['checked']))
     {
-        print '<td>'.dol_print_phone($obj->phone_pro,$obj->country_code,$obj->cidp,$obj->socid,'AC_TEL').'</td>';
+        print '<td>'.dol_print_phone($obj->phone_pro,$obj->country_code,$obj->rowid,$obj->socid,'AC_TEL').'</td>';
     }
     // Phone perso
     if (! empty($arrayfields['p.phone_perso']['checked']))
     {
-        print '<td>'.dol_print_phone($obj->phone_perso,$obj->country_code,$obj->cidp,$obj->socid,'AC_TEL').'</td>';
+        print '<td>'.dol_print_phone($obj->phone_perso,$obj->country_code,$obj->rowid,$obj->socid,'AC_TEL').'</td>';
     }
     // Phone mobile
     if (! empty($arrayfields['p.phone_mobile']['checked']))
     {
-        print '<td>'.dol_print_phone($obj->phone_mobile,$obj->country_code,$obj->cidp,$obj->socid,'AC_TEL').'</td>';
+        print '<td>'.dol_print_phone($obj->phone_mobile,$obj->country_code,$obj->rowid,$obj->socid,'AC_TEL').'</td>';
     }
     // Fax
     if (! empty($arrayfields['p.fax']['checked']))
     {
-        print '<td>'.dol_print_phone($obj->fax,$obj->country_code,$obj->cidp,$obj->socid,'AC_TEL').'</td>';
+        print '<td>'.dol_print_phone($obj->fax,$obj->country_code,$obj->rowid,$obj->socid,'AC_TEL').'</td>';
     }
     // EMail
     if (! empty($arrayfields['p.email']['checked']))
     {
-        print '<td>'.dol_print_email($obj->email,$obj->cidp,$obj->socid,'AC_EMAIL',18).'</td>';
+        print '<td>'.dol_print_email($obj->email,$obj->rowid,$obj->socid,'AC_EMAIL',18).'</td>';
     }
     // Skype
     if (! empty($arrayfields['p.skype']['checked']))
     {
-        if (! empty($conf->skype->enabled)) { print '<td>'.dol_print_skype($obj->skype,$obj->cidp,$obj->socid,'AC_SKYPE',18).'</td>'; }
+        if (! empty($conf->skype->enabled)) { print '<td>'.dol_print_skype($obj->skype,$obj->rowid,$obj->socid,'AC_SKYPE',18).'</td>'; }
     }
     // Company
     if (! empty($arrayfields['p.thirdparty']['checked']))
@@ -784,28 +818,35 @@ while ($i < min($num,$limit))
     {
         print '<td align="center">'.$contactstatic->getLibStatut(3).'</td>';
     }
-    // Action column - Links Add action and Export vcard
-    print '<td class="center">';
-    /*print '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;contactid='.$obj->cidp.'&amp;socid='.$obj->socid.'">'.img_object($langs->trans("AddAction"),"action").'</a>';
-    print ' &nbsp; ';
-    print '<a href="'.DOL_URL_ROOT.'/contact/vcard.php?id='.$obj->cidp.'">';
-    print img_picto($langs->trans("VCard"),'vcard.png').' ';
-    print '</a>'; */
-    print '</td>';
 
+   // Action column
+    print '<td class="nowrap" align="center">';
+    if ($massactionbutton || $massaction)   // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined
+    {
+        $selected=0;
+		if (in_array($obj->rowid, $arrayofselected)) $selected=1;
+		print '<input id="cb'.$obj->rowid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->rowid.'"'.($selected?' checked="checked"':'').'>';
+    }
+    print '</td>';
+    if (! $i) $totalarray['nbfield']++;
+    
     print "</tr>\n";
     $i++;
 }
 
+$db->free($result);
+
+$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>";
 print "</div>";
 
-if ($num > $limit || $page) print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_companies.png', 0, '', '', $limit, 1);
+//if ($num > $limit || $page) print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_companies.png', 0, '', '', $limit, 1);
 
 print '</form>';
 
-$db->free($result);
-
 
 llxFooter();
 $db->close();

+ 1 - 49
htdocs/contact/note.php

@@ -73,7 +73,7 @@ if ($id > 0)
 
     $head = contact_prepare_head($object);
 
-    dol_fiche_head($head, 'note', $title,0,'contact');
+    dol_fiche_head($head, 'note', $title, -1, 'contact');
     
     $linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php">'.$langs->trans("BackToList").'</a>';
 
@@ -100,61 +100,13 @@ if ($id > 0)
 
 	print '<table class="border centpercent">';
 
-    // Company
-    if (empty($conf->global->SOCIETE_DISABLE_CONTACTS))
-    {
-    	if ($object->socid > 0)
-    	{
-    		$objsoc = new Societe($db);
-    		$objsoc->fetch($object->socid);
-
-    		print '<tr><td class="'.$cssclass.'">'.$langs->trans("ThirdParty").'</td><td>'.$objsoc->getNomUrl(1).'</td></tr>';
-    	}
-
-    	else
-    	{
-    		print '<tr><td class="'.$cssclass.'">'.$langs->trans("ThirdParty").'</td><td>';
-    		print $langs->trans("ContactNotLinkedToCompany");
-    		print '</td></tr>';
-    	}
-    }
-
     // Civility
     print '<tr><td class="'.$cssclass.'">'.$langs->trans("UserTitle").'</td><td>';
     print $object->getCivilityLabel();
     print '</td></tr>';
 
-    // Date To Birth
-    print '<tr>';
-    if (! empty($object->birthday))
-    {
-    	include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
-
-    	print '<td>'.$langs->trans("DateToBirth").'</td><td>'.dol_print_date($object->birthday,"day");
-
-    	print ' &nbsp; ';
-    	//var_dump($birthdatearray);
-    	$ageyear=convertSecondToTime($now-$object->birthday,'year')-1970;
-    	$agemonth=convertSecondToTime($now-$object->birthday,'month')-1;
-    	if ($ageyear >= 2) print '('.$ageyear.' '.$langs->trans("DurationYears").')';
-    	else if ($agemonth >= 2) print '('.$agemonth.' '.$langs->trans("DurationMonths").')';
-    	else print '('.$agemonth.' '.$langs->trans("DurationMonth").')';
-
-
-    	print ' &nbsp; - &nbsp; ';
-    	if ($object->birthday_alert) print $langs->trans("BirthdayAlertOn");
-    	else print $langs->trans("BirthdayAlertOff");
-    	print '</td>';
-    }
-    else
-    {
-    	print '<td>'.$langs->trans("DateToBirth").'</td><td>'.$langs->trans("Unknown")."</td>";
-    }
-    print "</tr>";
-
     print "</table>";
 
-    print '<br>';
     
 	$cssclass="titlefield";
 	include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php';

+ 1 - 1
htdocs/contact/perso.php

@@ -229,7 +229,7 @@ else
 {
     // View mode
     
-    dol_fiche_head($head, 'perso', $title, 0, 'contact');
+    dol_fiche_head($head, 'perso', $title, -1, 'contact');
     
     $linkback = '<a href="'.DOL_URL_ROOT.'/contact/list.php">'.$langs->trans("BackToList").'</a>';
     

+ 34 - 33
htdocs/contrat/card.php

@@ -2083,44 +2083,45 @@ else
 
             print "</div>";
         }
-	// Select mail models is same action as presend
-	if (GETPOST('modelselected')) {
-		$action = 'presend';
-	}
-
-	if ($action != 'presend')
-	{
-		print '<div class="fichecenter"><div class="fichehalfleft">';
-
-		/*
-		 * Documents generes
-		*/
-		$filename = dol_sanitizeFileName($object->ref);
-		$filedir = $conf->contrat->dir_output . "/" . dol_sanitizeFileName($object->ref);
-		$urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
-		$genallowed = $user->rights->contrat->creer;
-		$delallowed = $user->rights->contrat->supprimer;
-
-		$var = true;
-
-		print $formfile->showdocuments('contract', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang);
-
-
-			// Show links to link elements
-			$linktoelem = $form->showLinkToObjectBlock($object, null, array('contrat'));
-			$somethingshown = $form->showLinkedObjectBlock($object, $linktoelem);
-
-
-		print '</div><div class="fichehalfright"><div class="ficheaddleft">';
-
+        
+    	// Select mail models is same action as presend
+    	if (GETPOST('modelselected')) {
+    		$action = 'presend';
+    	}
+    
+    	if ($action != 'presend')
+    	{
+    		print '<div class="fichecenter"><div class="fichehalfleft">';
+    
+    		/*
+    		 * Documents generes
+    		*/
+    		$filename = dol_sanitizeFileName($object->ref);
+    		$filedir = $conf->contrat->dir_output . "/" . dol_sanitizeFileName($object->ref);
+    		$urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
+    		$genallowed = $user->rights->contrat->creer;
+    		$delallowed = $user->rights->contrat->supprimer;
+    
+    		$var = true;
+    
+    		print $formfile->showdocuments('contract', $filename, $filedir, $urlsource, $genallowed, $delallowed, $object->modelpdf, 1, 0, 0, 28, 0, '', 0, '', $soc->default_lang);
+    
+    
+    			// Show links to link elements
+    			$linktoelem = $form->showLinkToObjectBlock($object, null, array('contrat'));
+    			$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, 'contract', $socid);
 
-
-		print '</div></div></div>';
-	}
+    
+    		print '</div></div></div>';
+    	}
 
 		/*
 		 * Action presend

+ 58 - 50
htdocs/core/actions_extrafields.inc.php

@@ -14,6 +14,8 @@
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  * or see http://www.gnu.org/
+ * 
+ * $elementype must be defined.
  */
 
 /**
@@ -24,11 +26,14 @@
 $maxsizestring=255;
 $maxsizeint=10;
 
-$extrasize=GETPOST('size');
-if (GETPOST('type')=='double' && strpos($extrasize,',')===false) $extrasize='24,8';
-if (GETPOST('type')=='date')     $extrasize='';
-if (GETPOST('type')=='datetime') $extrasize='';
-if (GETPOST('type')=='select')   $extrasize='';
+$extrasize=GETPOST('size','int');
+$type=GETPOST('type','alpha');
+$param=GETPOST('param','alpha');;
+
+if ($type=='double' && strpos($extrasize,',')===false) $extrasize='24,8';
+if ($type=='date')     $extrasize='';
+if ($type=='datetime') $extrasize='';
+if ($type=='select')   $extrasize='';
 
 
 // Add attribute
@@ -37,73 +42,73 @@ if ($action == 'add')
 	if ($_POST["button"] != $langs->trans("Cancel"))
 	{
 	    // Check values
-		if (! GETPOST('type'))
+		if (! $type)
 		{
 			$error++;
 			$langs->load("errors");
 			$mesg[]=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type"));
 			$action = 'create';
 		}
-		if (GETPOST('type')=='varchar' && $extrasize <= 0)
+		if ($type=='varchar' && $extrasize <= 0)
 		{
 		    $error++;
 		    $langs->load("errors");
 		    $mesg[]=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Size"));
 		    $action = 'edit';
 		}
-        if (GETPOST('type')=='varchar' && $extrasize > $maxsizestring)
+        if ($type=='varchar' && $extrasize > $maxsizestring)
         {
             $error++;
             $langs->load("errors");
             $mesg[]=$langs->trans("ErrorSizeTooLongForVarcharType",$maxsizestring);
             $action = 'create';
         }
-        if (GETPOST('type')=='int' && $extrasize > $maxsizeint)
+        if ($type=='int' && $extrasize > $maxsizeint)
         {
             $error++;
             $langs->load("errors");
             $mesg[]=$langs->trans("ErrorSizeTooLongForIntType",$maxsizeint);
             $action = 'create';
         }
-        if (GETPOST('type')=='select' && !GETPOST('param'))
+        if ($type=='select' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForSelectType");
         	$action = 'create';
         }
-        if (GETPOST('type')=='sellist' && !GETPOST('param'))
+        if ($type=='sellist' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForSelectListType");
         	$action = 'create';
         }
-        if (GETPOST('type')=='checkbox' && !GETPOST('param'))
+        if ($type=='checkbox' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForCheckBoxType");
         	$action = 'create';
         }
-        if (GETPOST('type')=='link' && !GETPOST('param'))
+        if ($type=='link' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForLinkType");
         	$action = 'create';
         }
-        if (GETPOST('type')=='radio' && !GETPOST('param'))
+        if ($type=='radio' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForRadioType");
         	$action = 'create';
         }
-        if  (((GETPOST('type')=='radio') || (GETPOST('type')=='checkbox')) && GETPOST('param'))
+        if  ((($type=='radio') || ($type=='checkbox')) && $param)
         {
         	// Construct array for parameter (value of select list)
-    		$parameters = GETPOST('param');
+    		$parameters = $param;
     		$parameters_array = explode("\r\n",$parameters);
     		foreach($parameters_array as $param_ligne)
     		{
@@ -134,11 +139,11 @@ if ($action == 'add')
     		if (isset($_POST["attrname"]) && preg_match("/^[a-z0-9-_]+$/",$_POST['attrname']) && !is_numeric($_POST["attrname"]))
     		{
     			// Construct array for parameter (value of select list)
-        		$default_value = GETPOST('default_value');
-    			$parameters = GETPOST('param');
+        		$default_value = GETPOST('default_value','alpha');
+    			$parameters = $param;
     			$parameters_array = explode("\r\n",$parameters);
     			//In sellist we have only one line and it can have come to do SQL expression
-    			if (GETPOST('type')=='sellist') {
+    			if ($type=='sellist') {
     				foreach($parameters_array as $param_ligne)
     				{
     					$params['options'] = array($parameters=>null);
@@ -155,20 +160,21 @@ if ($action == 'add')
     			}
 
                 $result=$extrafields->addExtraField(
-                	GETPOST('attrname'),
-                	GETPOST('label'),
-                	GETPOST('type'),
-                	GETPOST('pos'),
+                	GETPOST('attrname', 'alpha'),
+                	GETPOST('label', 'alpha'),
+                	$type,
+                	GETPOST('pos', 'alpha'),
                 	$extrasize,
                 	$elementtype,
-                	(GETPOST('unique')?1:0),
-                	(GETPOST('required')?1:0),
+                	(GETPOST('unique', 'alpha')?1:0),
+                	(GETPOST('required', 'alpha')?1:0),
                 	$default_value,
                 	$params,
-                	(GETPOST('alwayseditable')?1:0),
-                	(GETPOST('perms')?GETPOST('perms'):''),
-                	(GETPOST('list')?1:0),
-					(GETPOST('ishidden')?1:0)
+                	(GETPOST('alwayseditable', 'alpha')?1:0),
+                	(GETPOST('perms', 'alpha')?GETPOST('perms', 'alpha'):''),
+                	(GETPOST('list', 'alpha')?1:0),
+					(GETPOST('ishidden', 'alpha')?1:0),
+                    GETPOST('computed_value','alpha')
                 );
     			if ($result > 0)
     			{
@@ -205,66 +211,66 @@ if ($action == 'update')
 	if ($_POST["button"] != $langs->trans("Cancel"))
 	{
         // Check values
-		if (! GETPOST('type'))
+		if (! $type)
 		{
 			$error++;
 			$langs->load("errors");
 			$mesg[]=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Type"));
 			$action = 'edit';
 		}
-		if (GETPOST('type')=='varchar' && $extrasize <= 0)
+		if ($type=='varchar' && $extrasize <= 0)
 		{
 		    $error++;
 		    $langs->load("errors");
 		    $mesg[]=$langs->trans("ErrorFieldRequired",$langs->transnoentitiesnoconv("Size"));
 		    $action = 'edit';
 		}
-		if (GETPOST('type')=='varchar' && $extrasize > $maxsizestring)
+		if ($type=='varchar' && $extrasize > $maxsizestring)
         {
             $error++;
             $langs->load("errors");
             $mesg[]=$langs->trans("ErrorSizeTooLongForVarcharType",$maxsizestring);
             $action = 'edit';
         }
-        if (GETPOST('type')=='int' && $extrasize > $maxsizeint)
+        if ($type=='int' && $extrasize > $maxsizeint)
         {
             $error++;
             $langs->load("errors");
             $mesg[]=$langs->trans("ErrorSizeTooLongForIntType",$maxsizeint);
             $action = 'edit';
         }
-        if (GETPOST('type')=='select' && !GETPOST('param'))
+        if ($type=='select' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForSelectType");
         	$action = 'edit';
         }
-        if (GETPOST('type')=='sellist' && !GETPOST('param'))
+        if ($type=='sellist' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForSelectListType");
         	$action = 'edit';
         }
-        if (GETPOST('type')=='checkbox' && !GETPOST('param'))
+        if ($type=='checkbox' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForCheckBoxType");
         	$action = 'edit';
         }
-        if (GETPOST('type')=='radio' && !GETPOST('param'))
+        if ($type=='radio' && !$param)
         {
         	$error++;
         	$langs->load("errors");
         	$mesg[]=$langs->trans("ErrorNoValueForRadioType");
         	$action = 'edit';
         }
-        if  (((GETPOST('type')=='radio') || (GETPOST('type')=='checkbox')) && GETPOST('param'))
+        if  ((($type=='radio') || ($type=='checkbox')) && $param)
         {
         	// Construct array for parameter (value of select list)
-        	$parameters = GETPOST('param');
+        	$parameters = $param;
         	$parameters_array = explode("\r\n",$parameters);
         	foreach($parameters_array as $param_ligne)
         	{
@@ -295,10 +301,10 @@ if ($action == 'update')
     		{
     			$pos = GETPOST('pos','int');
     			// Construct array for parameter (value of select list)
-    			$parameters = GETPOST('param');
+    			$parameters = $param;
     			$parameters_array = explode("\r\n",$parameters);
     			//In sellist we have only one line and it can have come to do SQL expression
-    			if (GETPOST('type')=='sellist') {
+    			if ($type=='sellist') {
     				foreach($parameters_array as $param_ligne)
     				{
     					$params['options'] = array($parameters=>null);
@@ -315,19 +321,21 @@ if ($action == 'update')
     			}
 
     			$result=$extrafields->update(
-    				GETPOST('attrname'),
-    				GETPOST('label'),
-    				GETPOST('type'),
+    				GETPOST('attrname', 'alpha'),
+    				GETPOST('label', 'alpha'),
+    				$type,
     				$extrasize,
     				$elementtype,
-    				(GETPOST('unique')?1:0),
-    				(GETPOST('required')?1:0),
+    				(GETPOST('unique', 'alpha')?1:0),
+    				(GETPOST('required', 'alpha')?1:0),
     				$pos,
     				$params,
-    				(GETPOST('alwayseditable')?1:0),
-    				(GETPOST('perms')?GETPOST('perms'):''),
-                	(GETPOST('list')?1:0),
-					(GETPOST('ishidden')?1:0)
+    				(GETPOST('alwayseditable', 'alpha')?1:0),
+    				(GETPOST('perms', 'alpha')?GETPOST('perms', 'alpha'):''),
+                	(GETPOST('list', 'alpha')?1:0),
+					(GETPOST('ishidden', 'alpha')?1:0),
+    			    GETPOST('default_value','alpha'),
+    			    GETPOST('computed_value','alpha')
     			);
     			if ($result > 0)
     			{

+ 69 - 28
htdocs/core/class/extrafields.class.php

@@ -36,14 +36,22 @@
 class ExtraFields
 {
 	var $db;
-	// Tableau contenant le nom des champs en clef et la definition de ces champs
+
+	// type of element (for what object is the extrafield)
+	var $attribute_elementtype;
+	
+	// Array with type of the extra field
 	var $attribute_type;
-	// Tableau contenant le nom des champs en clef et le label de ces champs en value
+	// Array with label of extra field
 	var $attribute_label;
-	// Tableau contenant le nom des champs en clef et la taille/longueur max de ces champs en value
+	// Array with size of extra field
 	var $attribute_size;
-	// Tableau contenant le nom des choix en clef et la valeur de ces choix en value
+	// array with list of possible values for some types of extra fields
 	var $attribute_choice;
+	// Array to store compute formula for computed fields
+	var $attribute_computed;
+	// Array to store default value
+	var $attribute_default;
 	// Array to store if attribute is unique or not
 	var $attribute_unique;
 	// Array to store if attribute is required or not
@@ -77,16 +85,17 @@ class ExtraFields
 	'phone'=>'ExtrafieldPhone',
 	'mail'=>'ExtrafieldMail',
 	'url'=>'ExtrafieldUrl',
+	'password' => 'ExtrafieldPassword',
 	'select' => 'ExtrafieldSelect',
 	'sellist' => 'ExtrafieldSelectList',
 	'radio' => 'ExtrafieldRadio',
 	'checkbox' => 'ExtrafieldCheckBox',
 	'chkbxlst' => 'ExtrafieldCheckBoxFromList',
 	'link' => 'ExtrafieldLink',
-	'password' => 'ExtrafieldPassword',
 	'separate' => 'ExtrafieldSeparator',
 	);
 
+	
 	/**
 	 *	Constructor
 	 *
@@ -96,10 +105,12 @@ class ExtraFields
 	{
 		$this->db = $db;
 		$this->error = array();
+		$this->attribute_elementtype = array();
 		$this->attribute_type = array();
 		$this->attribute_label = array();
 		$this->attribute_size = array();
-		$this->attribute_elementtype = array();
+		$this->attribute_computed = array();
+		$this->attribute_default = array();
 		$this->attribute_unique = array();
 		$this->attribute_required = array();
 		$this->attribute_perms = array();
@@ -118,15 +129,16 @@ class ExtraFields
 	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', ...)
 	 *  @param	int		$unique				Is field unique or not
 	 *  @param	int		$required			Is field required or not
-	 *  @param	string	$default_value		Defaulted value (Example: '', '0', 'null', 'avalue')
+	 *  @param	string	$default_value		Defaulted value (In database. use the default_value feature for default value on screen. Example: '', '0', 'null', 'avalue')
 	 *  @param  array	$param				Params for field
 	 *  @param  int		$alwayseditable		Is attribute always editable regardless of the document status
 	 *  @param	string	$perms				Permission to check
 	 *  @param	int		$list				Into list view by default
 	 *  @param	int		$ishidden			Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
+	 *  @param  string  $computed           Computed value
 	 *  @return int      					<=0 if KO, >0 if OK
 	 */
-	function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param=0, $alwayseditable=0, $perms='', $list=0, $ishidden=0)
+	function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param=0, $alwayseditable=0, $perms='', $list=0, $ishidden=0, $computed='')
 	{
 		if (empty($attrname)) return -1;
 		if (empty($label)) return -1;
@@ -137,13 +149,13 @@ class ExtraFields
 		// Create field into database except for separator type which is not stored in database
 		if ($type != 'separate')
 		{
-			$result=$this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list);
+			$result=$this->create($attrname, $type, $size, $elementtype, $unique, $required, $default_value, $param, $perms, $list, $copmputed);
 		}
 		$err1=$this->errno;
 		if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate')
 		{
 			// Add declaration of field into table
-			$result2=$this->create_label($attrname,$label,$type,$pos,$size,$elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $ishidden);
+			$result2=$this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $ishidden, $default, $computed);
 			$err2=$this->errno;
 			if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS'))
 			{
@@ -169,13 +181,14 @@ class ExtraFields
 	 *  @param  string	$elementtype        Element type ('member', 'product', 'thirdparty', 'contact', ...)
 	 *  @param	int		$unique				Is field unique or not
 	 *  @param	int		$required			Is field required or not
-	 *  @param  string  $default_value		Default value for field
+	 *  @param  string  $default_value		Default value for field (in database)
 	 *  @param  array	$param				Params for field  (ex for select list : array('options'=>array('value'=>'label of option'))
 	 *  @param	string	$perms				Permission
 	 *	@param	int		$list				Into list view by default
+	 *  @param  string  $computed           Computed value
 	 *  @return int      	           		<=0 if KO, >0 if OK
 	 */
-	private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='',$param='', $perms='', $list=0)
+	private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0, $required=0, $default_value='',$param='', $perms='', $list=0, $computed='')
 	{
 		if ($elementtype == 'thirdparty') $elementtype='societe';
 		if ($elementtype == 'contact') $elementtype='socpeople';
@@ -258,9 +271,11 @@ class ExtraFields
 	 *  @param	string			$perms			Permission to check
 	 *  @param	int				$list			Into list view by default
 	 *  @param	int				$ishidden		Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
+	 *  @param  string          $default        Default value (in database. use the default_value feature for default value on screen).
+	 *  @param  string          $computed       Computed value
 	 *  @return	int								<=0 if KO, >0 if OK
 	 */
-	private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list=0, $ishidden=0)
+	private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0, $required=0, $param='', $alwayseditable=0, $perms='', $list=0, $ishidden=0, $default='', $computed='')
 	{
 		global $conf;
 
@@ -286,7 +301,7 @@ class ExtraFields
 				$params='';
 			}
 
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype, fieldunique, fieldrequired, param, alwayseditable, perms, list, ishidden)";
+			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype, fieldunique, fieldrequired, param, alwayseditable, perms, list, ishidden, fielddefault, fieldcomputed)";
 			$sql.= " VALUES('".$attrname."',";
 			$sql.= " '".$this->db->escape($label)."',";
 			$sql.= " '".$type."',";
@@ -299,8 +314,10 @@ class ExtraFields
 			$sql.= " '".$params."',";
 			$sql.= " '".$alwayseditable."',";
 			$sql.= " ".($perms?"'".$this->db->escape($perms)."'":"null").",";
-			$sql.= " ".$list;
-			$sql.= ", ".$ishidden;
+			$sql.= " ".$list.",";
+			$sql.= " ".$ishidden.",";
+			$sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
+			$sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
 			$sql.=')';
 
 			dol_syslog(get_class($this)."::create_label", LOG_DEBUG);
@@ -430,9 +447,11 @@ class ExtraFields
 	 *  @param	string	$perms				Permission to check
 	 *  @param	int		$list				Into list view by default
 	 *  @param	int		$ishidden			Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
+	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
+	 *  @param  string  $computed           Computed value
 	 * 	@return	int							>0 if OK, <=0 if KO
 	 */
-	function update($attrname,$label,$type,$length,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0, $perms='',$list='',$ishidden=0)
+	function update($attrname,$label,$type,$length,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0, $perms='',$list='',$ishidden=0,$default='',$computed='')
 	{
 		if ($elementtype == 'thirdparty') $elementtype='societe';
 		if ($elementtype == 'contact') $elementtype='socpeople';
@@ -479,7 +498,7 @@ class ExtraFields
 			{
 				if ($label)
 				{
-					$result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique,$required,$pos,$param,$alwayseditable,$perms,$list,$ishidden);
+					$result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique,$required,$pos,$param,$alwayseditable,$perms,$list,$ishidden,$default,$computed);
 				}
 				if ($result > 0)
 				{
@@ -531,12 +550,14 @@ class ExtraFields
 	 *  @param	string	$perms				Permission to check
 	 *  @param	int		$list				Into list view by default
 	 *  @param	int		$ishidden			Is hidden extrafield (warning, do not rely on this. If your module need a hidden data, it must use its own table)
+	 *  @param  string  $default            Default value (in database. use the default_value feature for default value on screen).
+	 *  @param  string  $computed           Computed value
 	 *  @return	int							<=0 if KO, >0 if OK
 	 */
-	private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list=0,$ishidden=0)
+	private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0,$required=0,$pos=0,$param='',$alwayseditable=0,$perms='',$list=0,$ishidden=0,$default='',$computed='')
 	{
 		global $conf;
-		dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$ishidden);
+		dol_syslog(get_class($this)."::update_label ".$attrname.", ".$label.", ".$type.", ".$size.", ".$elementtype.", ".$unique.", ".$required.", ".$pos.", ".$alwayseditable.", ".$perms.", ".$list.", ".$ishidden.", ".$default.", ".$computed);
 
 		// Clean parameters
 		if ($elementtype == 'thirdparty') $elementtype='societe';
@@ -557,7 +578,7 @@ class ExtraFields
 			$sql_del.= " WHERE name = '".$attrname."'";
 			$sql_del.= " AND entity = ".$conf->entity;
 			$sql_del.= " AND elementtype = '".$elementtype."'";
-			dol_syslog(get_class($this)."::update_label", LOG_DEBUG);
+
 			$resql1=$this->db->query($sql_del);
 
 			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(";
@@ -573,8 +594,10 @@ class ExtraFields
 			$sql.= " pos,";
 			$sql.= " alwayseditable,";
 			$sql.= " param,";
-			$sql.= " list";
-			$sql.= ", ishidden";
+			$sql.= " list,";
+			$sql.= " ishidden,";
+			$sql.= " fielddefault,";
+			$sql.= " fieldcomputed";
 			$sql.= ") VALUES (";
 			$sql.= "'".$attrname."',";
 			$sql.= " ".$conf->entity.",";
@@ -588,10 +611,12 @@ class ExtraFields
 			$sql.= " '".$pos."',";
 			$sql.= " '".$alwayseditable."',";
 			$sql.= " '".$param."',";
-			$sql.= " ".$list;
-			$sql.= ", ".$ishidden;
+			$sql.= " ".$list.", ";
+			$sql.= " ".$ishidden.", ";
+			$sql.= " ".($default?"'".$this->db->escape($default)."'":"null").",";
+			$sql.= " ".($computed?"'".$this->db->escape($computed)."'":"null");
 			$sql.= ")";
-			dol_syslog(get_class($this)."::update_label", LOG_DEBUG);
+
 			$resql2=$this->db->query($sql);
 
 			if ($resql1 && $resql2)
@@ -635,7 +660,7 @@ class ExtraFields
 		// For avoid conflicts with external modules
 		if (!$forceload && !empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) return $array_name_label;
 
-		$sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,list,ishidden";
+		$sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique,fieldrequired,param,pos,alwayseditable,perms,list,ishidden,fielddefault,fieldcomputed";
 		$sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
 		$sql.= " WHERE entity IN (0,".$conf->entity.")";
 		if ($elementtype) $sql.= " AND elementtype = '".$elementtype."'";
@@ -658,6 +683,8 @@ class ExtraFields
 					$this->attribute_label[$tab->name]=$tab->label;
 					$this->attribute_size[$tab->name]=$tab->size;
 					$this->attribute_elementtype[$tab->name]=$tab->elementtype;
+					$this->attribute_default[$tab->name]=$tab->fielddefault;
+					$this->attribute_computed[$tab->name]=$tab->fieldcomputed;
 					$this->attribute_unique[$tab->name]=$tab->fieldunique;
 					$this->attribute_required[$tab->name]=$tab->fieldrequired;
 					$this->attribute_param[$tab->name]=($tab->param ? unserialize($tab->param) : '');
@@ -699,6 +726,8 @@ class ExtraFields
 		$type =$this->attribute_type[$key];
 		$size =$this->attribute_size[$key];
 		$elementtype=$this->attribute_elementtype[$key];
+		$default=$this->attribute_default[$key];
+		$computed=$this->attribute_computed[$key];
 		$unique=$this->attribute_unique[$key];
 		$required=$this->attribute_required[$key];
 		$param=$this->attribute_param[$key];
@@ -706,6 +735,8 @@ class ExtraFields
 		$list=$this->attribute_list[$key];
 		$hidden=$this->attribute_hidden[$key];
 
+		if ($computed) return '<span class="opacitymedium">'.$langs->trans("AutomaticallyCalculated").'</span>';
+		
 		if (empty($showsize))
 		{
     		if ($type == 'date')
@@ -1218,10 +1249,12 @@ class ExtraFields
 	{
 		global $conf,$langs;
 
+		$elementtype=$this->attribute_elementtype[$key];
 		$label=$this->attribute_label[$key];
 		$type=$this->attribute_type[$key];
 		$size=$this->attribute_size[$key];
-		$elementtype=$this->attribute_elementtype[$key];
+		$default=$this->attribute_default[$key];
+		$computed=$this->attribute_computed[$key];
 		$unique=$this->attribute_unique[$key];
 		$required=$this->attribute_required[$key];
 		$params=$this->attribute_param[$key];
@@ -1229,6 +1262,14 @@ class ExtraFields
 		$list=$this->attribute_list[$key];
 		$hidden=$this->attribute_hidden[$key];	// warning, do not rely on this. If your module need a hidden data, it must use its own table.
 
+		// If field is a computed field, value must become result of compute
+		if ($computed)
+		{
+		    // Make the eval of compute string
+		    //var_dump($computed);
+		    $value = dol_eval($computed, 1, 0);
+		}
+		
 		$showsize=0;
 		if ($type == 'date')
 		{

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

@@ -4783,7 +4783,7 @@ class Form
                 {
                     $retstring.='<select'.($disabled?' disabled':'').' class="flat valignmiddle maxwidth75imp" id="'.$prefix.'year" name="'.$prefix.'year">';
 
-                    for ($year = $syear - 5; $year < $syear + 10 ; $year++)
+                    for ($year = $syear - 10; $year < $syear + 10 ; $year++)
                     {
                         $retstring.='<option value="'.$year.'"'.($year == $syear ? ' selected':'').'>'.$year.'</option>';
                     }

+ 4 - 1
htdocs/core/class/html.formactions.class.php

@@ -189,7 +189,9 @@ class FormActions
 
         	$page=0; $param=''; $sortfield='a.datep';
         	
-        	$total = 0;	$var=true; 
+        	$total = 0; 
+        	
+        	print '<div class="div-table-responsive">';
         	print '<table class="noborder'.($morecss?' '.$morecss:'').'" width="100%">';
         	print '<tr class="liste_titre">';
         	print_liste_field_titre($langs->trans('Ref'), $_SERVER["PHP_SELF"], '', $page, $param, '');
@@ -243,6 +245,7 @@ class FormActions
         		print '</tr>';
         	}
         	print '</table>';
+        	print '</div>';
         }
 
         return $num;

+ 3 - 3
htdocs/core/lib/ajax.lib.php

@@ -354,9 +354,9 @@ function ajax_dialog($title,$message,$w=350,$h=150)
  * Make content of an input box selected when we click into input field.
  * 
  * @param string	$htmlname	Id of html object 
- * @param int		$addlink	Add a link to after
+ * @param string	$addlink	Add a 'link to' after
  */
-function ajax_autoselect($htmlname, $addlink=0)
+function ajax_autoselect($htmlname, $addlink='')
 {
 	global $langs;
 	$out = '<script type="text/javascript">
@@ -364,7 +364,7 @@ function ajax_autoselect($htmlname, $addlink=0)
 				    jQuery("#'.$htmlname.'").click(function() { jQuery(this).select(); } );
 				});
 		    </script>';
-	if ($addlink) $out.=' <a href="'.$url.'" target="_blank">'.$langs->trans("Link").'</a>';
+	if ($addlink) $out.=' <a href="'.$addlink.'" target="_blank">'.$langs->trans("Link").'</a>';
 	return $out;
 }
 

+ 10 - 0
htdocs/core/lib/files.lib.php

@@ -2214,6 +2214,16 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
 		$original_file=$conf->don->dir_output.'/'.$original_file;
 	}
 
+	// Wrapping pour les dons
+	else if ($modulepart == 'dolresource' && !empty($conf->resource->dir_output))
+	{
+		if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i',$original_file))
+		{
+			$accessallowed=1;
+		}
+		$original_file=$conf->resource->dir_output.'/'.$original_file;
+	}
+	
 	// Wrapping pour les remises de cheques
 	else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output))
 	{

+ 19 - 6
htdocs/core/lib/functions.lib.php

@@ -280,6 +280,7 @@ function GETPOST($paramname, $check='', $method=0, $filter=NULL, $options=NULL)
     	$relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
     	$relativepathstring = preg_replace('/^\//', '', $relativepathstring);
 	
+        // Code for search criteria persistence.
     	// Retrieve values if restore_lastsearch_values is set and there is saved values
     	if (! empty($_GET['restore_lastsearch_values']) && ! empty($_SESSION['lastsearch_values_'.$relativepathstring]))        // Keep $_GET here
     	{
@@ -5603,20 +5604,32 @@ function verifCond($strRights)
  *
  * @param 	string	$s				String to evaluate
  * @param	int		$returnvalue	0=No return (used to execute eval($a=something)). 1=Value of eval is returned (used to eval($something)).
+ * @param   int     $hideerrors     1=Hide errors
  * @return	mixed					Nothing or return of eval
  */
-function dol_eval($s,$returnvalue=0)
+function dol_eval($s, $returnvalue=0, $hideerrors=1)
 {
 	// Only global variables can be changed by eval function and returned to caller
-	global $langs, $user, $conf;
-	global $leftmenu;
+	global $db, $langs, $user, $conf;
+	global $mainmenu, $leftmenu;
 	global $rights;
 	global $object;
-    global $soc;
+	global $mysoc;
+	
+	global $obj;       // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object      
+	global $soc;       // For backward compatibility
 
 	//print $s."<br>\n";
-	if ($returnvalue) return @eval('return '.$s.';');
-	else @eval($s);
+	if ($returnvalue)
+	{
+	    if ($hideerrors) return @eval('return '.$s.';');
+	    else return eval('return '.$s.';');
+	}
+	else
+	{
+	    if ($hideerrors) @eval($s);
+	    else eval($s);
+	}
 }
 
 /**

+ 52 - 15
htdocs/core/tpl/admin_extrafields_add.tpl.php

@@ -18,10 +18,12 @@
  */
 
 /**
- * The following vars must be defined
+ * The following vars must be defined:
  * $type2label
  * $form
  * $conf, $lang,
+ * The following vars may also be defined:
+ * $elementtype
  */
 
 ?>
@@ -31,15 +33,16 @@
     jQuery(document).ready(function() {
     	function init_typeoffields(type)
     	{
-        	console.log("select new type "+type);
+        	console.log("selected type is "+type);
     		var size = jQuery("#size");
+    		var computed_value = jQuery("#computed_value");
+    		var default_value = jQuery("#default_value");
     		var unique = jQuery("#unique");
     		var required = jQuery("#required");
-    		var default_value = jQuery("#default_value");
     		var alwayseditable = jQuery("#alwayseditable");
     		var list = jQuery("#list");
     		<?php
-    		if((GETPOST('type') != "select") && (GETPOST('type') != "sellist"))
+    		if ((GETPOST('type') != "select") && (GETPOST('type') != "sellist"))
     		{
     			print 'jQuery("#value_choice").hide();';
     		}
@@ -51,6 +54,28 @@
     		}
     		?>
 
+    		// Case of computed field
+    		console.log(type);
+    		if (type == '' || type == 'varchar' || type == 'int' || type == 'double' || type == 'price') { 
+    			jQuery("tr.extra_computed_value").show(); 
+    		} else {
+    			computed_value.val(''); jQuery("tr.extra_computed_value").hide();
+    		} 
+    		if (computed_value.val())
+    		{
+        		console.log("We enter a computed formula");
+        		jQuery("#default_value").val('');
+        		/* jQuery("#unique, #required, #alwayseditable, #ishidden, #list").removeAttr('checked'); */
+        		jQuery("#default_value, #unique, #required, #alwayseditable, #ishidden, #list").attr('disabled', true);
+        		jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_ishidden, tr.extra_list").hide();
+    		}
+    		else
+    		{
+        		console.log("No computed formula");
+        		jQuery("#default_value, #unique, #required, #alwayseditable, #ishidden, #list").attr('disabled', false);
+        		jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_ishidden, tr.extra_list").show();
+    		}
+    		
 			if (type == 'date')          { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
 			else if (type == 'datetime') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
     		else if (type == 'double')   { size.val('24,8').removeAttr('disabled'); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
@@ -65,7 +90,10 @@
 			else if (type == 'checkbox') { size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").show();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
 			else if (type == 'chkbxlst') { size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").show();jQuery("#helplink").hide();}
 			else if (type == 'link')     { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").show();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").show();}
-			else if (type == 'separate') { size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); required.val('').prop('disabled', true); default_value.val('').prop('disabled', true); jQuery("#value_choice").hide();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();}
+			else if (type == 'separate') { 
+				size.val('').prop('disabled', true); unique.removeAttr('checked').prop('disabled', true); required.val('').prop('disabled', true); 
+				jQuery("#value_choice").hide();jQuery("#helpselect").hide();jQuery("#helpsellist").hide();jQuery("#helpchkbxlst").hide();jQuery("#helplink").hide();
+			}
 			else {	// type = string
 				size.val('').prop('disabled', true);
 				unique.removeAttr('disabled');
@@ -73,10 +101,12 @@
 
 			if (type == 'separate')
 			{
-				unique.removeAttr('checked').prop('disabled', true); required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.val('').prop('disabled', true); 
+				required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.val('').prop('disabled', true);
+				jQuery('#size, #default_value').val('').prop('disabled', true); 
 			}
 			else
 			{
+				default_value.removeAttr('disabled');
 				required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); list.val('').removeAttr('disabled'); 
 			}
     	}
@@ -84,6 +114,11 @@
     	jQuery("#type").change(function() {
     		init_typeoffields($(this).val());
     	});
+
+    	// If we enter a formula, we disable other fields
+    	jQuery("#computed_value").keyup(function() {
+    		init_typeoffields(jQuery('#type').val());
+    	});
     });
 </script>
 
@@ -103,9 +138,7 @@
 <?php print $form->selectarray('type',$type2label,GETPOST('type')); ?>
 </td></tr>
 <!-- Size -->
-<tr><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td class="valeur"><input id="size" type="text" name="size" size="5" value="<?php echo (GETPOST('size')?GETPOST('size'):''); ?>"></td></tr>
-<!-- Position -->
-<tr><td><?php echo $langs->trans("Position"); ?></td><td class="valeur"><input type="text" name="pos" size="5" value="<?php echo GETPOST('pos'); ?>"></td></tr>
+<tr class="extra_size"><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td class="valeur"><input id="size" type="text" name="size" size="5" value="<?php echo (GETPOST('size')?GETPOST('size'):''); ?>"></td></tr>
 <!-- Default Value (for select list / radio/ checkbox) -->
 <tr id="value_choice">
 <td>
@@ -124,17 +157,21 @@
     </table>
 </td>
 </tr>
-<!-- Default Value -->
-<tr><td><?php echo $langs->trans("DefaultValue"); ?></td><td class="valeur"><input id="default_value" type="text" name="default_value" size="5" value="<?php echo (GETPOST('"default_value"')?GETPOST('"default_value"'):''); ?>"></td></tr>
+<!-- Position -->
+<tr><td class="titlefield"><?php echo $langs->trans("Position"); ?></td><td class="valeur"><input type="text" name="pos" size="5" value="<?php echo GETPOST('pos'); ?>"></td></tr>
+<!-- Computed Value -->
+<tr class="extra_computed_value"><td><?php echo $form->textwithpicto($langs->trans("ComputedFormula"), $langs->trans("ComputedFormulaDesc"), 1, 'help', '', 0, 2, 'tooltipcompute'); ?></td><td class="valeur"><input id="computed_value" type="text" name="computed_value" class="quatrevingtpercent" value="<?php echo (GETPOST('"computed_value"')?GETPOST('"computed_value"'):''); ?>"></td></tr>
+<!-- Default Value (at sql setup level) -->
+<tr class="extra_default_value"><td><?php echo $langs->trans("DefaultValue").' ('.$langs->trans("Database").')'; ?></td><td class="valeur"><input id="default_value" type="text" name="default_value" size="5" value="<?php echo (GETPOST('"default_value"')?GETPOST('"default_value"'):''); ?>"></td></tr>
 <!-- Unique -->
-<tr><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input id="unique" type="checkbox" name="unique"<?php echo (GETPOST('unique')?' checked':''); ?>></td></tr>
+<tr class="extra_unique"><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input id="unique" type="checkbox" name="unique"<?php echo (GETPOST('unique')?' checked':''); ?>></td></tr>
 <!-- Required -->
-<tr><td><?php echo $langs->trans("Required"); ?></td><td class="valeur"><input id="required" type="checkbox" name="required"<?php echo (GETPOST('required')?' checked':''); ?>></td></tr>
+<tr class="extra_required"><td><?php echo $langs->trans("Required"); ?></td><td class="valeur"><input id="required" type="checkbox" name="required"<?php echo (GETPOST('required')?' checked':''); ?>></td></tr>
 <!-- Always editable -->
-<tr><td><?php echo $langs->trans("AlwaysEditable"); ?></td><td class="valeur"><input id="alwayseditable" type="checkbox" name="alwayseditable"<?php echo ((GETPOST('alwayseditable') || ! GETPOST('button'))?' checked':''); ?>></td></tr>
+<tr class="extra_alwayseditable"><td><?php echo $langs->trans("AlwaysEditable"); ?></td><td class="valeur"><input id="alwayseditable" type="checkbox" name="alwayseditable"<?php echo ((GETPOST('alwayseditable') || ! GETPOST('button'))?' checked':''); ?>></td></tr>
 <!-- Is visible or not -->
 <?php if (! empty($conf->global->MAIN_CAN_HIDE_EXTRAFIELDS)) { ?>
-<tr><td><?php echo $langs->trans("Hidden"); ?></td><td class="valeur"><input id="ishidden" type="checkbox" name="ishidden"<?php echo (GETPOST('ishidden') ?' checked' : ''); ?>></td></tr>
+<tr class="extra_ishidden"><td><?php echo $langs->trans("Hidden"); ?></td><td class="valeur"><input id="ishidden" type="checkbox" name="ishidden"<?php echo (GETPOST('ishidden') ?' checked' : ''); ?>></td></tr>
 <?php } ?>
 <?php if ($conf->global->MAIN_FEATURES_LEVEL >= 2) { ?>
 <!-- By default visible into list -->

+ 52 - 7
htdocs/core/tpl/admin_extrafields_edit.tpl.php

@@ -15,6 +15,16 @@
  * You should have received a copy of the GNU General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
+
+/**
+ * The following vars must be defined:
+ * $type2label
+ * $form
+ * $conf, $lang,
+ * The following vars may also be defined:
+ * $elementtype
+ */
+
 ?>
 
 <!-- BEGIN PHP TEMPLATE admin_extrafields_edit.tpl.php -->
@@ -24,9 +34,10 @@
     	{
         	console.log("select new type "+type);
     		var size = jQuery("#size");
+    		var computed_value = jQuery("#computed_value");
+    		var default_value = jQuery("#default_value");
     		var unique = jQuery("#unique");
     		var required = jQuery("#required");
-    		var default_value = jQuery("#default_value");
     		var alwayseditable = jQuery("#alwayseditable");
     		var list = jQuery("#list");
     		<?php
@@ -42,6 +53,27 @@
     		}
     		?>
 
+    		// Case of computed field
+    		if (type == 'varchar' || type == 'int' || type == 'double' || type == 'price') { 
+    			jQuery("tr.extra_computed_value").show(); 
+    		} else {
+    			computed_value.val(''); jQuery("tr.extra_computed_value").hide();
+    		} 
+    		if (computed_value.val())
+    		{
+        		console.log("We enter a computed formula");
+        		jQuery("#default_value").val('');
+        		/* jQuery("#unique, #required, #alwayseditable, #ishidden, #list").removeAttr('checked'); */
+        		jQuery("#default_value, #unique, #required, #alwayseditable, #ishidden, #list").attr('disabled', true);
+        		jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_ishidden, tr.extra_list").hide();
+    		}
+    		else
+    		{
+        		console.log("No computed formula");
+        		jQuery("#default_value, #unique, #required, #alwayseditable, #ishidden, #list").attr('disabled', false);
+        		jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_ishidden, tr.extra_list").show();
+    		}
+    		
 			if (type == 'date') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide();jQuery("#helpchkbxlst").hide(); }
 			else if (type == 'datetime') { size.val('').prop('disabled', true); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
     		else if (type == 'double')   { size.removeAttr('disabled'); unique.removeAttr('disabled'); jQuery("#value_choice").hide(); jQuery("#helpchkbxlst").hide();}
@@ -65,9 +97,11 @@
 			if (type == 'separate')
 			{
 				required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.val('').prop('disabled', true); 
+				jQuery('#size, #default_value').val('').prop('disabled', true); 
 			}
 			else
 			{
+				default_value.removeAttr('disabled');
 				required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); list.val('').removeAttr('disabled'); 
 			}			
     	}
@@ -75,6 +109,11 @@
     	jQuery("#type").change(function() {
     		init_typeoffields($(this).val());
     	});
+
+    	// If we enter a formula, we disable other fields
+    	jQuery("#computed_value").keyup(function() {
+    		init_typeoffields(jQuery('#type').val());
+    	});    	
     });
 </script>
 
@@ -92,6 +131,8 @@
 <?php
 $type=$extrafields->attribute_type[$attrname];
 $size=$extrafields->attribute_size[$attrname];
+$computed=$extrafields->attribute_computed[$attrname];
+$default=$extrafields->attribute_default[$attrname];
 $unique=$extrafields->attribute_unique[$attrname];
 $required=$extrafields->attribute_required[$attrname];
 $pos=$extrafields->attribute_pos[$attrname];
@@ -156,9 +197,7 @@ else
 ?>
 </td></tr>
 <!-- Size -->
-<tr><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td><input id="size" type="text" name="size" size="5" value="<?php echo $size; ?>"></td></tr>
-<!-- Position -->
-<tr><td><?php echo $langs->trans("Position"); ?></td><td class="valeur"><input type="text" name="pos" size="5" value="<?php  echo $extrafields->attribute_pos[$attrname];  ?>"></td></tr>
+<tr class="extra_size"><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td><input id="size" type="text" name="size" size="5" value="<?php echo $size; ?>"></td></tr>
 <!--  Value (for select list / radio) -->
 <tr id="value_choice">
 <td>
@@ -177,12 +216,18 @@ else
     </table>
 </td>
 </tr>
+<!-- Position -->
+<tr><td class="titlefield"><?php echo $langs->trans("Position"); ?></td><td class="valeur"><input type="text" name="pos" size="5" value="<?php echo dol_escape_htmltag($extrafields->attribute_pos[$attrname]);  ?>"></td></tr>
+<!-- Computed value -->
+<tr class="extra_computed_value"><td><?php echo $form->textwithpicto($langs->trans("ComputedFormula"), $langs->trans("ComputedFormulaDesc"), 1, 'help', '', 0, 2, 'tooltipcompute'); ?></td><td class="valeur"><input id="computed_value" class="quatrevingtpercent" type="text" name="computed_value" value="<?php echo dol_escape_htmltag($computed); ?>"></td></tr>
+<!-- Default value -->
+<!-- Edit of default into sql structure not yet supported -->
 <!-- Unique -->
-<tr><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input id="unique" type="checkbox" name="unique"<?php echo ($unique?' checked':''); ?>></td></tr>
+<tr class="extra_unique"><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input id="unique" type="checkbox" name="unique"<?php echo ($unique?' checked':''); ?>></td></tr>
 <!-- Required -->
-<tr><td><?php echo $langs->trans("Required"); ?></td><td class="valeur"><input id="required" type="checkbox" name="required"<?php echo ($required?' checked':''); ?>></td></tr>
+<tr class="extra_required"><td><?php echo $langs->trans("Required"); ?></td><td class="valeur"><input id="required" type="checkbox" name="required"<?php echo ($required?' checked':''); ?>></td></tr>
 <!-- Always editable -->
-<tr><td><?php echo $langs->trans("AlwaysEditable"); ?></td><td class="valeur"><input id="alwayseditable" type="checkbox" name="alwayseditable"<?php echo ($alwayseditable?' checked':''); ?>></td></tr>
+<tr class="extra_alwayseditable"><td><?php echo $langs->trans("AlwaysEditable"); ?></td><td class="valeur"><input id="alwayseditable" type="checkbox" name="alwayseditable"<?php echo ($alwayseditable?' checked':''); ?>></td></tr>
 <!-- Is visible or not -->
 <?php if (! empty($conf->global->MAIN_CAN_HIDE_EXTRAFIELDS)) { ?>
     <tr><td><?php echo $langs->trans("Hidden"); ?></td><td class="valeur"><input id="ishidden" type="checkbox" name="ishidden"<?php echo ($ishidden ?' checked':''); ?>></td></tr>

+ 5 - 1
htdocs/core/tpl/admin_extrafields_view.tpl.php

@@ -37,12 +37,15 @@ print '<div class="div-table-responsive">';
 print '<table summary="listofattributes" class="noborder" width="100%">';
 
 print '<tr class="liste_titre">';
-print '<td align="left">'.$langs->trans("Position").'</td>';
+print '<td align="left">'.$langs->trans("Position");
+print '<span class="nowrap"><img src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/1downarrow.png" alt="" title="A-Z" class="imgdown"></span>';
+print '</td>';
 print '<td>'.$langs->trans("Label").'</td>';
 print '<td>'.$langs->trans("AttributeCode").'</td>';
 print '<td>'.$langs->trans("Type").'</td>';
 print '<td align="right">'.$langs->trans("Size").'</td>';
 print '<td align="center">'.$langs->trans("Unique").'</td>';
+print '<td>'.$langs->trans("ComputedFormula").'</td>';
 print '<td align="center">'.$langs->trans("Required").'</td>';
 print '<td align="center">'.$langs->trans("AlwaysEditable").'</td>';
 if (! empty($conf->global->MAIN_CAN_HIDE_EXTRAFIELDS)) print '<td align="center">'.$langs->trans("Hidden").'</td>';
@@ -61,6 +64,7 @@ if (count($extrafields->attribute_type))
         print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n";
         print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n";
         print '<td align="center">'.yn($extrafields->attribute_unique[$key])."</td>\n";
+        print '<td>'.dol_trunc($extrafields->attribute_computed[$key], 20)."</td>\n";
         print '<td align="center">'.yn($extrafields->attribute_required[$key])."</td>\n";
         print '<td align="center">'.yn($extrafields->attribute_alwayseditable[$key])."</td>\n";
     	if (! empty($conf->global->MAIN_CAN_HIDE_EXTRAFIELDS)) print '<td align="center">'.yn($extrafields->attribute_hidden[$key])."</td>\n";	// Add hidden option on not working feature. Why hide if user can't see it.

+ 2 - 1
htdocs/expensereport/class/api_expensereports.class.php

@@ -134,7 +134,8 @@ class ExpenseReports extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $expensereport_static = new ExpenseReport($db);

+ 1 - 1
htdocs/fourn/card.php

@@ -130,7 +130,7 @@ if ($object->id > 0)
 	 */
 	$head = societe_prepare_head($object);
 
-	dol_fiche_head($head, 'supplier', $langs->trans("ThirdParty"),0,'company');
+	dol_fiche_head($head, 'supplier', $langs->trans("ThirdParty"), -1, 'company');
 
 	$linkback = '<a href="'.DOL_URL_ROOT.'/societe/list.php">'.$langs->trans("BackToList").'</a>';
 	

+ 2 - 1
htdocs/fourn/class/api_supplier_invoices.class.php

@@ -155,7 +155,8 @@ class SupplierInvoices extends DolibarrApi
         {
             $i = 0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $invoice_static = new FactureFournisseur($db);

+ 12 - 31
htdocs/includes/restler/framework/Luracast/Restler/explorer/css/screen.css

@@ -350,7 +350,7 @@
   font-size: .85em;
   line-height: 1.2em;
   overflow: auto;
-  max-height: 400px;
+  max-height: 200px;
   cursor: pointer;
 }
 .swagger-section .swagger-ui-wrap .model-signature ul.signature-nav {
@@ -743,17 +743,20 @@
   display: inline-block;
   font-size: 0.9em;
 }
-.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header img {
-  display: block;
-  clear: none;
-  float: right;
-}
 .swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header input.submit {
   display: block;
   clear: none;
   float: left;
   padding: 6px 8px;
 }
+.swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content div.sandbox_header span.response_throbber {
+  background-image: url('../images/throbber.gif');
+  width: 128px;
+  height: 16px;
+  display: block;
+  clear: none;
+  float: right;
+}
 .swagger-section .swagger-ui-wrap ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation div.content form input[type='text'].error {
   outline: 2px solid black;
   outline-color: #cc0000;
@@ -1158,7 +1161,7 @@
   cursor: pointer;
 }
 .swagger-section #header {
-  background-color: #646257;
+  background-color: #89bf04;
   padding: 14px;
 }
 .swagger-section #header a#logo {
@@ -1193,7 +1196,7 @@
   padding: 6px 8px;
   font-size: 0.9em;
   color: white;
-  background-color: #000000;
+  background-color: #547f00;
   -moz-border-radius: 4px;
   -webkit-border-radius: 4px;
   -o-border-radius: 4px;
@@ -1202,35 +1205,13 @@
   border-radius: 4px;
 }
 .swagger-section #header form#api_selector .input a#explore:hover {
-  background-color: #a41e22;
+  background-color: #547f00;
 }
 .swagger-section #header form#api_selector .input input {
   font-size: 0.9em;
   padding: 3px;
   margin: 0;
 }
-.swagger-section #footer-nav {
-  margin-top: 50px;
-  color: #bbb;
-  float: left;
-  list-style: none;
-  font-size: 0.8em;
-}
-.swagger-section #footer-nav li {
-  display: block;
-  float: left;
-}
-.swagger-section #footer-nav a {
-  margin-right: 4px;
-  text-decoration: none;
-  font-weight: none;
-  padding: 4px 2px;
-  font-size: 0.9em;
-  color: #999;
-}
-.swagger-section #footer-nav a:hover {
-  color: #555;
-}
 .swagger-section #content_message {
   margin: 10px 15px;
   font-style: italic;

BIN
htdocs/includes/restler/framework/Luracast/Restler/explorer/images/logo_small.png


BIN
htdocs/includes/restler/framework/Luracast/Restler/explorer/images/pet_store_api.png


BIN
htdocs/includes/restler/framework/Luracast/Restler/explorer/images/wordnik_api.png


+ 25 - 9
htdocs/includes/restler/framework/Luracast/Restler/explorer/index.html

@@ -2,8 +2,7 @@
 <html>
 <head>
   <title>Api Explorer</title>
-  <!-- DOL_CHANGE LDR Remove external links <link href='https://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
-  <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">-->
+  <!-- DOL_CHANGE LDR Remove external links <link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>-->
   <link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
   <link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
   <link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
@@ -27,10 +26,11 @@
     $(function () {
       window.swaggerUi = new SwaggerUi({
       url: "resources.json",
+      validatorUrl: null,
       dom_id: "swagger-ui-container",
-      supportedSubmitMethods: ['get', 'post', 'put', 'patch', 'delete'],
+      supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
       onComplete: function(swaggerApi, swaggerUi){
-        log("Loaded Api Explorer");
+        log("Loaded API Explorer");
 
         if(typeof initOAuth == "function") {
           /*
@@ -45,15 +45,19 @@
           hljs.highlightBlock(e)
         });
       },
+      defaultModelRendering: 'model',
       onFailure: function(data) {
-        log("Unable to Load Api Explorer");
+        log("Unable to Load API Explorer");
       },
-      docExpansion: "none"
+      docExpansion: "none",
+      /*showRequestHeaders: true,
+      jsonEditor: true */
+      /*, sorter : "alpha"*/
     });
 
     $('#input_apiKey').change(function() {
       var key = $('#input_apiKey')[0].value;
-
+      log("key: " + key);
       if(key && key.trim() != "") {
         /* DOL_CHANGE LDR We set DOLAPIKEY into header */
         log("added key " + key);
@@ -67,11 +71,15 @@
         console.log("header DOLAPIKEY added with value "+key);
       }
     })
-    
     window.swaggerUi.load();
   });
-    
   </script>
+  
+  <style>
+	.info_title, .info_description, .info_contact, .info_license {
+		display: none;
+	}
+  </style>
 </head>
 
 <body class="swagger-section">
@@ -79,6 +87,14 @@
   <div class="swagger-ui-wrap">
     <a id="logo" href="#">API Explorer</a>
     <form id='api_selector'>
+      <!-- DOL_CHANGE LDR
+      <div class='input icon-btn'>
+        <img id="show-pet-store-icon" src="images/pet_store_api.png" title="Show Swagger Petstore Example Apis">
+      </div>
+      <div class='input icon-btn'>
+        <img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis">
+      </div>
+      -->
       <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="hidden" value="resources.json"/></div>
       <div class='input'><input placeholder="DOLAPIKEY" id="input_apiKey" name="apiKey" type="text"/></div>
       <div class='input'><a id="explore" href="#">Explore</a></div>

+ 54 - 61
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/swagger-oauth.js

@@ -48,72 +48,65 @@ function handleLogin() {
       str += '</label></li>';
       popup.append(str);
     }
-  
-
-    var $win = $(window),
-      dw = $win.width(),
-      dh = $win.height(),
-      st = $win.scrollTop(),
-      dlgWd = popupDialog.outerWidth(),
-      dlgHt = popupDialog.outerHeight(),
-      top = (dh -dlgHt)/2 + st,
-      left = (dw - dlgWd)/2;
-
-    popupDialog.css({
-      top: (top < 0? 0 : top) + 'px',
-      left: (left < 0? 0 : left) + 'px'
-    });
-
-    popupDialog.find('button.api-popup-cancel').click(function() {
-      popupMask.hide();
-      popupDialog.hide();
-    });
-    popupDialog.find('button.api-popup-authbtn').click(function() {
-      popupMask.hide();
-      popupDialog.hide();
-
-      var authSchemes = window.swaggerUi.api.authSchemes;
-      var location = window.location;
-      var locationUrl = location.protocol + '//' + location.host + location.pathname;
-      var redirectUrl = locationUrl.replace("index.html","").concat("/o2c.html").replace("//o2c.html","/o2c.html");
-      var url = null;
-
-      var p = window.swaggerUi.api.authSchemes;
-      for (var key in p) {
-        if (p.hasOwnProperty(key)) {
-          var o = p[key].grantTypes;
-          for(var t in o) {
-            if(o.hasOwnProperty(t) && t === 'implicit') {
-              var dets = o[t];
-              url = dets.loginEndpoint.url + "?response_type=token";
-              window.swaggerUi.tokenName = dets.tokenName;
-            }
+  }
+
+  var $win = $(window),
+    dw = $win.width(),
+    dh = $win.height(),
+    st = $win.scrollTop(),
+    dlgWd = popupDialog.outerWidth(),
+    dlgHt = popupDialog.outerHeight(),
+    top = (dh -dlgHt)/2 + st,
+    left = (dw - dlgWd)/2;
+
+  popupDialog.css({
+    top: (top < 0? 0 : top) + 'px',
+    left: (left < 0? 0 : left) + 'px'
+  });
+
+  popupDialog.find('button.api-popup-cancel').click(function() {
+    popupMask.hide();
+    popupDialog.hide();
+  });
+  popupDialog.find('button.api-popup-authbtn').click(function() {
+    popupMask.hide();
+    popupDialog.hide();
+
+    var authSchemes = window.swaggerUi.api.authSchemes;
+    var host = window.location;
+    var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/"));
+    var redirectUrl = host.protocol + '//' + host.host + pathname + "/o2c.html";
+    var url = null;
+
+    for (var key in authSchemes) {
+      if (authSchemes.hasOwnProperty(key)) {
+        var o = authSchemes[key].grantTypes;
+        for(var t in o) {
+          if(o.hasOwnProperty(t) && t === 'implicit') {
+            var dets = o[t];
+            url = dets.loginEndpoint.url + "?response_type=token";
+            window.swaggerUi.tokenName = dets.tokenName;
           }
         }
       }
-      var scopes = [];
-      var scopeForUrl='';
-      var o = $('.api-popup-scopes').find('input:checked');
-
-      for(var k =0; k < o.length; k++) {
-        scopes.push($(o[k]).attr("scope"));
-        if(k > 0){
-      	  scopeForUrl+=' ';
-        }
-        scopeForUrl+=$(o[k]).attr("scope");
-      }
+    }
+    var scopes = []
+    var o = $('.api-popup-scopes').find('input:checked');
 
-      window.enabledScopes=scopes;
-    
+    for(k =0; k < o.length; k++) {
+      scopes.push($(o[k]).attr("scope"));
+    }
 
-      url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
-      url += '&realm=' + encodeURIComponent(realm);
-      url += '&client_id=' + encodeURIComponent(clientId);
-      url += '&scope=' + encodeURIComponent(scopeForUrl);
+    window.enabledScopes=scopes;
+
+    url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
+    url += '&realm=' + encodeURIComponent(realm);
+    url += '&client_id=' + encodeURIComponent(clientId);
+    url += '&scope=' + encodeURIComponent(scopes);
+
+    window.open(url);
+  });
 
-      window.open(url);
-    });
-  }
   popupMask.show();
   popupDialog.show();
   return;
@@ -211,7 +204,7 @@ function onOAuthComplete(token) {
           }
         });
 
-        window.authorizations.add("key", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header"));
+        window.authorizations.add("oauth2", new ApiKeyAuthorization("Authorization", "Bearer " + b, "header"));
       }
     }
   }

+ 269 - 154
htdocs/includes/restler/framework/Luracast/Restler/explorer/lib/swagger.js

@@ -1,5 +1,5 @@
 // swagger.js
-// version 2.0.30
+// version 2.0.39
 
 var __bind = function(fn, me){
   return function(){
@@ -11,10 +11,20 @@ log = function(){
   log.history = log.history || [];
   log.history.push(arguments);
   if(this.console){
-    console.log( Array.prototype.slice.call(arguments) );
+    console.log( Array.prototype.slice.call(arguments)[0] );
   }
 };
 
+// if you want to apply conditional formatting of parameter values
+parameterMacro = function(value) {
+  return value;
+}
+
+// if you want to apply conditional formatting of model property values
+modelPropertyMacro = function(value) {
+  return value;
+}
+
 if (!Array.prototype.indexOf) {
   Array.prototype.indexOf = function(obj, start) {
     for (var i = (start || 0), j = this.length; i < j; i++) {
@@ -45,48 +55,50 @@ if (!('map' in Array.prototype)) {
 }
 
 Object.keys = Object.keys || (function () {
-    var hasOwnProperty = Object.prototype.hasOwnProperty,
-        hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
-        DontEnums = [
-            'toString',
-            'toLocaleString',
-            'valueOf',
-            'hasOwnProperty',
-            'isPrototypeOf',
-            'propertyIsEnumerable',
-            'constructor'
-        ],
-        DontEnumsLength = DontEnums.length;
-  
-    return function (o) {
-        if (typeof o != "object" && typeof o != "function" || o === null)
-            throw new TypeError("Object.keys called on a non-object");
-     
-        var result = [];
-        for (var name in o) {
-            if (hasOwnProperty.call(o, name))
-                result.push(name);
-        }
-     
-        if (hasDontEnumBug) {
-            for (var i = 0; i < DontEnumsLength; i++) {
-                if (hasOwnProperty.call(o, DontEnums[i]))
-                    result.push(DontEnums[i]);
-            }   
-        }
-     
-        return result;
-    };
-})();
+  var hasOwnProperty = Object.prototype.hasOwnProperty,
+    hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
+    DontEnums = [
+      'toString',
+      'toLocaleString',
+      'valueOf',
+      'hasOwnProperty',
+      'isPrototypeOf',
+      'propertyIsEnumerable',
+      'constructor'
+    ],
+  DontEnumsLength = DontEnums.length;
+
+  return function (o) {
+    if (typeof o != "object" && typeof o != "function" || o === null)
+      throw new TypeError("Object.keys called on a non-object");
+
+    var result = [];
+    for (var name in o) {
+      if (hasOwnProperty.call(o, name))
+        result.push(name);
+    }
+
+    if (hasDontEnumBug) {
+      for (var i = 0; i < DontEnumsLength; i++) {
+        if (hasOwnProperty.call(o, DontEnums[i]))
+          result.push(DontEnums[i]);
+      }
+    }
 
+    return result;
+  };
+})();
 
 var SwaggerApi = function(url, options) {
+  this.isBuilt = false;
   this.url = null;
   this.debug = false;
   this.basePath = null;
   this.authorizations = null;
   this.authorizationScheme = null;
   this.info = null;
+  this.useJQuery = false;
+  this.modelsArray = [];
 
   options = (options||{});
   if (url)
@@ -103,13 +115,20 @@ var SwaggerApi = function(url, options) {
   if (options.success != null)
     this.success = options.success;
 
+  if (typeof options.useJQuery === 'boolean')
+    this.useJQuery = options.useJQuery;
+
   this.failure = options.failure != null ? options.failure : function() {};
   this.progress = options.progress != null ? options.progress : function() {};
-  if (options.success != null)
+  if (options.success != null) {
     this.build();
+    this.isBuilt = true;
+  }
 }
 
 SwaggerApi.prototype.build = function() {
+  if(this.isBuilt)
+    return this;
   var _this = this;
   this.progress('fetching resource list: ' + this.url);
   var obj = {
@@ -117,7 +136,7 @@ SwaggerApi.prototype.build = function() {
     url: this.url,
     method: "get",
     headers: {
-      accept: "application/json"
+      accept: "application/json,application/json;charset=\"utf-8\",*/*"
     },
     on: {
       error: function(response) {
@@ -154,6 +173,7 @@ SwaggerApi.prototype.buildFromSpec = function(response) {
   }
   this.apis = {};
   this.apisArray = [];
+  this.consumes = response.consumes;
   this.produces = response.produces;
   this.authSchemes = response.authorizations;
   if (response.info != null) {
@@ -171,13 +191,13 @@ SwaggerApi.prototype.buildFromSpec = function(response) {
       }
     }
   }
-  if (response.basePath) {
+  if (response.basePath)
     this.basePath = response.basePath;
-  } else if (this.url.indexOf('?') > 0) {
+  else if (this.url.indexOf('?') > 0)
     this.basePath = this.url.substring(0, this.url.lastIndexOf('?'));
-  } else {
+  else
     this.basePath = this.url;
-  }
+
   if (isApi) {
     var newName = response.resourcePath.replace(/\//g, '');
     this.resourcePath = response.resourcePath;
@@ -272,7 +292,6 @@ SwaggerApi.prototype.fail = function(message) {
 
 SwaggerApi.prototype.setConsolidatedModels = function() {
   var model, modelName, resource, resource_name, _i, _len, _ref, _ref1, _results;
-  this.modelsArray = [];
   this.models = {};
   _ref = this.apis;
   for (resource_name in _ref) {
@@ -317,8 +336,8 @@ var SwaggerResource = function(resourceObj, api) {
   var _this = this;
   this.api = api;
   this.api = this.api;
-  produces = [];
-  consumes = [];
+  consumes = (this.consumes | []);
+  produces = (this.produces | []);
   this.path = this.api.resourcePath != null ? this.api.resourcePath : resourceObj.path;
   this.description = resourceObj.description;
 
@@ -349,7 +368,7 @@ var SwaggerResource = function(resourceObj, api) {
       method: "get",
       useJQuery: this.useJQuery,
       headers: {
-        accept: "application/json"
+        accept: "application/json,application/json;charset=\"utf-8\",*/*"
       },
       on: {
         response: function(resp) {
@@ -368,22 +387,28 @@ var SwaggerResource = function(resourceObj, api) {
   }
 }
 
-SwaggerResource.prototype.getAbsoluteBasePath = function(relativeBasePath) {
-  var parts, pos, url;
+SwaggerResource.prototype.getAbsoluteBasePath = function (relativeBasePath) {
+  var pos, url;
   url = this.api.basePath;
   pos = url.lastIndexOf(relativeBasePath);
-  if (pos === -1) {
-    parts = url.split("/");
-    url = parts[0] + "//" + parts[2];
-    if (relativeBasePath.indexOf("/") === 0) {
-      return url + relativeBasePath;
-    } else {
-      return url + "/" + relativeBasePath;
-    }
-  } else if (relativeBasePath === "/") {
-    return url.substring(0, pos);
-  } else {
-    return url.substring(0, pos) + relativeBasePath;
+  var parts = url.split("/");
+  var rootUrl = parts[0] + "//" + parts[2];
+
+  if(relativeBasePath.indexOf("http") === 0)
+    return relativeBasePath;
+  if(relativeBasePath === "/")
+    return rootUrl;
+  if(relativeBasePath.substring(0, 1) == "/") {
+    // use root + relative
+    return rootUrl + relativeBasePath;
+  }
+  else {
+    var pos = this.basePath.lastIndexOf("/");
+    var base = this.basePath.substring(0, pos);
+    if(base.substring(base.length - 1) == "/")
+      return base + relativeBasePath;
+    else
+      return base + "/" + relativeBasePath;
   }
 };
 
@@ -478,8 +503,7 @@ SwaggerResource.prototype.addOperations = function(resource_path, ops, consumes,
 
 SwaggerResource.prototype.sanitize = function(nickname) {
   var op;
-  op = nickname.replace(/[\s!@#$%^&*()_+=\[{\]};:<>|./?,\\'""-]/g, '_');
-  //'
+  op = nickname.replace(/[\s!@#$%^&*()_+=\[{\]};:<>|.\/?,\\'""-]/g, '_');
   op = op.replace(/((_){2,})/g, '_');
   op = op.replace(/^(_)*/g, '');
   op = op.replace(/([_])*$/g, '');
@@ -584,6 +608,7 @@ var SwaggerModelProperty = function(name, obj) {
   this.isCollection = this.dataType && (this.dataType.toLowerCase() === 'array' || this.dataType.toLowerCase() === 'list' || this.dataType.toLowerCase() === 'set');
   this.descr = obj.description;
   this.required = obj.required;
+  this.defaultValue = modelPropertyMacro(obj.defaultValue);
   if (obj.items != null) {
     if (obj.items.type != null) {
       this.refDataType = obj.items.type;
@@ -629,7 +654,9 @@ SwaggerModelProperty.prototype.getSampleValue = function(modelsToIgnore) {
 
 SwaggerModelProperty.prototype.toSampleValue = function(value) {
   var result;
-  if (value === "integer") {
+  if ((typeof this.defaultValue !== 'undefined') && this.defaultValue !== null) {
+    result = this.defaultValue;
+  } else if (value === "integer") {
     result = 0;
   } else if (value === "boolean") {
     result = false;
@@ -759,6 +786,7 @@ var SwaggerOperation = function(nickname, path, method, parameters, summary, not
         }
       }
     }
+    param.defaultValue = parameterMacro(param.defaultValue);
   }
   this.resource[this.nickname] = function(args, callback, error) {
     return _this["do"](args, callback, error);
@@ -812,7 +840,7 @@ SwaggerOperation.prototype.getSampleJSON = function(type, models) {
       else
         return JSON.stringify(val, null, 2);
     }
-    else 
+    else
       return val;
   }
 };
@@ -1073,7 +1101,7 @@ SwaggerOperation.prototype.formatXml = function(xml) {
 var SwaggerRequest = function(type, url, params, opts, successCallback, errorCallback, operation, execution) {
   var _this = this;
   var errors = [];
-  this.useJQuery = (typeof operation.useJQuery !== 'undefined' ? operation.useJQuery : null);
+  this.useJQuery = (typeof operation.resource.useJQuery !== 'undefined' ? operation.resource.useJQuery : null);
   this.type = (type||errors.push("SwaggerRequest type is required (get/post/put/delete/patch/options)."));
   this.url = (url||errors.push("SwaggerRequest url is required."));
   this.params = params;
@@ -1090,96 +1118,59 @@ var SwaggerRequest = function(type, url, params, opts, successCallback, errorCal
 
   this.type = this.type.toUpperCase();
 
-  var myHeaders = {};
+  // set request, response content type headers
+  var headers = this.setHeaders(params, this.operation);
   var body = params.body;
-  var parent = params["parent"];
-  var requestContentType = "application/json";
-
-  var formParams = [];
-  var fileParams = [];
-  var params = this.operation.parameters;
 
-
-  for(var i = 0; i < params.length; i++) {
-    var param = params[i];
-    if(param.paramType === "form")
-      formParams.push(param);
-    else if(param.paramType === "file")
-      fileParams.push(param);
-  }
-
-
-  if (body && (this.type === "POST" || this.type === "PUT" || this.type === "PATCH")) {
-    if (this.opts.requestContentType) {
-      requestContentType = this.opts.requestContentType;
-    }
-  } else {
-    // if any form params, content type must be set
-    if(formParams.length > 0) {
-      if(fileParams.length > 0)
-        requestContentType = "multipart/form-data";
-      else
-        requestContentType = "application/x-www-form-urlencoded";
+  // encode the body for form submits
+  if (headers["Content-Type"]) {
+    var values = {};
+    var i;
+    var operationParams = this.operation.parameters;
+    for(i = 0; i < operationParams.length; i++) {
+      var param = operationParams[i];
+      if(param.paramType === "form")
+        values[param.name] = param;
     }
-    else if (this.type != "DELETE")
-      requestContentType = null;
-  }
 
-  if (requestContentType && this.operation.consumes) {
-    if (this.operation.consumes[requestContentType] === 'undefined') {
-      log("server doesn't consume " + requestContentType + ", try " + JSON.stringify(this.operation.consumes));
-      if (this.requestContentType === null) {
-        requestContentType = this.operation.consumes[0];
+    if(headers["Content-Type"].indexOf("application/x-www-form-urlencoded") === 0) {
+      var encoded = "";
+      var key;
+      for(key in values) {
+        value = this.params[key];
+        if(typeof value !== 'undefined'){
+          if(encoded !== "")
+            encoded += "&";
+          encoded += encodeURIComponent(key) + '=' + encodeURIComponent(value);
+        }
       }
+      body = encoded;
     }
-  }
-
-  var responseContentType = null;
-  if (this.opts.responseContentType) {
-    responseContentType = this.opts.responseContentType;
-  } else {
-    responseContentType = "application/json";
-  }
-  if (responseContentType && this.operation.produces) {
-    if (this.operation.produces[responseContentType] === 'undefined') {
-      log("server can't produce " + responseContentType);
-    }
-  }
-  if (requestContentType && requestContentType.indexOf("application/x-www-form-urlencoded") === 0) {
-    var fields = {};
-    var possibleParams = {};
-    var values = {};
-    var key;
-    for(key in formParams){
-      var param = formParams[key];
-      values[param.name] = param;
-    }
-
-    var encoded = "";
-    var key;
-    for(key in values) {
-      value = this.params[key];
-      if(typeof value !== 'undefined'){
-        if(encoded !== "")
-          encoded += "&";
-        encoded += encodeURIComponent(key) + '=' + encodeURIComponent(value);
+    else if (headers["Content-Type"].indexOf("multipart/form-data") === 0) {
+      // encode the body for form submits
+      var data = "";
+      var boundary = "----SwaggerFormBoundary" + Date.now();
+      var key;
+      for(key in values) {
+        value = this.params[key];
+        if(typeof value !== 'undefined') {
+          data += '--' + boundary + '\n';
+          data += 'Content-Disposition: form-data; name="' + key + '"';
+          data += '\n\n';
+          data += value + "\n";
+        }
       }
+      data += "--" + boundary + "--\n";
+      headers["Content-Type"] = "multipart/form-data; boundary=" + boundary;
+      body = data;
     }
-    body = encoded;
   }
-  var name;
-  for (name in this.headers)
-    myHeaders[name] = this.headers[name];
-  if ((requestContentType && body !== "") || (requestContentType === "application/x-www-form-urlencoded"))
-    myHeaders["Content-Type"] = requestContentType;
-  if (responseContentType)
-    myHeaders["Accept"] = responseContentType;
 
   if (!((this.headers != null) && (this.headers.mock != null))) {
     obj = {
       url: this.url,
       method: this.type,
-      headers: myHeaders,
+      headers: headers,
       body: body,
       useJQuery: this.useJQuery,
       on: {
@@ -1216,6 +1207,77 @@ var SwaggerRequest = function(type, url, params, opts, successCallback, errorCal
   }
 };
 
+SwaggerRequest.prototype.setHeaders = function(params, operation) {
+  // default type
+  var accepts = "application/json";
+  var consumes = "application/json";
+
+  var allDefinedParams = this.operation.parameters;
+  var definedFormParams = [];
+  var definedFileParams = [];
+  var body = params.body;
+  var headers = {};
+
+  // get params from the operation and set them in definedFileParams, definedFormParams, headers
+  var i;
+  for(i = 0; i < allDefinedParams.length; i++) {
+    var param = allDefinedParams[i];
+    if(param.paramType === "form")
+      definedFormParams.push(param);
+    else if(param.paramType === "file")
+      definedFileParams.push(param);
+    else if(param.paramType === "header" && this.params.headers) {
+      var key = param.name;
+      var headerValue = this.params.headers[param.name];
+      if(typeof this.params.headers[param.name] !== 'undefined')
+        headers[key] = headerValue;
+    }
+  }
+
+  // if there's a body, need to set the accepts header via requestContentType
+  if (body && (this.type === "POST" || this.type === "PUT" || this.type === "PATCH" || this.type === "DELETE")) {
+    if (this.opts.requestContentType)
+      consumes = this.opts.requestContentType;
+  } else {
+    // if any form params, content type must be set
+    if(definedFormParams.length > 0) {
+      if(definedFileParams.length > 0)
+        consumes = "multipart/form-data";
+      else
+        consumes = "application/x-www-form-urlencoded";
+    }
+    else if (this.type === "DELETE")
+      body = "{}";
+    else if (this.type != "DELETE")
+      accepts = null;
+  }
+
+  if (consumes && this.operation.consumes) {
+    if (this.operation.consumes.indexOf(consumes) === -1) {
+      log("server doesn't consume " + consumes + ", try " + JSON.stringify(this.operation.consumes));
+      consumes = this.operation.consumes[0];
+    }
+  }
+
+  if (this.opts.responseContentType) {
+    accepts = this.opts.responseContentType;
+  } else {
+    accepts = "application/json";
+  }
+  if (accepts && this.operation.produces) {
+    if (this.operation.produces.indexOf(accepts) === -1) {
+      log("server can't produce " + accepts);
+      accepts = this.operation.produces[0];
+    }
+  }
+
+  if ((consumes && body !== "") || (consumes === "application/x-www-form-urlencoded"))
+    headers["Content-Type"] = consumes;
+  if (accepts)
+    headers["Accept"] = accepts;
+  return headers;
+}
+
 SwaggerRequest.prototype.asCurl = function() {
   var results = [];
   if(this.headers) {
@@ -1259,9 +1321,16 @@ SwaggerHttp.prototype.isIE8 = function() {
 };
 
 /*
- * JQueryHttpClient lets a browser take advantage of JQuery's cross-browser magic
+ * JQueryHttpClient lets a browser take advantage of JQuery's cross-browser magic.
+ * NOTE: when jQuery is available it will export both '$' and 'jQuery' to the global space.
+ *       Since we are using closures here we need to alias it for internal use.
  */
-var JQueryHttpClient = function(options) {}
+var JQueryHttpClient = function(options) {
+  "use strict";
+  if(!jQuery){
+    var jQuery = window.jQuery;
+  }
+}
 
 JQueryHttpClient.prototype.execute = function(obj) {
   var cb = obj.on;
@@ -1335,8 +1404,8 @@ JQueryHttpClient.prototype.execute = function(obj) {
       return cb.response(out);
   };
 
-  $.support.cors = true;
-  return $.ajax(obj);
+  jQuery.support.cors = true;
+  return jQuery.ajax(obj);
 }
 
 /*
@@ -1411,11 +1480,36 @@ ShredHttpClient.prototype.execute = function(obj) {
     return out;
   };
 
+  // Transform an error into a usable response-like object
+  var transformError = function(error) {
+    var out = {
+      // Default to a status of 0 - The client will treat this as a generic permissions sort of error
+      status: 0,
+      data: error.message || error
+    };
+
+    if(error.code) {
+      out.obj = error;
+
+      if(error.code === 'ENOTFOUND' || error.code === 'ECONNREFUSED' ) {
+        // We can tell the client that this should be treated as a missing resource and not as a permissions thing
+        out.status = 404;
+      }
+    }
+
+    return out;
+  };
+
   res = {
     error: function(response) {
       if (obj)
         return cb.error(transform(response));
     },
+    // Catch the Shred error raised when the request errors as it is made (i.e. No Response is coming)
+    request_error: function(err) {
+      if(obj)
+        return cb.error(transformError(err));
+    },
     redirect: function(response) {
       if (obj)
         return cb.redirect(transform(response));
@@ -1452,26 +1546,42 @@ SwaggerAuthorizations.prototype.remove = function(name) {
 };
 
 SwaggerAuthorizations.prototype.apply = function(obj, authorizations) {
-  status = null;
+  var status = null;
   var key;
-  for (key in this.authz) {
-    value = this.authz[key];
-    result = value.apply(obj, authorizations);
-    if (result === false)
-      status = false;
-    if (result === true)
-      status = true;
+
+  // if the "authorizations" key is undefined, or has an empty array, add all keys
+  if(typeof authorizations === 'undefined' || Object.keys(authorizations).length == 0) {
+    for (key in this.authz) {
+      value = this.authz[key];
+      result = value.apply(obj, authorizations);
+      if (result === true)
+        status = true;
+    }
   }
+  else {
+    for(name in authorizations) {
+      for (key in this.authz) {
+        if(key == name) {
+          value = this.authz[key];
+          result = value.apply(obj, authorizations);
+          if (result === true)
+            status = true;
+        }
+      }      
+    }
+  }
+
   return status;
 };
 
 /**
  * ApiKeyAuthorization allows a query param or header to be injected
  */
-var ApiKeyAuthorization = function(name, value, type) {
+var ApiKeyAuthorization = function(name, value, type, delimiter) {
   this.name = name;
   this.value = value;
   this.type = type;
+  this.delimiter = delimiter;
 };
 
 ApiKeyAuthorization.prototype.apply = function(obj, authorizations) {
@@ -1482,7 +1592,12 @@ ApiKeyAuthorization.prototype.apply = function(obj, authorizations) {
       obj.url = obj.url + "?" + this.name + "=" + this.value;
     return true;
   } else if (this.type === "header") {
-    obj.headers[this.name] = this.value;
+    if(typeof obj.headers[this.name] !== 'undefined') {
+      if(typeof this.delimiter !== 'undefined')
+        obj.headers[this.name] = obj.headers[this.name] + this.delimiter +  this.value;
+    }
+    else
+      obj.headers[this.name] = this.value;
     return true;
   }
 };

+ 190 - 141
htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.js

@@ -1,5 +1,5 @@
 // swagger-ui.js
-// version 2.0.17
+// version 2.0.23
 $(function() {
 
 	// Helper function for vertically aligning DOM elements
@@ -68,7 +68,7 @@ log = function(){
   log.history = log.history || [];
   log.history.push(arguments);
   if(this.console){
-    console.log( Array.prototype.slice.call(arguments) );
+    console.log( Array.prototype.slice.call(arguments)[0] );
   }
 };
 
@@ -240,67 +240,74 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
 function program1(depth0,data) {
   
   var buffer = "", stack1, stack2;
-  buffer += "\n                ";
+  buffer += "\n    <div class=\"info_title\">"
+    + escapeExpression(((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.title)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
+    + "</div>\n    <div class=\"info_description\">";
+  stack2 = ((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.description)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1);
+  if(stack2 || stack2 === 0) { buffer += stack2; }
+  buffer += "</div>\n    ";
   stack2 = helpers['if'].call(depth0, ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.termsOfServiceUrl), {hash:{},inverse:self.noop,fn:self.program(2, program2, data),data:data});
   if(stack2 || stack2 === 0) { buffer += stack2; }
-  buffer += "\n                ";
+  buffer += "\n    ";
   stack2 = helpers['if'].call(depth0, ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.contact), {hash:{},inverse:self.noop,fn:self.program(4, program4, data),data:data});
   if(stack2 || stack2 === 0) { buffer += stack2; }
-  buffer += "\n                ";
+  buffer += "\n    ";
   stack2 = helpers['if'].call(depth0, ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.license), {hash:{},inverse:self.noop,fn:self.program(6, program6, data),data:data});
   if(stack2 || stack2 === 0) { buffer += stack2; }
-  buffer += "\n            ";
+  buffer += "\n  ";
   return buffer;
   }
 function program2(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += "<li><a href=\""
+  buffer += "<div class=\"info_tos\"><a href=\""
     + escapeExpression(((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.termsOfServiceUrl)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
-    + "\" title=\"Terms of Service\"><i class=\"fa fa-lg fa-bullhorn\"></i> Terms</a></li>";
+    + "\">Terms of service</a></div>";
   return buffer;
   }
 
 function program4(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += "<li><a href=\"mailto:"
+  buffer += "<div class='info_contact'><a href=\"mailto:"
     + escapeExpression(((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.contact)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
-    + "\"><i class=\"fa fa-lg fa-send\"></i> Contact</a></li>";
+    + "\">Contact the developer</a></div>";
   return buffer;
   }
 
 function program6(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += "<li><a href=\""
+  buffer += "<div class='info_license'><a href='"
     + escapeExpression(((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.licenseUrl)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
-    + "\" title=\""
+    + "'>"
     + escapeExpression(((stack1 = ((stack1 = depth0.info),stack1 == null || stack1 === false ? stack1 : stack1.license)),typeof stack1 === functionType ? stack1.apply(depth0) : stack1))
-    + "\"><i class=\"fa fa-lg fa-certificate\"></i> License</a></li>";
+    + "</a></div>";
   return buffer;
   }
 
 function program8(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += " v";
+  buffer += "\n        , <span style=\"font-variant: small-caps\">api version</span>: ";
   if (stack1 = helpers.apiVersion) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.apiVersion; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
-  buffer += escapeExpression(stack1);
+  buffer += escapeExpression(stack1)
+    + "\n        ";
   return buffer;
   }
 
-  buffer += "<div class='info' id='api_info'>\n</div>\n<div class='container' id='resources_container'>\n    <ul id='resources'>\n    </ul>\n\n    <div class=\"footer\">\n        <ul id=\"footer-nav\">\n            ";
+  buffer += "<div class='info' id='api_info'>\n  ";
   stack1 = helpers['if'].call(depth0, depth0.info, {hash:{},inverse:self.noop,fn:self.program(1, program1, data),data:data});
   if(stack1 || stack1 === 0) { buffer += stack1; }
-  buffer += "\n            <li>\n                ";
+  buffer += "\n</div>\n<div class='container' id='resources_container'>\n    <ul id='resources'>\n    </ul>\n\n    <div class=\"footer\">\n        <br>\n        <br>\n        <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: ";
   if (stack1 = helpers.basePath) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.basePath; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
-  buffer += escapeExpression(stack1);
+  buffer += escapeExpression(stack1)
+    + "\n        ";
   stack1 = helpers['if'].call(depth0, depth0.apiVersion, {hash:{},inverse:self.noop,fn:self.program(8, program8, data),data:data});
   if(stack1 || stack1 === 0) { buffer += stack1; }
-  buffer += " Powered by Restler & Swagger\n            </li>\n        </ul>\n    </div>\n</div>\n";
+  buffer += "]</h4>\n    </div>\n</div>\n";
   return buffer;
   });
 })();
@@ -389,7 +396,7 @@ function program18(depth0,data) {
 function program20(depth0,data) {
   
   
-  return "\n          <div class='sandbox_header'>\n            <input class='submit' name='commit' type='button' value='Try it out!' />\n            <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n            <img alt='Throbber' class='response_throbber' src='images/throbber.gif' style='display:none' />\n          </div>\n          ";
+  return "\n          <div class='sandbox_header'>\n            <input class='submit' name='commit' type='button' value='Try it out!' />\n            <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n            <span class='response_throbber' style='display:none'></span>\n          </div>\n          ";
   }
 
   buffer += "\n  <ul class='operations' >\n    <li class='";
@@ -555,7 +562,7 @@ function program9(depth0,data) {
   
   var buffer = "", stack1;
   buffer += "\n		";
-  stack1 = helpers['if'].call(depth0, depth0.defaultValue, {hash:{},inverse:self.program(12, program12, data),fn:self.program(10, program10, data),data:data});
+  stack1 = helpers['if'].call(depth0, depth0.isFile, {hash:{},inverse:self.program(10, program10, data),fn:self.program(2, program2, data),data:data});
   if(stack1 || stack1 === 0) { buffer += stack1; }
   buffer += "\n	";
   return buffer;
@@ -563,7 +570,16 @@ function program9(depth0,data) {
 function program10(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += "\n			<input class='parameter' minlength='0' name='";
+  buffer += "\n			";
+  stack1 = helpers['if'].call(depth0, depth0.defaultValue, {hash:{},inverse:self.program(13, program13, data),fn:self.program(11, program11, data),data:data});
+  if(stack1 || stack1 === 0) { buffer += stack1; }
+  buffer += "\n		";
+  return buffer;
+  }
+function program11(depth0,data) {
+  
+  var buffer = "", stack1;
+  buffer += "\n				<input class='parameter' minlength='0' name='";
   if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
@@ -571,18 +587,18 @@ function program10(depth0,data) {
   if (stack1 = helpers.defaultValue) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.defaultValue; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "'/>\n		";
+    + "'/>\n			";
   return buffer;
   }
 
-function program12(depth0,data) {
+function program13(depth0,data) {
   
   var buffer = "", stack1;
-  buffer += "\n			<input class='parameter' minlength='0' name='";
+  buffer += "\n				<input class='parameter' minlength='0' name='";
   if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "' placeholder='' type='text' value=''/>\n		";
+    + "' placeholder='' type='text' value=''/>\n			";
   return buffer;
   }
 
@@ -1057,23 +1073,19 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
 
 function program1(depth0,data) {
   
-  var buffer = "", stack1;
-  buffer += " : ";
-  if (stack1 = helpers.description) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
-  else { stack1 = depth0.description; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
-  if(stack1 || stack1 === 0) { buffer += stack1; }
-  return buffer;
+  
+  return " : ";
   }
 
   buffer += "<div class='heading'>\n  <h2>\n    <a href='#!/";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "' onclick=\"Docs.toggleEndpointListForResource('";
+    + "' class=\"toggleEndpointList\" data-id=\"";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "');\">";
+    + "\">";
   if (stack1 = helpers.name) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.name; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
@@ -1083,6 +1095,9 @@ function program1(depth0,data) {
   else { stack1 = depth0.description; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   if (!helpers.description) { stack1 = blockHelperMissing.call(depth0, stack1, options); }
   if(stack1 || stack1 === 0) { buffer += stack1; }
+  if (stack1 = helpers.description) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
+  else { stack1 = depth0.description; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
+  if(stack1 || stack1 === 0) { buffer += stack1; }
   buffer += "\n  </h2>\n  <ul class='options'>\n    <li>\n      <a href='#!/";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
@@ -1091,19 +1106,19 @@ function program1(depth0,data) {
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "'\n         onclick=\"Docs.toggleEndpointListForResource('";
+    + "' class=\"toggleEndpointList\" data-id=\"";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "');\">Show/Hide</a>\n    </li>\n    <li>\n      <a href='#' onclick=\"Docs.collapseOperationsForResource('";
+    + "\">Show/Hide</a>\n    </li>\n    <li>\n      <a href='#' class=\"collapseResource\" data-id=\"";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "'); return false;\">\n        List Operations\n      </a>\n    </li>\n    <li>\n      <a href='#' onclick=\"Docs.expandOperationsForResource('";
+    + "\">\n        List Operations\n      </a>\n    </li>\n    <li>\n      <a href='#' class=\"expandResource\" data-id=";
   if (stack1 = helpers.id) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.id; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
-    + "'); return false;\">\n        Expand Operations\n      </a>\n    </li>\n    <li>\n      <a href='";
+    + ">\n        Expand Operations\n      </a>\n    </li>\n    <li>\n      <a href='";
   if (stack1 = helpers.url) { stack1 = stack1.call(depth0, {hash:{},data:data}); }
   else { stack1 = depth0.url; stack1 = typeof stack1 === functionType ? stack1.apply(depth0) : stack1; }
   buffer += escapeExpression(stack1)
@@ -1203,18 +1218,18 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
 
 
 
-// Generated by CoffeeScript 1.5.0
+// Generated by CoffeeScript 1.6.3
 (function() {
-  var ContentTypeView, HeaderView, MainView, OperationView, ParameterContentTypeView, ParameterView, ResourceView, ResponseContentTypeView, SignatureView, StatusCodeView, SwaggerUi,
+  var ContentTypeView, HeaderView, MainView, OperationView, ParameterContentTypeView, ParameterView, ResourceView, ResponseContentTypeView, SignatureView, StatusCodeView, SwaggerUi, _ref, _ref1, _ref10, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9,
     __hasProp = {}.hasOwnProperty,
     __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
 
   SwaggerUi = (function(_super) {
-
     __extends(SwaggerUi, _super);
 
     function SwaggerUi() {
-      SwaggerUi.__super__.constructor.apply(this, arguments);
+      _ref = SwaggerUi.__super__.constructor.apply(this, arguments);
+      return _ref;
     }
 
     SwaggerUi.prototype.dom_id = "swagger_ui";
@@ -1263,9 +1278,9 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     SwaggerUi.prototype.load = function() {
-      var url, _ref;
-      if ((_ref = this.mainView) != null) {
-        _ref.clear();
+      var url, _ref1;
+      if ((_ref1 = this.mainView) != null) {
+        _ref1.clear();
       }
       url = this.options.url;
       if (url.indexOf("http") !== 0) {
@@ -1281,10 +1296,10 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     SwaggerUi.prototype.render = function() {
       var _this = this;
       this.showMessage('Finished Loading Resource Information. Rendering Swagger UI...');
-      this.headerView.updateInfo(this.api.info);
       this.mainView = new MainView({
         model: this.api,
-        el: $('#' + this.dom_id)
+        el: $('#' + this.dom_id),
+        swaggerOptions: this.options
       }).render();
       this.showMessage();
       switch (this.options.docExpansion) {
@@ -1355,11 +1370,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   window.SwaggerUi = SwaggerUi;
 
   HeaderView = (function(_super) {
-
     __extends(HeaderView, _super);
 
     function HeaderView() {
-      HeaderView.__super__.constructor.apply(this, arguments);
+      _ref1 = HeaderView.__super__.constructor.apply(this, arguments);
+      return _ref1;
     }
 
     HeaderView.prototype.events = {
@@ -1412,40 +1427,56 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
       }
     };
 
-    HeaderView.prototype.updateInfo = function(info) {
-      if (info.title != null) {
-        $('#logo').text(info.title);
-      }
-      if (info.description != null) {
-        $('#logo').attr('title', info.description);
-      }
-      if (info.termsOfServiceUrl != null) {
-        return $('#logo').attr('href', info.termsOfServiceUrl);
-      }
-    };
-
     return HeaderView;
 
   })(Backbone.View);
 
   MainView = (function(_super) {
+    var sorters;
 
     __extends(MainView, _super);
 
     function MainView() {
-      MainView.__super__.constructor.apply(this, arguments);
+      _ref2 = MainView.__super__.constructor.apply(this, arguments);
+      return _ref2;
     }
 
-    MainView.prototype.initialize = function() {};
+    sorters = {
+      'alpha': function(a, b) {
+        return a.path.localeCompare(b.path);
+      },
+      'method': function(a, b) {
+        return a.method.localeCompare(b.method);
+      }
+    };
+
+    MainView.prototype.initialize = function(opts) {
+      var route, sorter, sorterName, _i, _len, _ref3;
+      if (opts == null) {
+        opts = {};
+      }
+      if (opts.swaggerOptions.sorter) {
+        sorterName = opts.swaggerOptions.sorter;
+        sorter = sorters[sorterName];
+        _ref3 = this.model.apisArray;
+        for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
+          route = _ref3[_i];
+          route.operationsArray.sort(sorter);
+        }
+        if (sorterName === "alpha") {
+          return this.model.apisArray.sort(sorter);
+        }
+      }
+    };
 
     MainView.prototype.render = function() {
-      var counter, id, resource, resources, _i, _len, _ref;
+      var counter, id, resource, resources, _i, _len, _ref3;
       $(this.el).html(Handlebars.templates.main(this.model));
       resources = {};
       counter = 0;
-      _ref = this.model.apisArray;
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        resource = _ref[_i];
+      _ref3 = this.model.apisArray;
+      for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
+        resource = _ref3[_i];
         id = resource.name;
         while (typeof resources[id] !== 'undefined') {
           id = id + "_" + counter;
@@ -1464,7 +1495,8 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
         model: resource,
         tagName: 'li',
         id: 'resource_' + resource.id,
-        className: 'resource'
+        className: 'resource',
+        swaggerOptions: this.options.swaggerOptions
       });
       return $('#resources').append(resourceView.render().el);
     };
@@ -1478,22 +1510,22 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   ResourceView = (function(_super) {
-
     __extends(ResourceView, _super);
 
     function ResourceView() {
-      ResourceView.__super__.constructor.apply(this, arguments);
+      _ref3 = ResourceView.__super__.constructor.apply(this, arguments);
+      return _ref3;
     }
 
     ResourceView.prototype.initialize = function() {};
 
     ResourceView.prototype.render = function() {
-      var counter, id, methods, operation, _i, _len, _ref;
+      var counter, id, methods, operation, _i, _len, _ref4;
       $(this.el).html(Handlebars.templates.resource(this.model));
       methods = {};
-      _ref = this.model.operationsArray;
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        operation = _ref[_i];
+      _ref4 = this.model.operationsArray;
+      for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
+        operation = _ref4[_i];
         counter = 0;
         id = operation.nickname;
         while (typeof methods[id] !== 'undefined') {
@@ -1505,6 +1537,10 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
         operation.parentId = this.model.id;
         this.addOperation(operation);
       }
+      $('.toggleEndpointList', this.el).click(this.callDocs.bind(this, 'toggleEndpointListForResource'));
+      $('.collapseResource', this.el).click(this.callDocs.bind(this, 'collapseOperationsForResource'));
+      /* DOL_CHANGE LDR Fix typo error that break expand */
+      $('.expandResource', this.el).click(this.callDocs.bind(this, 'expandOperationsForResource'));
       return this;
     };
 
@@ -1514,22 +1550,28 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
       operationView = new OperationView({
         model: operation,
         tagName: 'li',
-        className: 'endpoint'
+        className: 'endpoint',
+        swaggerOptions: this.options.swaggerOptions
       });
       $('.endpoints', $(this.el)).append(operationView.render().el);
       return this.number++;
     };
 
+    ResourceView.prototype.callDocs = function(fnName, e) {
+      e.preventDefault();
+      return Docs[fnName](e.currentTarget.getAttribute('data-id'));
+    };
+
     return ResourceView;
 
   })(Backbone.View);
 
   OperationView = (function(_super) {
-
     __extends(OperationView, _super);
 
     function OperationView() {
-      OperationView.__super__.constructor.apply(this, arguments);
+      _ref4 = OperationView.__super__.constructor.apply(this, arguments);
+      return _ref4;
     }
 
     OperationView.prototype.invocationUrl = null;
@@ -1548,8 +1590,8 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     OperationView.prototype.mouseEnter = function(e) {
       var elem, hgh, pos, scMaxX, scMaxY, scX, scY, wd, x, y;
       elem = $(e.currentTarget.parentNode).find('#api_information_panel');
-      x = event.pageX;
-      y = event.pageY;
+      x = e.pageX;
+      y = e.pageY;
       scX = $(window).scrollLeft();
       scY = $(window).scrollTop();
       scMaxX = scX + $(window).width();
@@ -1580,16 +1622,16 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     OperationView.prototype.render = function() {
-      var contentTypeModel, isMethodSubmissionSupported, k, o, param, responseContentTypeView, responseSignatureView, signatureModel, statusCode, type, v, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3;
+      var contentTypeModel, isMethodSubmissionSupported, k, o, param, responseContentTypeView, responseSignatureView, signatureModel, statusCode, type, v, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref5, _ref6, _ref7, _ref8;
       isMethodSubmissionSupported = true;
       if (!isMethodSubmissionSupported) {
         this.model.isReadOnly = true;
       }
       this.model.oauth = null;
       if (this.model.authorizations) {
-        _ref = this.model.authorizations;
-        for (k in _ref) {
-          v = _ref[k];
+        _ref5 = this.model.authorizations;
+        for (k in _ref5) {
+          v = _ref5[k];
           if (k === "oauth2") {
             if (this.model.oauth === null) {
               this.model.oauth = {};
@@ -1624,9 +1666,9 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
       };
       contentTypeModel.consumes = this.model.consumes;
       contentTypeModel.produces = this.model.produces;
-      _ref1 = this.model.parameters;
-      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
-        param = _ref1[_j];
+      _ref6 = this.model.parameters;
+      for (_j = 0, _len1 = _ref6.length; _j < _len1; _j++) {
+        param = _ref6[_j];
         type = param.type || param.dataType;
         if (type.toLowerCase() === 'file') {
           if (!contentTypeModel.consumes) {
@@ -1639,14 +1681,14 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
         model: contentTypeModel
       });
       $('.response-content-type', $(this.el)).append(responseContentTypeView.render().el);
-      _ref2 = this.model.parameters;
-      for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
-        param = _ref2[_k];
+      _ref7 = this.model.parameters;
+      for (_k = 0, _len2 = _ref7.length; _k < _len2; _k++) {
+        param = _ref7[_k];
         this.addParameter(param, contentTypeModel.consumes);
       }
-      _ref3 = this.model.responseMessages;
-      for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
-        statusCode = _ref3[_l];
+      _ref8 = this.model.responseMessages;
+      for (_l = 0, _len3 = _ref8.length; _l < _len3; _l++) {
+        statusCode = _ref8[_l];
         this.addStatusCode(statusCode);
       }
       return this;
@@ -1673,7 +1715,7 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     OperationView.prototype.submitOperation = function(e) {
-      var error_free, form, isFileUpload, map, o, opts, val, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
+      var error_free, form, isFileUpload, map, o, opts, val, _i, _j, _k, _len, _len1, _len2, _ref5, _ref6, _ref7;
       if (e != null) {
         e.preventDefault();
       }
@@ -1698,9 +1740,9 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
           parent: this
         };
         isFileUpload = false;
-        _ref = form.find("input");
-        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-          o = _ref[_i];
+        _ref5 = form.find("input");
+        for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
+          o = _ref5[_i];
           if ((o.value != null) && jQuery.trim(o.value).length > 0) {
             map[o.name] = o.value;
           }
@@ -1708,16 +1750,16 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
             isFileUpload = true;
           }
         }
-        _ref1 = form.find("textarea");
-        for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
-          o = _ref1[_j];
+        _ref6 = form.find("textarea");
+        for (_j = 0, _len1 = _ref6.length; _j < _len1; _j++) {
+          o = _ref6[_j];
           if ((o.value != null) && jQuery.trim(o.value).length > 0) {
             map["body"] = o.value;
           }
         }
-        _ref2 = form.find("select");
-        for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
-          o = _ref2[_k];
+        _ref7 = form.find("select");
+        for (_k = 0, _len2 = _ref7.length; _k < _len2; _k++) {
+          o = _ref7[_k];
           val = this.getSelectedValue(o);
           if ((val != null) && jQuery.trim(val).length > 0) {
             map[o.name] = val;
@@ -1739,46 +1781,46 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     OperationView.prototype.handleFileUpload = function(map, form) {
-      var bodyParam, el, headerParams, o, obj, param, params, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3,
+      var bodyParam, el, headerParams, o, obj, param, params, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref5, _ref6, _ref7, _ref8,
         _this = this;
-      _ref = form.serializeArray();
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        o = _ref[_i];
+      _ref5 = form.serializeArray();
+      for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
+        o = _ref5[_i];
         if ((o.value != null) && jQuery.trim(o.value).length > 0) {
           map[o.name] = o.value;
         }
       }
       bodyParam = new FormData();
       params = 0;
-      _ref1 = this.model.parameters;
-      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
-        param = _ref1[_j];
+      _ref6 = this.model.parameters;
+      for (_j = 0, _len1 = _ref6.length; _j < _len1; _j++) {
+        param = _ref6[_j];
         if (param.paramType === 'form') {
-          if (map[param.name] !== void 0) {
+          if (param.type.toLowerCase() !== 'file' && map[param.name] !== void 0) {
             bodyParam.append(param.name, map[param.name]);
           }
         }
       }
       headerParams = {};
-      _ref2 = this.model.parameters;
-      for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
-        param = _ref2[_k];
+      _ref7 = this.model.parameters;
+      for (_k = 0, _len2 = _ref7.length; _k < _len2; _k++) {
+        param = _ref7[_k];
         if (param.paramType === 'header') {
           headerParams[param.name] = map[param.name];
         }
       }
       log(headerParams);
-      _ref3 = form.find('input[type~="file"]');
-      for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) {
-        el = _ref3[_l];
+      _ref8 = form.find('input[type~="file"]');
+      for (_l = 0, _len3 = _ref8.length; _l < _len3; _l++) {
+        el = _ref8[_l];
         if (typeof el.files[0] !== 'undefined') {
           bodyParam.append($(el).attr('name'), el.files[0]);
           params += 1;
         }
       }
-      log(bodyParam);
       this.invocationUrl = this.model.supportHeaderParams() ? (headerParams = this.model.getHeaderParams(map), this.model.urlify(map, false)) : this.model.urlify(map, true);
-      $(".request_url", $(this.el)).html("<pre>" + this.invocationUrl + "</pre>");
+      $(".request_url", $(this.el)).html("<pre></pre>");
+      $(".request_url pre", $(this.el)).text(this.invocationUrl);
       obj = {
         type: this.model.method,
         url: this.invocationUrl,
@@ -1829,14 +1871,14 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     OperationView.prototype.getSelectedValue = function(select) {
-      var opt, options, _i, _len, _ref;
+      var opt, options, _i, _len, _ref5;
       if (!select.multiple) {
         return select.value;
       } else {
         options = [];
-        _ref = select.options;
-        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-          opt = _ref[_i];
+        _ref5 = select.options;
+        for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
+          opt = _ref5[_i];
           if (opt.selected) {
             options.push(opt.value);
           }
@@ -1924,9 +1966,9 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
         padding = '';
         indent += transitions[fromTo];
         padding = ((function() {
-          var _j, _ref, _results;
+          var _j, _ref5, _results;
           _results = [];
-          for (j = _j = 0, _ref = indent; 0 <= _ref ? _j < _ref : _j > _ref; j = 0 <= _ref ? ++_j : --_j) {
+          for (j = _j = 0, _ref5 = indent; 0 <= _ref5 ? _j < _ref5 : _j > _ref5; j = 0 <= _ref5 ? ++_j : --_j) {
             _results.push('  ');
           }
           return _results;
@@ -1945,7 +1987,7 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
     };
 
     OperationView.prototype.showStatus = function(response) {
-      var code, content, contentType, headers, pre, response_body, url;
+      var code, content, contentType, headers, opts, pre, response_body, response_body_el, url;
       if (response.content === void 0) {
         content = response.data;
         url = response.url;
@@ -1974,14 +2016,21 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
         pre = $('<pre class="json" />').append(code);
       }
       response_body = pre;
-      $(".request_url", $(this.el)).html("<pre>" + url + "</pre>");
+      $(".request_url", $(this.el)).html("<pre></pre>");
+      $(".request_url pre", $(this.el)).text(url);
       $(".response_code", $(this.el)).html("<pre>" + response.status + "</pre>");
       $(".response_body", $(this.el)).html(response_body);
-      $(".response_headers", $(this.el)).html("<pre>" + JSON.stringify(response.headers, null, "  ").replace(/\n/g, "<br>") + "</pre>");
+      $(".response_headers", $(this.el)).html("<pre>" + _.escape(JSON.stringify(response.headers, null, "  ")).replace(/\n/g, "<br>") + "</pre>");
       $(".response", $(this.el)).slideDown();
       $(".response_hider", $(this.el)).show();
       $(".response_throbber", $(this.el)).hide();
-      return hljs.highlightBlock($('.response_body', $(this.el))[0]);
+      response_body_el = $('.response_body', $(this.el))[0];
+      opts = this.options.swaggerOptions;
+      if (opts.highlightSizeThreshold && response.data.length > opts.highlightSizeThreshold) {
+        return response_body_el;
+      } else {
+        return hljs.highlightBlock(response_body_el);
+      }
     };
 
     OperationView.prototype.toggleOperationContent = function() {
@@ -1999,11 +2048,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   StatusCodeView = (function(_super) {
-
     __extends(StatusCodeView, _super);
 
     function StatusCodeView() {
-      StatusCodeView.__super__.constructor.apply(this, arguments);
+      _ref5 = StatusCodeView.__super__.constructor.apply(this, arguments);
+      return _ref5;
     }
 
     StatusCodeView.prototype.initialize = function() {};
@@ -2038,11 +2087,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   ParameterView = (function(_super) {
-
     __extends(ParameterView, _super);
 
     function ParameterView() {
-      ParameterView.__super__.constructor.apply(this, arguments);
+      _ref6 = ParameterView.__super__.constructor.apply(this, arguments);
+      return _ref6;
     }
 
     ParameterView.prototype.initialize = function() {
@@ -2127,11 +2176,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   SignatureView = (function(_super) {
-
     __extends(SignatureView, _super);
 
     function SignatureView() {
-      SignatureView.__super__.constructor.apply(this, arguments);
+      _ref7 = SignatureView.__super__.constructor.apply(this, arguments);
+      return _ref7;
     }
 
     SignatureView.prototype.events = {
@@ -2146,7 +2195,7 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
       var template;
       template = this.template();
       $(this.el).html(template(this.model));
-      this.switchToDescription();
+      this.switchToSnippet();
       this.isParam = this.model.isParam;
       if (this.isParam) {
         $('.notice', $(this.el)).text('Click to set as parameter value');
@@ -2196,11 +2245,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   ContentTypeView = (function(_super) {
-
     __extends(ContentTypeView, _super);
 
     function ContentTypeView() {
-      ContentTypeView.__super__.constructor.apply(this, arguments);
+      _ref8 = ContentTypeView.__super__.constructor.apply(this, arguments);
+      return _ref8;
     }
 
     ContentTypeView.prototype.initialize = function() {};
@@ -2222,11 +2271,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   ResponseContentTypeView = (function(_super) {
-
     __extends(ResponseContentTypeView, _super);
 
     function ResponseContentTypeView() {
-      ResponseContentTypeView.__super__.constructor.apply(this, arguments);
+      _ref9 = ResponseContentTypeView.__super__.constructor.apply(this, arguments);
+      return _ref9;
     }
 
     ResponseContentTypeView.prototype.initialize = function() {};
@@ -2248,11 +2297,11 @@ helpers = this.merge(helpers, Handlebars.helpers); data = data || {};
   })(Backbone.View);
 
   ParameterContentTypeView = (function(_super) {
-
     __extends(ParameterContentTypeView, _super);
 
     function ParameterContentTypeView() {
-      ParameterContentTypeView.__super__.constructor.apply(this, arguments);
+      _ref10 = ParameterContentTypeView.__super__.constructor.apply(this, arguments);
+      return _ref10;
     }
 
     ParameterContentTypeView.prototype.initialize = function() {};

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
htdocs/includes/restler/framework/Luracast/Restler/explorer/swagger-ui.min.js


+ 3 - 3
htdocs/install/default.css

@@ -54,9 +54,9 @@ span.titre {
 	font-weight: bold;
 	background: #FFFFFF;
 	color: #444;
-	border: 1px solid #999;
-	padding: 5px 5px 5px 5px;
-	margin: 0 0 0 15px;
+	border: 1px solid #bbb;
+	padding: 10px 10px 10px 10px;
+	margin: 0 0 10px 10px;
 }
 
 div.soustitre {

+ 23 - 1
htdocs/install/mysql/migration/5.0.0-6.0.0.sql

@@ -25,6 +25,29 @@
 -- -- VMYSQL4.1 DELETE FROM llx_usergroup_user      WHERE fk_usergroup NOT IN (SELECT rowid from llx_usergroup);
 
 
+-- Clean corrupted values for tms
+-- VMYSQL4.1 SET sql_mode = 'ALLOW_INVALID_DATES';
+-- VMYSQL4.1 update llx_opensurvey_sondage set tms = date_fin where DATE(STR_TO_DATE(tms, '%Y-%m-%d')) IS NULL;
+-- VMYSQL4.1 SET sql_mode = 'NO_ZERO_DATE';
+-- VMYSQL4.1 update llx_opensurvey_sondage set tms = date_fin where DATE(STR_TO_DATE(tms, '%Y-%m-%d')) IS NULL;
+-- Remove default not null on date_fin
+-- VMYSQL4.3 ALTER TABLE llx_opensurvey_sondage MODIFY COLUMN date_fin DATETIME NULL DEFAULT NULL;
+-- VPGSQL8.2 ALTER TABLE llx_opensurvey_sondage ALTER COLUMN date_fin DROP NOT NULL;
+
+
+ALTER TABLE llx_extrafields ADD COLUMN fieldcomputed text;
+ALTER TABLE llx_extrafields ADD COLUMN fielddefault varchar(255);
+
+ALTER TABLE llx_opensurvey_sondage MODIFY COLUMN tms timestamp DEFAULT CURRENT_TIMESTAMP;
+
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN fk_user_creat integer NOT NULL DEFAULT 0;
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN status integer DEFAULT 1 after date_fin;
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN entity integer DEFAULT 1 NOT NULL;
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN allow_comments tinyint NOT NULL DEFAULT 1;
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN allow_spy tinyint NOT NULL DEFAULT 1 AFTER allow_comments;
+ALTER TABLE llx_opensurvey_sondage ADD COLUMN sujet TEXT;
+
+
 create table llx_notify_def_object
 (
   id				integer AUTO_INCREMENT PRIMARY KEY,
@@ -232,7 +255,6 @@ ALTER TABLE llx_product_fournisseur_price_log ADD COLUMN multicurrency_tx	     d
 ALTER TABLE llx_product_fournisseur_price_log ADD COLUMN multicurrency_price	 double(24,8) DEFAULT NULL;
 ALTER TABLE llx_product_fournisseur_price_log ADD COLUMN multicurrency_price_ttc double(24,8) DEFAULT NULL;
 
-
 create table llx_payment_various
 (
   rowid                 integer AUTO_INCREMENT PRIMARY KEY,

+ 4 - 2
htdocs/install/mysql/tables/llx_extrafields.sql

@@ -21,12 +21,14 @@ create table llx_extrafields
 (
 	rowid           integer AUTO_INCREMENT PRIMARY KEY,
 	name            varchar(64) NOT NULL,         				-- name of field into extrafields tables
-	entity          integer DEFAULT 1 NOT NULL,				-- multi company id
-    elementtype     varchar(64) NOT NULL DEFAULT 'member',	-- for which element this extra fields is for
+	entity          integer DEFAULT 1 NOT NULL,					-- multi company id
+    elementtype     varchar(64) NOT NULL DEFAULT 'member',		-- for which element this extra fields is for
 	tms             timestamp,									-- date of last update
 	label           varchar(255) NOT NULL,        				-- label to show for attribute
 	type            varchar(8),
 	size            varchar(8) DEFAULT NULL,
+	fieldcomputed   text,
+	fielddefault    varchar(255),
 	fieldunique     integer DEFAULT 0,
 	fieldrequired   integer DEFAULT 0,
 	perms			varchar(255),								-- not used yet

+ 1 - 1
htdocs/install/mysql/tables/llx_opensurvey_sondage.sql

@@ -23,7 +23,7 @@ CREATE TABLE llx_opensurvey_sondage (
 	nom_admin VARCHAR(64),
 	fk_user_creat integer NOT NULL,
 	titre TEXT NOT NULL,
-	date_fin DATETIME NOT NULL,
+	date_fin DATETIME NULL,
     status integer DEFAULT 1,
 	format VARCHAR(2) NOT NULL,                 -- 'A' = Text choice (choices are saved into sujet field), 'D' = Date choice (choices are saved into sujet field), 'F' = Form survey
 	mailsonde tinyint NOT NULL DEFAULT 0,

+ 4 - 4
htdocs/install/step5.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2004       Rodolphe Quiedeville    <rodolphe@quiedeville.org>
- * Copyright (C) 2004-2012  Laurent Destailleur     <eldy@users.sourceforge.net>
+ * Copyright (C) 2004-2017  Laurent Destailleur     <eldy@users.sourceforge.net>
  * Copyright (C) 2004       Benoit Mortier          <benoit.mortier@opensides.be>
  * Copyright (C) 2004       Sebastien DiCintio      <sdicintio@ressource-toi.org>
  * Copyright (C) 2005-2012  Regis Houssin           <regis.houssin@capnetworks.com>
@@ -395,11 +395,11 @@ elseif (empty($action) || preg_match('/upgrade/i',$action))
             print '<br><div class="warning">'.$langs->trans("WarningRemoveInstallDir")."</div>";
         }
 
-        print "<br>";
+        print "<br><br>";
 
         print '<div class="center"><a href="../index.php?mainmenu=home' . (isset($login) ? '&username=' . urlencode($login) : '') . '">';
-        print $langs->trans("GoToDolibarr");
-        print '</a></div>';
+        print $langs->trans("GoToDolibarr").'...';
+        print '</a></div><br>';
     }
     else
     {

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

@@ -375,19 +375,21 @@ Int=Integer
 Float=Float
 DateAndTime=Date and hour
 Unique=Unique
-Boolean=Boolean (Checkbox)
+Boolean=Boolean (one checkbox)
 ExtrafieldPhone = Phone
 ExtrafieldPrice = Price
 ExtrafieldMail = Email
 ExtrafieldUrl = Url
 ExtrafieldSelect = Select list
 ExtrafieldSelectList = Select from table
-ExtrafieldSeparator=Separator
+ExtrafieldSeparator=Separator (not a field)
 ExtrafieldPassword=Password
-ExtrafieldCheckBox=Checkbox
-ExtrafieldRadio=Radio button
-ExtrafieldCheckBoxFromList= Checkbox from table
+ExtrafieldRadio=Radio buttons (on choice only)
+ExtrafieldCheckBox=Checkboxes
+ExtrafieldCheckBoxFromList=Checkboxes from table
 ExtrafieldLink=Link to an object
+ComputedFormula=Computed field
+ComputedFormulaDesc=You can enter here a formula using other properties of object or any PHP coding to get a dynamic computed value. You can use any PHP compatible formulas including the "?" condition operator, and following global object: <strong>$db, $conf, $langs, $mysoc, $user, $object</strong>.<br><strong>WARNING</strong>: Only some properties of $object may be available. If you need a properties not loaded, just fetch yourself the object into your formula like in the second example.<br>Using a computed field means you can't enter yourself any value from interface. Also, if there is a syntax error, the formula may return nothing.<br><br>Example of formula:<br>$object->id < 5 ? round($object->id / 2, 2) : ($object->id + 2*$user->id) * (int) substr($mysoc->zip, 1, 2)<br><br>Example of formula to force load of object and its parent object:<br>(($reloadedobj = new Task($db)) && ($reloadedobj->fetch($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetch($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : 'Parent project not found'<br><br>Other example to reload object<br>(($reloadedobj = new Societe($db)) && ($reloadedobj->fetch($obj->id ? $obj->id : ($obj->rowid ? $obj->rowid : $object->id)) > 0)) ? round($reloadedobj->capital / 5) : '-1'
 ExtrafieldParamHelpselect=Parameters list have to be like key,value<br><br> for example : <br>1,value1<br>2,value2<br>3,value3<br>...<br><br>In order to have the list depending on another complementary attribute list :<br>1,value1|options_<i>parent_list_code</i>:parent_key<br>2,value2|options_<i>parent_list_code</i>:parent_key <br><br>In order to have the list depending on another list :<br>1,value1|<i>parent_list_code</i>:parent_key<br>2,value2|<i>parent_list_code</i>:parent_key
 ExtrafieldParamHelpcheckbox=Parameters list have to be like key,value<br><br> for example : <br>1,value1<br>2,value2<br>3,value3<br>...
 ExtrafieldParamHelpradio=Parameters list have to be like key,value<br><br> for example : <br>1,value1<br>2,value2<br>3,value3<br>...

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

@@ -762,7 +762,7 @@ Calendar=Calendar
 GroupBy=Group by...
 ViewFlatList=View flat list
 RemoveString=Remove string '%s'
-SomeTranslationAreUncomplete=Some languages may be partially translated or may contains errors. If you detect some, you can fix language files registering to <a href="https://transifex.com/projects/p/dolibarr/" target="_blank">http://transifex.com/projects/p/dolibarr/</a>. 
+SomeTranslationAreUncomplete=Some languages may be partially translated or may contains errors. If you detect some, you can fix language files registering to <a href="https://transifex.com/projects/p/dolibarr/" target="_blank">https://transifex.com/projects/p/dolibarr/</a>. 
 DirectDownloadLink=Direct download link
 Download=Download
 ActualizeCurrency=Update currency rate
@@ -773,6 +773,7 @@ BulkActions=Bulk actions
 ClickToShowHelp=Click to show tooltip help
 HR=HR
 HRAndBank=HR and Bank
+AutomaticallyCalculated=Automatically calculated
 # Week day
 Monday=Monday
 Tuesday=Tuesday

+ 14 - 14
htdocs/langs/en_US/other.lang

@@ -158,20 +158,20 @@ AuthenticationDoesNotAllowSendNewPassword=Authentication mode is <b>%s</b>.<br /
 EnableGDLibraryDesc=Install or enable GD library on your PHP installation to use this option.
 ProfIdShortDesc=<b>Prof Id %s</b> is an information depending on third party country.<br>For example, for country <b>%s</b>, it's code <b>%s</b>.
 DolibarrDemo=Dolibarr ERP/CRM demo
-StatsByNumberOfUnits=Statistics in number of products/services units
-StatsByNumberOfEntities=Statistics in number of referring entities
-NumberOfProposals=Number of proposals in past 12 months
-NumberOfCustomerOrders=Number of customer orders in past 12 months
-NumberOfCustomerInvoices=Number of customer invoices in past 12 months
-NumberOfSupplierProposals=Number of supplier proposals in past 12 months
-NumberOfSupplierOrders=Number of supplier orders in past 12 months
-NumberOfSupplierInvoices=Number of supplier invoices in past 12 months
-NumberOfUnitsProposals=Number of units on proposals in past 12 months
-NumberOfUnitsCustomerOrders=Number of units on customer orders in past 12 months
-NumberOfUnitsCustomerInvoices=Number of units on customer invoices in past 12 months
-NumberOfUnitsSupplierProposals=Number of units on supplier proposals in past 12 months
-NumberOfUnitsSupplierOrders=Number of units on supplier orders in past 12 months
-NumberOfUnitsSupplierInvoices=Number of units on supplier invoices in past 12 months
+StatsByNumberOfUnits=Statistics for sum of qty of products/services
+StatsByNumberOfEntities=Statistics in number of referring entities (nb of invoice, or order...)
+NumberOfProposals=Number of proposals
+NumberOfCustomerOrders=Number of customer orders
+NumberOfCustomerInvoices=Number of customer invoices
+NumberOfSupplierProposals=Number of supplier proposals
+NumberOfSupplierOrders=Number of supplier orders
+NumberOfSupplierInvoices=Number of supplier invoices
+NumberOfUnitsProposals=Number of units on proposals
+NumberOfUnitsCustomerOrders=Number of units on customer orders
+NumberOfUnitsCustomerInvoices=Number of units on customer invoices
+NumberOfUnitsSupplierProposals=Number of units on supplier proposals
+NumberOfUnitsSupplierOrders=Number of units on supplier orders
+NumberOfUnitsSupplierInvoices=Number of units on supplier invoices
 EMailTextInterventionAddedContact=A newintervention %s has been assigned to you.
 EMailTextInterventionValidated=The intervention %s has been validated.
 EMailTextInvoiceValidated=The invoice %s has been validated.

+ 1 - 1
htdocs/langs/en_US/stocks.lang

@@ -119,7 +119,7 @@ NbOfProductBeforePeriod=Quantity of product %s in stock before selected period (
 NbOfProductAfterPeriod=Quantity of product %s in stock after selected period (> %s)
 MassMovement=Mass movement
 SelectProductInAndOutWareHouse=Select a product, a quantity, a source warehouse and a target warehouse, then click "%s". Once this is done for all required movements, click onto "%s".
-RecordMovement=Record transfert
+RecordMovement=Record transfer
 ReceivingForSameOrder=Receipts for this order
 StockMovementRecorded=Stock movements recorded
 RuleForStockAvailability=Rules on stock requirements

+ 1 - 2
htdocs/main.inc.php

@@ -859,7 +859,7 @@ if (! defined('NOLOGIN'))
 }
 
 
-dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]);
+dol_syslog("--- Access to ".$_SERVER["PHP_SELF"].' - action='.GETPOST('action','az09').', massaction='.GETPOST('massaction','az09'));
 //Another call for easy debugg
 //dol_syslog("Access to ".$_SERVER["PHP_SELF"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
 
@@ -1935,7 +1935,6 @@ if (! function_exists("llxFooter"))
         if ($comment) print '<!-- '.$comment.' -->'."\n";
 
         printCommonFooter($zone);
-        //var_dump($langs);		// Uncommment to see the property _tab_loaded to see which language file were loaded
 
         if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '</div> <!-- End div id-container -->'."\n";	// End div container
 

+ 12 - 8
htdocs/modulebuilder/skeletons/skeleton_list.php

@@ -126,13 +126,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
 }
 
 
-// Load object if id or ref is provided as parameter
 $object=new Skeleton_Class($db);
-if (($id > 0 || ! empty($ref)) && $action != 'add')
-{
-	$result=$object->fetch($id,$ref);
-	if ($result < 0) dol_print_error($db);
-}
 
 
 
@@ -354,7 +348,9 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
        if (! empty($arrayfields["ef.".$key]['checked'])) 
        {
 			$align=$extrafields->getAlignFlag($key);
-			print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+			$sortonfield = "ef.".$key;
+			if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+			print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
        }
    }
 }
@@ -383,7 +379,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
             $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')))
+        	if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select')) && empty($extrafields->attribute_computed[$key]))
 			{
 			    $crit=$val;
 				$tmpkey=preg_replace('/search_options_/','',$key);
@@ -427,6 +423,14 @@ print '</td>';
 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
+}
+
+
 $i=0;
 $totalarray=array();
 while ($i < min($num, $limit))

+ 15 - 18
htdocs/opensurvey/card.php

@@ -212,22 +212,23 @@ print '<input type="hidden" name="action" value="update">';
 $head = opensurvey_prepare_head($object);
 
 
-dol_fiche_head($head,'general',$langs->trans("Survey"),0,dol_buildpath('/opensurvey/img/object_opensurvey.png',1),1);
+dol_fiche_head($head,'general',$langs->trans("Survey"), -1, DOL_URL_ROOT.'/opensurvey/img/object_opensurvey.png', 1);
 
-print '<table class="border" width="100%">';
+$morehtmlref = '';
+
+$linkback = '<a href="'.DOL_URL_ROOT.'/opensurvey/list.php">'.$langs->trans("BackToList").'</a>';
+
+dol_banner_tab($object, 'id', $linkback, 1, 'id_sondage', 'id_sondage', $morehtmlref);
 
-$linkback = '<a href="'.dol_buildpath('/opensurvey/list.php',1).'">'.$langs->trans("BackToList").'</a>';
 
-// Ref
-print '<tr><td class="titlefield">'.$langs->trans('Ref').'</td>';
-print '<td colspan="3">';
-print $form->showrefnav($object, 'id', $linkback, 1, 'id_sondage', 'id_sondage');
-print '</td>';
-print '</tr>';
+print '<div class="fichecenter">';
+print '<div class="underbanner clearboth"></div>';
+
+print '<table class="border" width="100%">';
 
 // Type
 $type=($object->format=="A")?'classic':'date';
-print '<tr><td>'.$langs->trans("Type").'</td><td colspan="2">';
+print '<tr><td class="titlefield">'.$langs->trans("Type").'</td><td colspan="2">';
 print img_picto('',dol_buildpath('/opensurvey/img/'.($type == 'classic'?'chart-32.png':'calendar-32.png'),1),'width="16"',1);
 print ' '.$langs->trans($type=='classic'?"TypeClassic":"TypeDate").'</td></tr>';
 
@@ -242,12 +243,6 @@ if ($action == 'edit')
 else print dol_htmlentities($object->titre);
 print '</td></tr>';
 
-// Status
-print '<tr><td>';
-print $langs->trans("Status") .'</td><td colspan="2">';
-print $object->getLibStatut(4);
-print '</td></tr>';
-
 // Description
 print '<tr><td class="tdtop">'.$langs->trans("Description") .'</td><td colspan="2">';
 if ($action == 'edit')
@@ -337,14 +332,16 @@ $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($
 $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
 //$urlwithroot=DOL_MAIN_URL_ROOT;					// This is to use same domain name than current
 
-$url=$urlwithouturlroot.dol_buildpath('/public/opensurvey/studs.php',1).'?sondage='.$object->id_sondage;
+$url=$urlwithroot.'/public/opensurvey/studs.php?sondage='.$object->id_sondage;
 print '<input type="text" style="width: 60%" '.($action == 'edit' ? 'disabled' : '').' id="opensurveyurl" name="opensurveyurl" value="'.$url.'">';
-if ($action != 'edit') print ajax_autoselect("opensurveyurl", 1);
+if ($action != 'edit') print ajax_autoselect("opensurveyurl", $url);
 
 print '</td></tr>';
 
 print '</table>';
 
+print '</div>';
+
 dol_fiche_end();
 
 if ($action == 'edit')

+ 13 - 12
htdocs/opensurvey/class/opensurveysondage.class.php

@@ -34,19 +34,20 @@ require_once(DOL_DOCUMENT_ROOT."/core/class/commonobject.class.php");
  */
 class Opensurveysondage extends CommonObject
 {
-	var $element='opensurvey_sondage';			//!< Id that identify managed objects
-	var $table_element='opensurvey_sondage';	//!< Name of table without prefix where object is stored
-
-	var $id_sondage;
+	public $element='opensurvey_sondage';			//!< Id that identify managed objects
+	public $table_element='opensurvey_sondage';	//!< Name of table without prefix where object is stored
+    public $picto = 'opensurvey';
+    
+	public $id_sondage;
 	/**
 	 * @deprecated
 	 * @see description
 	 */
-	var $commentaires;
+	public $commentaires;
 	public $description;
 
-	var $mail_admin;
-	var $nom_admin;
+	public $mail_admin;
+	public $nom_admin;
 
 	/**
 	 * Id of user author of the poll
@@ -54,11 +55,11 @@ class Opensurveysondage extends CommonObject
 	 */
 	public $fk_user_creat;
 
-	var $titre;
-	var $date_fin='';
-	var $status=1;
-	var $format;
-	var $mailsonde;
+	public $titre;
+	public $date_fin='';
+	public $status=1;
+	public $format;
+	public $mailsonde;
 
 	public $sujet;
 

+ 17 - 16
htdocs/opensurvey/results.php

@@ -426,23 +426,23 @@ print '<form name="formulaire4" action="#" method="POST">'."\n";
 
 $head = opensurvey_prepare_head($object);
 
-print dol_get_fiche_head($head,'preview',$langs->trans("Survey"),0,dol_buildpath('/opensurvey/img/object_opensurvey.png',1),1);
+dol_fiche_head($head,'preview',$langs->trans("Survey"), -1, DOL_URL_ROOT.'/opensurvey/img/object_opensurvey.png', 1);
 
+$morehtmlref = '';
 
-print '<table class="border" width="100%">';
+$linkback = '<a href="'.DOL_URL_ROOT.'/opensurvey/list.php">'.$langs->trans("BackToList").'</a>';
 
-$linkback = '<a href="'.dol_buildpath('/opensurvey/list.php',1).(! empty($socid)?'?socid='.$socid:'').'">'.$langs->trans("BackToList").'</a>';
+dol_banner_tab($object, 'id', $linkback, 1, 'id_sondage', 'id_sondage', $morehtmlref);
 
-// Ref
-print '<tr><td class="titlefield">'.$langs->trans('Ref').'</td>';
-print '<td colspan="3">';
-print $form->showrefnav($object, 'id', $linkback, 1, 'id_sondage', 'id_sondage');
-print '</td>';
-print '</tr>';
+
+print '<div class="fichecenter">';
+print '<div class="underbanner clearboth"></div>';
+
+print '<table class="border" width="100%">';
 
 // Type
 $type=($object->format=="A")?'classic':'date';
-print '<tr><td>'.$langs->trans("Type").'</td><td colspan="2">';
+print '<tr><td class="titlefield">'.$langs->trans("Type").'</td><td colspan="2">';
 print img_picto('',dol_buildpath('/opensurvey/img/'.($type == 'classic'?'chart-32.png':'calendar-32.png'),1),'width="16"',1);
 print ' '.$langs->trans($type=='classic'?"TypeClassic":"TypeDate").'</td></tr>';
 
@@ -499,6 +499,8 @@ print '</td></tr>';
 
 print '</table>';
 
+print '</div>';
+
 dol_fiche_end();
 
 print '</form>'."\n";
@@ -1045,7 +1047,7 @@ print '</table>'."\n";
 print '</div>'."\n";
 
 
-$toutsujet = explode(",", $object->sujet);
+$toutsujet = explode(",", $object->sujet);  // With old versions, this field was not set
 
 $compteursujet = 0;
 $meilleursujet = '';
@@ -1056,7 +1058,7 @@ for ($i = 0; $i < $nbcolonnes; $i++) {
 		if ($object->format == "D") {
 			$meilleursujetexport = $toutsujet[$i];
 
-			if (strpos($toutsujet[$i], '@') !== false) {
+            if (strpos($toutsujet[$i], '@') !== false) {
 				$toutsujetdate = explode("@", $toutsujet[$i]);
 				$meilleursujet .= dol_print_date($toutsujetdate[0],'daytext'). ' ('.dol_print_date($toutsujetdate[0],'%A').')' . ' - ' . $toutsujetdate[1];
 			} else {
@@ -1072,8 +1074,7 @@ for ($i = 0; $i < $nbcolonnes; $i++) {
 		$compteursujet++;
 	}
 }
-
-$meilleursujet = substr("$meilleursujet", 1);
+$meilleursujet = substr($meilleursujet, 1);
 $meilleursujet = str_replace("°", "'", $meilleursujet);
 
 // Show best choice
@@ -1083,9 +1084,9 @@ if ($nbofcheckbox >= 2)
 	print '<p class="affichageresultats">'."\n";
 
 	if (isset($meilleurecolonne) && $compteursujet == "1") {
-		print "<img src=\"".dol_buildpath('/opensurvey/img/medaille.png',1)."\"> " . $langs->trans('TheBestChoice') . ": <b>".$meilleursujet." </b>" . $langs->trans("with") . " <b>$meilleurecolonne </b>" . $vote_str . ".\n";
+		print "<img src=\"".DOL_URL_ROOT.'/opensurvey/img/medaille.png'."\"> " . $langs->trans('TheBestChoice') . ": <b>".$meilleursujet." </b>" . $langs->trans("with") . " <b>".$meilleurecolonne."</b>" . $vote_str . ".\n";
 	} elseif (isset($meilleurecolonne)) {
-		print "<img src=\"".dol_buildpath('/opensurvey/img/medaille.png',1)."\"> " . $langs->trans('TheBestChoices') . ": <b>".$meilleursujet." </b>" . $langs->trans("with") . " <b>$meilleurecolonne </b>" . $vote_str . ".\n";
+		print "<img src=\"".DOL_URL_ROOT.'/opensurvey/img/medaille.png'."\"> " . $langs->trans('TheBestChoices') . ": <b>".$meilleursujet." </b>" . $langs->trans("with") . " <b>".$meilleurecolonne."</b>" . $vote_str . ".\n";
 	}
 	print '<br></p><br>'."\n";
 }

+ 2 - 2
htdocs/product/ajax/products.php

@@ -178,11 +178,11 @@ else
 
 	$idprod = (! empty($match[0]) ? $match[0] : '');
 	
-	if (! GETPOST($htmlname) && ! GETPOST($idprod))
+	if (! $htmlname && (! $idprod || ! GETPOST($idprod,'alpha')))
 		return;
 
 		// When used from jQuery, the search term is added as GET param "term".
-	$searchkey = (GETPOST($idprod) ? GETPOST($idprod) : (GETPOST($htmlname) ? GETPOST($htmlname) : ''));
+	$searchkey = (($idprod && GETPOST($idprod,'alpha')) ? GETPOST($idprod,'alpha') :  (GETPOST($htmlname, 'alpha') ? GETPOST($htmlname, 'alpha') : ''));
 
 	$form = new Form($db);
 	if (empty($mode) || $mode == 1) {  // mode=1: customer

+ 2 - 1
htdocs/product/card.php

@@ -1448,7 +1448,8 @@ else
 		    $head=product_prepare_head($object);
             $titre=$langs->trans("CardProduct".$object->type);
             $picto=($object->type== Product::TYPE_SERVICE?'service':'product');
-            dol_fiche_head($head, 'card', $titre, 0, $picto);
+            
+            dol_fiche_head($head, 'card', $titre, -1, $picto);
 
             $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
             $object->next_prev_filter=" fk_product_type = ".$object->type;

+ 4 - 2
htdocs/product/class/api_deprecated_product.class.php

@@ -149,7 +149,8 @@ class ProductApi extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $product_static = new Product($db);
@@ -235,7 +236,8 @@ class ProductApi extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $product_static = new Product($db);

+ 2 - 1
htdocs/product/class/api_products.class.php

@@ -146,7 +146,8 @@ class Products extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $product_static = new Product($db);

+ 41 - 16
htdocs/product/class/product.class.php

@@ -2459,9 +2459,10 @@ class Product extends CommonObject
 	 *
 	 *  @param		string	$sql        Request to execute
 	 *  @param		string	$mode		'byunit'=number of unit, 'bynumber'=nb of entities
+	 *  @param      int     $year       Year (0=current year)
 	 *  @return   	array       		<0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function _get_stats($sql,$mode)
+	function _get_stats($sql, $mode, $year=0)
 	{
 		$resql = $this->db->query($sql);
 		if ($resql)
@@ -2482,8 +2483,15 @@ class Product extends CommonObject
 			return -1;
 		}
 
-		$year = strftime('%Y',time());
-		$month = strftime('%m',time());
+		if (empty($year)) 
+		{
+		    $year = strftime('%Y',time());
+		    $month = strftime('%m',time());
+		}
+		else
+		{
+		    $month=12;    // We imagine we are at end of year, so we get last 12 month before, so all correct year.
+		}
 		$result = array();
 
 		for ($j = 0 ; $j < 12 ; $j++)
@@ -2516,9 +2524,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 *  @param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_vente($socid, $mode, $filteronproducttype=-1)
+	function get_nb_vente($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf;
 		global $user;
@@ -2536,10 +2546,11 @@ class Product extends CommonObject
 		$sql.= " AND f.entity IN (".getEntity('facture', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND f.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND f.fk_soc = $socid";
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(f.datef,'%Y%m')";
 		$sql.= " ORDER BY date_format(f.datef,'%Y%m') DESC";
 
-		return $this->_get_stats($sql,$mode);
+		return $this->_get_stats($sql,$mode, $year);
 	}
 
 
@@ -2549,9 +2560,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 * 	@param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_achat($socid, $mode, $filteronproducttype=-1)
+	function get_nb_achat($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf;
 		global $user;
@@ -2569,11 +2582,11 @@ class Product extends CommonObject
 		$sql.= " AND f.entity IN (".getEntity('facture_fourn', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND f.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND f.fk_soc = $socid";
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(f.datef,'%Y%m')";
 		$sql.= " ORDER BY date_format(f.datef,'%Y%m') DESC";
 
-		$resarray=$this->_get_stats($sql,$mode);
-		return $resarray;
+		return $this->_get_stats($sql,$mode, $year);
 	}
 
 	/**
@@ -2582,9 +2595,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 * 	@param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_propal($socid, $mode, $filteronproducttype=-1)
+	function get_nb_propal($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf;
 		global $user;
@@ -2602,10 +2617,11 @@ class Product extends CommonObject
 		$sql.= " AND p.entity IN (".getEntity('propal', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND p.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND p.fk_soc = ".$socid;
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(p.datep,'%Y%m')";
 		$sql.= " ORDER BY date_format(p.datep,'%Y%m') DESC";
 
-		return $this->_get_stats($sql,$mode);
+		return $this->_get_stats($sql,$mode, $year);
 	}
 
 	/**
@@ -2614,9 +2630,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 * 	@param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1)
+	function get_nb_propalsupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf;
 		global $user;
@@ -2634,10 +2652,11 @@ class Product extends CommonObject
 		$sql.= " AND p.entity IN (".getEntity('propal', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND p.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND p.fk_soc = ".$socid;
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(p.date_valid,'%Y%m')";
 		$sql.= " ORDER BY date_format(p.date_valid,'%Y%m') DESC";
 
-		return $this->_get_stats($sql,$mode);
+		return $this->_get_stats($sql,$mode, $year);
 	}
 	
 	/**
@@ -2646,9 +2665,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 *  @param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_order($socid, $mode, $filteronproducttype=-1)
+	function get_nb_order($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf, $user;
 
@@ -2665,10 +2686,11 @@ class Product extends CommonObject
 		$sql.= " AND c.entity IN (".getEntity('commande', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND c.fk_soc = ".$socid;
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(c.date_commande,'%Y%m')";
 		$sql.= " ORDER BY date_format(c.date_commande,'%Y%m') DESC";
 
-		return $this->_get_stats($sql,$mode);
+		return $this->_get_stats($sql,$mode, $year);
 	}
 
 	/**
@@ -2677,9 +2699,11 @@ class Product extends CommonObject
 	 *  @param  	int		$socid                   Limit count on a particular third party id
 	 *  @param		string	$mode		             'byunit'=number of unit, 'bynumber'=nb of entities
 	 *  @param      int     $filteronproducttype     0=To filter on product only, 1=To filter on services only
+	 *  @param      int     $year                    Year (0=last 12 month)
+	 *  @param      string  $morefilter              More sql filters
 	 * 	@return   	array       		             <0 if KO, result[month]=array(valuex,valuey) where month is 0 to 11
 	 */
-	function get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1)
+	function get_nb_ordersupplier($socid, $mode, $filteronproducttype=-1, $year=0, $morefilter='')
 	{
 		global $conf, $user;
 
@@ -2696,10 +2720,11 @@ class Product extends CommonObject
 		$sql.= " AND c.entity IN (".getEntity('supplier_order', 1).")";
 		if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND c.fk_soc = sc.fk_soc AND sc.fk_user = " .$user->id;
 		if ($socid > 0)	$sql.= " AND c.fk_soc = ".$socid;
+		$sql.=$morefilter;
 		$sql.= " GROUP BY date_format(c.date_commande,'%Y%m')";
 		$sql.= " ORDER BY date_format(c.date_commande,'%Y%m') DESC";
 
-		return $this->_get_stats($sql,$mode);
+		return $this->_get_stats($sql,$mode, $year);
 	}
 
 	/**

+ 41 - 42
htdocs/product/composition/card.php

@@ -193,7 +193,7 @@ llxHeader('', $title, $helpurl);
 $head=product_prepare_head($object);
 $titre=$langs->trans("CardProduct".$object->type);
 $picto=($object->type==Product::TYPE_SERVICE?'service':'product');
-dol_fiche_head($head, 'subproduct', $titre, 0, $picto);
+dol_fiche_head($head, 'subproduct', $titre, -1, $picto);
 
 
 if ($id > 0 || ! empty($ref))
@@ -209,48 +209,47 @@ if ($id > 0 || ! empty($ref))
 		
         if ($object->type!=Product::TYPE_SERVICE || empty($conf->global->PRODUIT_MULTIPRICES))
         {
+            print '<div class="fichecenter">';
     	    print '<div class="underbanner clearboth"></div>';	
             print '<table class="border tableforfield" width="100%">';
-        }
         
-		// Nature
-		if ($object->type!=Product::TYPE_SERVICE)
-		{
-			print '<tr><td>'.$langs->trans("Nature").'</td><td>';
-			print $object->getLibFinished();
-			print '</td></tr>';
-		}
-
-		if (empty($conf->global->PRODUIT_MULTIPRICES))
-		{
-		    // Price
-			print '<tr><td>'.$langs->trans("SellingPrice").'</td><td>';
-			if ($object->price_base_type == 'TTC')
-			{
-				print price($object->price_ttc).' '.$langs->trans($object->price_base_type);
-			}
-			else
-			{
-				print price($object->price).' '.$langs->trans($object->price_base_type?$object->price_base_type:'HT');
-			}
-			print '</td></tr>';
-
-			// Price minimum
-			print '<tr><td>'.$langs->trans("MinPrice").'</td><td>';
-			if ($object->price_base_type == 'TTC')
-			{
-				print price($object->price_min_ttc).' '.$langs->trans($object->price_base_type);
-			}
-			else
-			{
-				print price($object->price_min).' '.$langs->trans($object->price_base_type?$object->price_base_type:'HT');
-			}
-			print '</td></tr>';
-		}
-
-        if ($object->type!=Product::TYPE_SERVICE || empty($conf->global->PRODUIT_MULTIPRICES))
-        {
-		  print '</table>';
+    		// Nature
+    		if ($object->type!=Product::TYPE_SERVICE)
+    		{
+    			print '<tr><td>'.$langs->trans("Nature").'</td><td>';
+    			print $object->getLibFinished();
+    			print '</td></tr>';
+    		}
+    
+    		if (empty($conf->global->PRODUIT_MULTIPRICES))
+    		{
+    		    // Price
+    			print '<tr><td>'.$langs->trans("SellingPrice").'</td><td>';
+    			if ($object->price_base_type == 'TTC')
+    			{
+    				print price($object->price_ttc).' '.$langs->trans($object->price_base_type);
+    			}
+    			else
+    			{
+    				print price($object->price).' '.$langs->trans($object->price_base_type?$object->price_base_type:'HT');
+    			}
+    			print '</td></tr>';
+    
+    			// Price minimum
+    			print '<tr><td>'.$langs->trans("MinPrice").'</td><td>';
+    			if ($object->price_base_type == 'TTC')
+    			{
+    				print price($object->price_min_ttc).' '.$langs->trans($object->price_base_type);
+    			}
+    			else
+    			{
+    				print price($object->price_min).' '.$langs->trans($object->price_base_type?$object->price_base_type:'HT');
+    			}
+    			print '</td></tr>';
+    		}
+
+            print '</table>';
+            print '</div>';
         }
 
 		dol_fiche_end();
@@ -271,7 +270,7 @@ if ($id > 0 || ! empty($ref))
 
 		//if (count($prodsfather) > 0)
 		//{
-			print load_fiche_titre($langs->trans("ProductParentList"),'','').'<br>';
+			print load_fiche_titre($langs->trans("ProductParentList"),'','');
 			print '<table class="centpercent noborder">';
 			print '<tr class="liste_titre">';
 			print '<td>'.$langs->trans('ParentProducts').'</td>';
@@ -320,7 +319,7 @@ if ($id > 0 || ! empty($ref))
 		//if (count($prods_arbo) > 0)
 		//{
 			$atleastonenotdefined=0;
-			print load_fiche_titre($langs->trans("ProductAssociationList"),'','').'<br>';
+			print load_fiche_titre($langs->trans("ProductAssociationList"),'','');
 
 			print '<form name="formComposedProduct" action="'.$_SERVER['PHP_SELF'].'" method="post">';
 			print '<input type="hidden" name="action" value="save_composed_product" />';

+ 44 - 24
htdocs/product/list.php

@@ -55,6 +55,7 @@ $sall=GETPOST('sall', 'alphanohtml');
 $sref=GETPOST("sref");
 $sbarcode=GETPOST("sbarcode");
 $snom=GETPOST("snom");
+$search_type = GETPOST("search_type",'int');
 $search_sale = GETPOST("search_sale");
 $search_categ = GETPOST("search_categ",'int');
 $tosell = GETPOST("tosell", 'int');
@@ -65,7 +66,7 @@ $search_tobatch = GETPOST("search_tobatch",'int');
 $search_accountancy_code_sell = GETPOST("search_accountancy_code_sell",'alpha');
 $search_accountancy_code_buy = GETPOST("search_accountancy_code_buy",'alpha');
 $optioncss = GETPOST('optioncss','alpha');
-$type= (int) GETPOST("type","int");
+$type=(int) GETPOST("type","int");
 
 //Show/hide child products. Hidden by default
 if (!$_POST) {
@@ -114,8 +115,8 @@ if (! empty($canvas))
 }
 
 // Security check
-if ($type=='0') $result=restrictedArea($user,'produit','','','','','',$objcanvas);
-else if ($type=='1') $result=restrictedArea($user,'service','','','','','',$objcanvas);
+if ($search_type=='0') $result=restrictedArea($user,'produit','','','','','',$objcanvas);
+else if ($search_type=='1') $result=restrictedArea($user,'service','','','','','',$objcanvas);
 else $result=restrictedArea($user,'produit|service','','','','','',$objcanvas);
 
 // Define virtualdiffersfromphysical
@@ -158,7 +159,8 @@ $arrayfields=array(
     'p.ref'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
     //'pfp.ref_fourn'=>array('label'=>$langs->trans("RefSupplier"), 'checked'=>1, 'enabled'=>(! empty($conf->barcode->enabled))),
     'p.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
-	'p.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>($contextpage != 'servicelist'), 'enabled'=>(! empty($conf->barcode->enabled))),
+    'p.fk_product_type'=>array('label'=>$langs->trans("Type"), 'checked'=>0, 'enabled'=>(! empty($conf->produit->enabled) && ! empty($conf->service->enabled))),
+    'p.barcode'=>array('label'=>$langs->trans("Gencod"), 'checked'=>($contextpage != 'servicelist'), 'enabled'=>(! empty($conf->barcode->enabled))),
     'p.duration'=>array('label'=>$langs->trans("Duration"), 'checked'=>($contextpage != 'productlist'), 'enabled'=>(! empty($conf->service->enabled))),
 	'p.sellprice'=>array('label'=>$langs->trans("SellingPrice"), 'checked'=>1, 'enabled'=>empty($conf->global->PRODUIT_MULTIPRICES)),
     'p.minbuyprice'=>array('label'=>$langs->trans("BuyingPriceMinShort"), 'checked'=>1, 'enabled'=>(! empty($user->rights->fournisseur->lire))),
@@ -212,6 +214,7 @@ if (empty($reshook))
     	$tosell="";
     	$tobuy="";
     	$search_tobatch='';
+    	$search_type='';
     	$search_accountancy_code_sell='';
     	$search_accountancy_code_buy='';
     	$search_array_options=array();
@@ -219,8 +222,8 @@ if (empty($reshook))
     
     // Mass actions
     $objectclass='Product';
-    if ((string) $type == '1') { $objectlabel='Services'; }
-    if ((string) $type == '0') { $objectlabel='Products'; }
+    if ((string) $search_type == '1') { $objectlabel='Services'; }
+    if ((string) $search_type == '0') { $objectlabel='Products'; }
     
     $permtoread = $user->rights->produit->lire;
     $permtodelete = $user->rights->produit->supprimer;
@@ -244,9 +247,9 @@ else
 {
 	$title=$langs->trans("ProductsAndServices");
 
-	if (isset($type))
+	if ($search_type != '' && $search_type != '-1')
 	{
-		if ($type==1)
+		if ($search_type==1)
 		{
 			$texte = $langs->trans("Services");
 		}
@@ -260,13 +263,13 @@ else
 		$texte = $langs->trans("ProductsAndServices");
 	}
 
-    $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
+    $sql = 'SELECT DISTINCT p.rowid, p.ref, p.label, p.fk_product_type, p.barcode, p.price, p.price_ttc, p.price_base_type, p.entity,';
     $sql.= ' p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,';
     $sql.= ' p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy,';
     $sql.= ' p.datec as date_creation, p.tms as date_update,';
     //$sql.= ' pfp.ref_fourn as ref_supplier, ';
     $sql.= ' MIN(pfp.unitprice) as minsellprice';
-	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
 		$sql .= ', pac.rowid prod_comb_id';
 	}
 	// Add fields from extrafields
@@ -281,17 +284,17 @@ else
    	$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_fournisseur_price as pfp ON p.rowid = pfp.fk_product";
 	// multilang
 	if (! empty($conf->global->MAIN_MULTILANGS)) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product_lang as pl ON pl.fk_product = p.rowid AND pl.lang = '".$langs->getDefaultLang() ."'";
-	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
 		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product_attribute_combination pac ON pac.fk_product_child = p.rowid";
 	}
 
 	$sql.= ' WHERE p.entity IN ('.getEntity('product', 1).')';
 	if ($sall) $sql .= natural_search(array_keys($fieldstosearchall), $sall);
     // if the type is not 1, we show all products (type = 0,2,3)
-    if (dol_strlen($type))
+    if (dol_strlen($search_type) && $search_type != '-1')
     {
-    	if ($type == 1) $sql.= " AND p.fk_product_type = '1'";
-    	else $sql.= " AND p.fk_product_type <> '1'";
+    	if ($search_type == 1) $sql.= " AND p.fk_product_type = 1";
+    	else $sql.= " AND p.fk_product_type <> 1";
     }
 	if ($sref)     $sql .= natural_search('p.ref', $sref);
 	if ($snom)     $sql .= natural_search('p.label', $snom);
@@ -309,7 +312,7 @@ else
     if ($search_accountancy_code_sell)   $sql.= natural_search('p.accountancy_code_buy', $search_accountancy_code_buy);
     // Add where from extra fields
 
-	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
 		$sql .= " AND pac.rowid IS NULL";
 	}
 
@@ -333,7 +336,7 @@ else
     $sql.= " GROUP BY p.rowid, p.ref, p.label, p.barcode, p.price, p.price_ttc, p.price_base_type,";
     $sql.= " p.fk_product_type, p.duration, p.tosell, p.tobuy, p.seuil_stock_alerte, p.desiredstock,";
     $sql.= ' p.datec, p.tms, p.entity, p.tobatch, p.accountancy_code_sell, p.accountancy_code_buy';
-	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($type === 0)) {
+	if (!empty($conf->variants->enabled) && $search_hidechildproducts && ($search_type === 0)) {
 		$sql .= ', pac.rowid';
 	}
 	// Add fields from extrafields
@@ -368,13 +371,13 @@ else
     	}
 
     	$helpurl='';
-    	if (isset($type))
+    	if ($search_type != '')
     	{
-    		if ($type == 0)
+    		if ($search_type == 0)
     		{
     			$helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
     		}
-    		else if ($type == 1)
+    		else if ($search_type == 1)
     		{
     			$helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
     		}
@@ -401,7 +404,8 @@ else
     	if ($fourn_id > 0) $param.=($fourn_id?"&amp;fourn_id=".$fourn_id:"");
     	if ($seach_categ) $param.=($search_categ?"&amp;search_categ=".urlencode($search_categ):"");
     	if ($type != '') $param.='&amp;type='.urlencode($type);
-		if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
+    	if ($search_type != '') $param.='&amp;search_type='.urlencode($search_type);
+    	if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
     	if ($search_tobatch) $param="&amp;search_ref_supplier=".urlencode($search_ref_supplier);
     	if ($search_accountancy_code_sell) $param="&amp;search_accountancy_code_sell=".urlencode($search_accountancy_code_sell);
     	if ($search_accountancy_code_buy) $param="&amp;search_accountancy_code_buy=".urlencode($search_accountancy_code_buy);
@@ -430,7 +434,8 @@ else
 		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="type" value="'.$type.'">';
+        print '<input type="hidden" name="type" value="'.$type.'">';
+        if (empty($arrayfields['p.fk_product_type']['checked'])) print '<input type="hidden" name="search_type" value="'.dol_escape_htmltag($search_type).'">';
 
 	    print_barre_liste($texte, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_products.png', 0, '', '', $limit);
 
@@ -480,7 +485,7 @@ else
     		}
 
 			//Show/hide child products. Hidden by default
-			if (!empty($conf->variants->enabled) && $type === 0) {
+			if (!empty($conf->variants->enabled) && $search_type === 0) {
 				$moreforfilter.='<div class="divsearchfield">';
 				$moreforfilter.= '<input type="checkbox" id="search_hidechildproducts" name="search_hidechildproducts" value="on"'.($search_hidechildproducts ? 'checked="checked"' : '').'>';
 				$moreforfilter.= ' <label for="search_hidechildproducts">'.$langs->trans('HideChildProducts').'</label>';
@@ -524,6 +529,14 @@ else
 		   		print '<input class="flat" type="text" name="snom" size="12" value="'.dol_escape_htmltag($snom).'">';
     			print '</td>';
     		}
+    		// Type
+    	    if (! empty($arrayfields['p.fk_product_type']['checked']))
+    		{
+    			print '<td class="liste_titre" align="left">';
+		   		$array=array('-1'=>'&nbsp;', '0'=>$langs->trans('Product'), '1'=>$langs->trans('Service'));
+    			print $form->selectarray('search_type', $array, $search_type);
+    			print '</td>';
+    		}
     		// Barcode
     		if (! empty($arrayfields['p.barcode']['checked']))
     		{
@@ -622,6 +635,7 @@ else
     		if (! empty($arrayfields['p.ref']['checked']))  print_liste_field_titre($arrayfields['p.ref']['label'], $_SERVER["PHP_SELF"],"p.ref","",$param,"",$sortfield,$sortorder);
     		if (! empty($arrayfields['pfp.ref_fourn']['checked']))  print_liste_field_titre($arrayfields['pfp.ref_fourn']['label'], $_SERVER["PHP_SELF"],"pfp.ref_fourn","",$param,"",$sortfield,$sortorder);
     		if (! empty($arrayfields['p.label']['checked']))  print_liste_field_titre($arrayfields['p.label']['label'], $_SERVER["PHP_SELF"],"p.label","",$param,"",$sortfield,$sortorder);
+    		if (! empty($arrayfields['p.fk_product_type']['checked']))  print_liste_field_titre($arrayfields['p.fk_product_type']['label'], $_SERVER["PHP_SELF"],"p.fk_product_type","",$param,"",$sortfield,$sortorder);
     		if (! empty($arrayfields['p.barcode']['checked']))  print_liste_field_titre($arrayfields['p.barcode']['label'], $_SERVER["PHP_SELF"],"p.barcode","",$param,"",$sortfield,$sortorder);
     		if (! empty($arrayfields['p.duration']['checked']))  print_liste_field_titre($arrayfields['p.duration']['label'], $_SERVER["PHP_SELF"],"p.duration","",$param,'align="center"',$sortfield,$sortorder);
     		if (! empty($arrayfields['p.sellprice']['checked']))  print_liste_field_titre($arrayfields['p.sellprice']['label'], $_SERVER["PHP_SELF"],"","",$param,'align="right"',$sortfield,$sortorder);
@@ -690,7 +704,7 @@ else
                 $product_static->status     = $obj->tosell;
 				$product_static->entity = $obj->entity;
 
-				if (! empty($conf->stock->enabled) && $user->rights->stock->lire && $type != 1)	// To optimize call of load_stock
+				if (! empty($conf->stock->enabled) && $user->rights->stock->lire && $search_type != 1)	// To optimize call of load_stock
 				{
 				    if ($obj->fk_product_type != 1)    // Not a service
 				    {
@@ -721,7 +735,13 @@ else
 			    	print '<td>'.dol_trunc($obj->label,40).'</td>';
 			    }
 			    
-    			// Barcode
+    		    // Type
+			    if (! empty($arrayfields['p.fk_product_type']['checked']))
+			    {
+			    	print '<td>'.$obj->fk_product_type.'</td>';
+			    }
+			    
+			    // Barcode
 			    if (! empty($arrayfields['p.barcode']['checked']))
 			    {
     				print '<td>'.$obj->barcode.'</td>';

+ 319 - 282
htdocs/product/stats/card.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2001-2007	Rodolphe Quiedeville	<rodolphe@quiedeville.org>
- * Copyright (c) 2004-2015	Laurent Destailleur		<eldy@users.sourceforge.net>
+ * Copyright (c) 2004-2017	Laurent Destailleur		<eldy@users.sourceforge.net>
  * Copyright (C) 2005-2012	Regis Houssin			<regis.houssin@capnetworks.com>
  * Copyright (C) 2005		Eric Seigne				<eric.seigne@ryxeo.com>
  * Copyright (C) 2013		Juanjo Menent			<jmenent@2byte.es>
@@ -30,6 +30,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgraph.class.php';
+require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
 
 $WIDTH=DolGraph::getDefaultGraphSizeForStats('width',380);
 $HEIGHT=DolGraph::getDefaultGraphSizeForStats('height',160);
@@ -43,6 +45,9 @@ $langs->load("other");
 $id		= GETPOST('id','int');         // For this page, id can also be 'all'
 $ref	= GETPOST('ref');
 $mode	= (GETPOST('mode') ? GETPOST('mode') : 'byunit');
+$search_year   = GETPOST('search_year','int');
+$search_categ  = GETPOST('search_categ','int');
+
 $error	= 0;
 $mesg	= '';
 $graphfiles=array();
@@ -55,348 +60,380 @@ $fieldvalue = (! empty($id) ? $id : $ref);
 $fieldtype = (! empty($ref) ? 'ref' : 'rowid');
 $result=restrictedArea($user,'produit|service',$fieldvalue,'product&product','','',$fieldtype);
 
+$tmp=dol_getdate(dol_now());
+$currentyear=$tmp['year'];
+if (empty($search_year)) $search_year=$currentyear;
+
+
+/*
+ * Actions
+ */
+
+// None
+
 
 /*
  *	View
  */
 
 $form = new Form($db);
+$htmlother = new FormOther($db);
 
-if (! empty($id) || ! empty($ref) || GETPOST('id') == 'all')
+$object = new Product($db);
+if (! $id)
 {
-	$object = new Product($db);
-    if (GETPOST('id') == 'all')
+    llxHeader("",$langs->trans("ProductStatistics"));
+
+    $type = GETPOST('type','int');
+
+   	$helpurl='';
+    if ($type == '0')
+    {
+        $helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
+        //$title=$langs->trans("StatisticsOfProducts");
+        $title=$langs->trans("Statistics");
+    }
+    else if ($type == '1')
     {
-        llxHeader("",$langs->trans("ProductStatistics"));
-
-   	    $type = GETPOST('type');
-
-       	$helpurl='';
-        if ($type == '0')
-        {
-            $helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
-            //$title=$langs->trans("StatisticsOfProducts");
-            $title=$langs->trans("Statistics");
-        }
-        else if ($type == '1')
-        {
-            $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
-            //$title=$langs->trans("StatisticsOfServices");
-            $title=$langs->trans("Statistics");
-        }
-        else
-        {
-            $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
-            //$title=$langs->trans("StatisticsOfProductsOrServices");
-            $title=$langs->trans("Statistics");
-        }
-
-        print load_fiche_titre($title, $mesg,'title_products.png');
+        $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
+        //$title=$langs->trans("StatisticsOfServices");
+        $title=$langs->trans("Statistics");
     }
     else
     {
-        $result = $object->fetch($id,$ref);
-
-		$title = $langs->trans('ProductServiceCard');
-		$helpurl = '';
-		$shortlabel = dol_trunc($object->label,16);
-		if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT))
-		{
-			$title = $langs->trans('Product')." ". $shortlabel ." - ".$langs->trans('Statistics');
-			$helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
-		}
-		if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE))
-		{
-			$title = $langs->trans('Service')." ". $shortlabel ." - ".$langs->trans('Statistics');
-			$helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
-		}
-
-		llxHeader('', $title, $helpurl);
+        $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
+        //$title=$langs->trans("StatisticsOfProductsOrServices");
+        $title=$langs->trans("Statistics");
     }
 
+    print load_fiche_titre($title, $mesg,'title_products.png');
+}
+else
+{
+    $result = $object->fetch($id,$ref);
 
-	if ($result && (! empty($id) || ! empty($ref)))
+	$title = $langs->trans('ProductServiceCard');
+	$helpurl = '';
+	$shortlabel = dol_trunc($object->label,16);
+	if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT))
 	{
-		$head=product_prepare_head($object);
-		$titre=$langs->trans("CardProduct".$object->type);
-		$picto=($object->type==Product::TYPE_SERVICE?'service':'product');
-
-		dol_fiche_head($head, 'stats', $titre, 0, $picto);
-
-		$linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php">'.$langs->trans("BackToList").'</a>';
-		
-        dol_banner_tab($object, 'ref', $linkback, ($user->societe_id?0:1), 'ref', '', '', '', 0, '', '', 1);
-
-        dol_fiche_end();
+		$title = $langs->trans('Product')." ". $shortlabel ." - ".$langs->trans('Statistics');
+		$helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
 	}
-	if (GETPOST('id') == 'all')
+	if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE))
 	{
-        $h=0;
-        $head = array();
-
-        $head[$h][0] = DOL_URL_ROOT.'/product/stats/card.php?id=all';
-        $head[$h][1] = $langs->trans("Chart");
-        $head[$h][2] = 'chart';
-        $h++;
-
-    	$title = $langs->trans("ListProductServiceByPopularity");
-        if ((string) $type == '1') {
-        	$title = $langs->trans("ListServiceByPopularity");
-        }
-        if ((string) $type == '0') {
-        	$title = $langs->trans("ListProductByPopularity");
-        }
-
-        $head[$h][0] = DOL_URL_ROOT.'/product/popuprop.php'.($type != ''?'?type='.$type:'');
-        $head[$h][1] = $title;
-        $head[$h][2] = 'popularityprop';
-        $h++;
-
-        dol_fiche_head($head,'chart',$langs->trans("Statistics"));
+		$title = $langs->trans('Service')." ". $shortlabel ." - ".$langs->trans('Statistics');
+		$helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
 	}
 
+	llxHeader('', $title, $helpurl);
+}
 
-	if ($result || GETPOST('id') == 'all')
-	{
-	    if (GETPOST('id') == 'all')
-	    {
-    		// Choice of type of product
-    		if (! empty($conf->dol_use_jmobile)) print "\n".'<div class="fichecenter"><div class="nowrap">'."\n";
-
-    		if ((string) $type != '0') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).'&type=0'.($mode?'&mode='.$mode:'').'">';
-    		else print img_picto('','tick').' ';
-    		print $langs->trans("Products");
-    		if ((string) $type != '0') print '</a>';
-
-    		if (! empty($conf->dol_use_jmobile)) print '</div>'."\n".'<div class="nowrap">'."\n";
-    		else print ' &nbsp; / &nbsp; ';
-
-    		if ((string) $type != '1') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).'&type=1'.($mode?'&mode='.$mode:'').'">';
-    		else print img_picto('','tick').' ';
-    		print $langs->trans("Services");
-    		if ((string) $type != '1') print '</a>';
-
-    		if (! empty($conf->dol_use_jmobile)) print '</div>'."\n".'<div class="nowrap">'."\n";
-    		else print ' &nbsp; / &nbsp; ';
-
-    		if ((string) $type == '0' || (string) $type == '1') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).($mode?'&mode='.$mode:'').'">';
-    		else print img_picto('','tick').' ';
-    		print $langs->trans("ProductsAndServices");
-    		if ((string) $type == '0' || (string) $type == '1') print '</a>';
-
-    		if (! empty($conf->dol_use_jmobile)) print '</div></div>';
-    		else print '<br>';
-    		print '<br>';
-	    }
-
-		// Choice of stats mode (byunit or bynumber)
-		if (! empty($conf->dol_use_jmobile)) print "\n".'<div class="fichecenter"><div class="nowrap">'."\n";
-
-		if ($mode == 'bynumber') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).($type != '' ? '&type='.$type:'').'&mode=byunit">';
-		else print img_picto('','tick').' ';
-		print $langs->trans("StatsByNumberOfUnits");
-		if ($mode == 'bynumber') print '</a>';
-
-		if (! empty($conf->dol_use_jmobile)) print '</div>'."\n".'<div class="nowrap">'."\n";
-		else print ' &nbsp; / &nbsp; ';
-
-		if ($mode == 'byunit') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).($type != '' ? '&type='.$type:'').'&mode=bynumber">';
-		else print img_picto('','tick').' ';
-		print $langs->trans("StatsByNumberOfEntities");
-		if ($mode == 'byunit') print '</a>';
-
-		if (! empty($conf->dol_use_jmobile)) print '</div></div>';
-		else print '<br>';
-		print '<br>';
 
-		//print '<table width="100%">';
+if ($result && (! empty($id) || ! empty($ref)))
+{
+	$head=product_prepare_head($object);
+	$titre=$langs->trans("CardProduct".$object->type);
+	$picto=($object->type==Product::TYPE_SERVICE?'service':'product');
+
+	dol_fiche_head($head, 'stats', $titre, -1, $picto);
 
-		// Generation des graphs
-    	$dir = (! empty($conf->product->multidir_temp[$object->entity])?$conf->product->multidir_temp[$object->entity]:$conf->service->multidir_temp[$object->entity]);
-		if ($object->id > 0)  // We are on statistics for a dedicated product
-		{
-    		if (! file_exists($dir.'/'.$object->id))
+	$linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php">'.$langs->trans("BackToList").'</a>';
+	
+    dol_banner_tab($object, 'ref', $linkback, ($user->societe_id?0:1), 'ref', '', '', '', 0, '', '', 1);
+
+    dol_fiche_end();
+}
+if (empty($id) & empty($ref))
+{
+    $h=0;
+    $head = array();
+
+    $head[$h][0] = DOL_URL_ROOT.'/product/stats/card.php'.($type != ''?'?type='.$type:'');
+    $head[$h][1] = $langs->trans("Chart");
+    $head[$h][2] = 'chart';
+    $h++;
+
+	$title = $langs->trans("ListProductServiceByPopularity");
+    if ((string) $type == '1') {
+    	$title = $langs->trans("ListServiceByPopularity");
+    }
+    if ((string) $type == '0') {
+    	$title = $langs->trans("ListProductByPopularity");
+    }
+
+    $head[$h][0] = DOL_URL_ROOT.'/product/popuprop.php'.($type != ''?'?type='.$type:'');
+    $head[$h][1] = $title;
+    $head[$h][2] = 'popularityprop';
+    $h++;
+
+    dol_fiche_head($head, 'chart', $langs->trans("Statistics"), -1);
+}
+
+
+if ($result || empty($id))
+{
+        print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
+        print '<input type="hidden" name="id" value="'.$id.'">';
+        
+    	print '<table class="noborder" width="100%">';
+    	print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
+
+    	if (empty($id))
+    	{
+        	// Type
+    		print '<tr><td class="titlefield">'.$langs->trans("ProductsAndServices").'</td><td>';
+    		$array=array('-1'=>'&nbsp;', '0'=>$langs->trans('Product'), '1'=>$langs->trans('Service'));
+    		print $form->selectarray('type', $array, $type);
+    		print '</td></tr>';
+		
+    		// Tag
+    		if ($conf->categorie->enabled)
     		{
-    			if (dol_mkdir($dir.'/'.$object->id) < 0)
-    			{
-    				$mesg = $langs->trans("ErrorCanNotCreateDir",$dir);
-    				$error++;
-    			}
+        		print '<tr><td class="titlefield">'.$langs->trans("Categories").'</td><td>';
+        		//$moreforfilter.='<div class="divsearchfield">';
+        		$moreforfilter.=$htmlother->select_categories(Categorie::TYPE_PRODUCT,$search_categ,'search_categ',1);
+        		//$moreforfilter.='</div>';
+        		print $moreforfilter;
+        		print '</td></tr>';
     		}
+    	}
+		
+		// Year
+		print '<tr><td class="titlefield">'.$langs->trans("Year").'</td><td>';
+		$arrayyears=array();
+		for ($year = $currentyear - 10; $year < $currentyear + 10 ; $year++)
+		{
+		    $arrayyears[$year]=$year;
 		}
+		if (! in_array($year,$arrayyears)) $arrayyears[$year]=$year;
+		if (! in_array($nowyear,$arrayyears)) $arrayyears[$nowyear]=$nowyear;
+		arsort($arrayyears);
+		print $form->selectarray('search_year',$arrayyears,$search_year,0);
+		print '</td></tr>';
+		print '</table>';
+		print '<div class="center"><input type="submit" name="submit" class="button" value="'.$langs->trans("Refresh").'"></div>';
+		print '</form>';
+		
+		print '<br>';
+    
 
-		if($conf->propal->enabled) {
-			$graphfiles['propal']=array('modulepart'=>'productstats_proposals',
-			'file' => $object->id.'/propal12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsProposals"):$langs->transnoentitiesnoconv("NumberOfProposals")));
-		}
-
-		if($conf->supplier_proposal->enabled) {
-			$graphfiles['proposalssuppliers']=array('modulepart'=>'productstats_proposalssuppliers',
-			'file' => $object->id.'/proposalssuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierProposals"):$langs->transnoentitiesnoconv("NumberOfSupplierProposals")));
-		}
+	// Choice of stats mode (byunit or bynumber)
+	if (! empty($conf->dol_use_jmobile)) print "\n".'<div class="fichecenter"><div class="nowrap">'."\n";
 
-		if($conf->order->enabled) {
-			$graphfiles['orders']=array('modulepart'=>'productstats_orders',
-			'file' => $object->id.'/orders12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsCustomerOrders"):$langs->transnoentitiesnoconv("NumberOfCustomerOrders")));
-		}
+	if ($mode == 'bynumber') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).($type != '' ? '&type='.$type:'').'&mode=byunit&search_year='.$search_year.'">';
+	else print img_picto('','tick').' ';
+	print $langs->trans("StatsByNumberOfUnits");
+	if ($mode == 'bynumber') print '</a>';
 
-		if($conf->fournisseur->enabled) {
-			$graphfiles['orderssuppliers']=array('modulepart'=>'productstats_orderssuppliers',
-			'file' => $object->id.'/orderssuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierOrders"):$langs->transnoentitiesnoconv("NumberOfSupplierOrders")));
-		}
+	if (! empty($conf->dol_use_jmobile)) print '</div>'."\n".'<div class="nowrap">'."\n";
+	else print ' &nbsp; / &nbsp; ';
 
-		if($conf->facture->enabled) {
-			$graphfiles['invoices']=array('modulepart'=>'productstats_invoices',
-			'file' => $object->id.'/invoices12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsCustomerInvoices"):$langs->transnoentitiesnoconv("NumberOfCustomerInvoices")));
+	if ($mode == 'byunit') print '<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).($type != '' ? '&type='.$type:'').'&mode=bynumber&search_year='.$search_year.'">';
+	else print img_picto('','tick').' ';
+	print $langs->trans("StatsByNumberOfEntities");
+	if ($mode == 'byunit') print '</a>';
 
-			$graphfiles['invoicessuppliers']=array('modulepart'=>'productstats_invoicessuppliers',
-			'file' => $object->id.'/invoicessuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.'.png',
-			'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierInvoices"):$langs->transnoentitiesnoconv("NumberOfSupplierInvoices")));
-		}
+	if (! empty($conf->dol_use_jmobile)) print '</div></div>';
+	else print '<br>';
+	print '<br>';
 
-		$px = new DolGraph();
+	//print '<table width="100%">';
 
-		if (! $error && count($graphfiles)>0)
+	// Generation des graphs
+	$dir = (! empty($conf->product->multidir_temp[$object->entity])?$conf->product->multidir_temp[$object->entity]:$conf->service->multidir_temp[$object->entity]);
+	if ($object->id > 0)  // We are on statistics for a dedicated product
+	{
+		if (! file_exists($dir.'/'.$object->id))
 		{
-			$mesg = $px->isGraphKo();
-			if (! $mesg)
+			if (dol_mkdir($dir.'/'.$object->id) < 0)
 			{
-				foreach($graphfiles as $key => $val)
-				{
-					if (! $graphfiles[$key]['file']) continue;
-
-					$graph_data = array();
-
-					if (dol_is_file($dir . '/' . $graphfiles[$key]['file']))
-					{
-    					// TODO Load cachefile $graphfiles[$key]['file']
-					}
-					else
-					{
-    					if ($key == 'propal')             $graph_data = $object->get_nb_propal($socid,$mode,((string) $type != '' ? $type : -1));
-    					if ($key == 'orders')             $graph_data = $object->get_nb_order($socid,$mode,((string) $type != '' ? $type : -1));
-    					if ($key == 'invoices')           $graph_data = $object->get_nb_vente($socid,$mode,((string) $type != '' ? $type : -1));
-    					if ($key == 'proposalssuppliers') $graph_data = $object->get_nb_propalsupplier($socid,$mode,((string) $type != '' ? $type : -1));
-    					if ($key == 'invoicessuppliers')  $graph_data = $object->get_nb_achat($socid,$mode,((string) $type != '' ? $type : -1));
-    					if ($key == 'orderssuppliers')    $graph_data = $object->get_nb_ordersupplier($socid,$mode,((string) $type != '' ? $type : -1));
-
-    					// TODO Save cachefile $graphfiles[$key]['file']
-					}
-
-					if (is_array($graph_data))
-					{
-						$px->SetData($graph_data);
-						$px->SetYLabel($graphfiles[$key]['label']);
-						$px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue());
-						$px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue());
-						$px->SetWidth($WIDTH);
-						$px->SetHeight($HEIGHT);
-						$px->SetHorizTickIncrement(1);
-						$px->SetPrecisionY(0);
-						$px->SetShading(3);
-						//print 'x '.$key.' '.$graphfiles[$key]['file'];
-
-						$url=DOL_URL_ROOT.'/viewimage.php?modulepart='.$graphfiles[$key]['modulepart'].'&entity='.$object->entity.'&file='.urlencode($graphfiles[$key]['file']);
-						$px->draw($dir."/".$graphfiles[$key]['file'],$url);
-
-						$graphfiles[$key]['output']=$px->show();
-					}
-					else
-					{
-						dol_print_error($db,'Error for calculating graph on key='.$key.' - '.$object->error);
-					}
-				}
+				$mesg = $langs->trans("ErrorCanNotCreateDir",$dir);
+				$error++;
 			}
-
-			$mesg = $langs->trans("ChartGenerated");
 		}
+	}
+
+	if($conf->propal->enabled) {
+		$graphfiles['propal']=array('modulepart'=>'productstats_proposals',
+		'file' => $object->id.'/propal12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsProposals"):$langs->transnoentitiesnoconv("NumberOfProposals")));
+	}
+
+	if($conf->supplier_proposal->enabled) {
+		$graphfiles['proposalssuppliers']=array('modulepart'=>'productstats_proposalssuppliers',
+		'file' => $object->id.'/proposalssuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierProposals"):$langs->transnoentitiesnoconv("NumberOfSupplierProposals")));
+	}
+
+	if($conf->order->enabled) {
+		$graphfiles['orders']=array('modulepart'=>'productstats_orders',
+		'file' => $object->id.'/orders12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsCustomerOrders"):$langs->transnoentitiesnoconv("NumberOfCustomerOrders")));
+	}
+
+	if($conf->fournisseur->enabled) {
+		$graphfiles['orderssuppliers']=array('modulepart'=>'productstats_orderssuppliers',
+		'file' => $object->id.'/orderssuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierOrders"):$langs->transnoentitiesnoconv("NumberOfSupplierOrders")));
+	}
+
+	if($conf->facture->enabled) {
+		$graphfiles['invoices']=array('modulepart'=>'productstats_invoices',
+		'file' => $object->id.'/invoices12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsCustomerInvoices"):$langs->transnoentitiesnoconv("NumberOfCustomerInvoices")));
+
+		$graphfiles['invoicessuppliers']=array('modulepart'=>'productstats_invoicessuppliers',
+		'file' => $object->id.'/invoicessuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year?'_year'.$search_year:'').'.png',
+		'label' => ($mode=='byunit'?$langs->transnoentitiesnoconv("NumberOfUnitsSupplierInvoices"):$langs->transnoentitiesnoconv("NumberOfSupplierInvoices")));
+	}
+
+	$px = new DolGraph();
 
-		// Show graphs
-		$i=0;
-		if ( count($graphfiles)>0)
+	if (! $error && count($graphfiles)>0)
+	{
+		$mesg = $px->isGraphKo();
+		if (! $mesg)
 		{
 			foreach($graphfiles as $key => $val)
 			{
 				if (! $graphfiles[$key]['file']) continue;
-	
-				if ($graphfiles == 'propal' && ! $user->rights->propale->lire) continue;
-				if ($graphfiles == 'order' && ! $user->rights->commande->lire) continue;
-				if ($graphfiles == 'invoices' && ! $user->rights->facture->lire) continue;
-				if ($graphfiles == 'proposals_suppliers' && ! $user->rights->supplier_proposal->lire) continue;
-				if ($graphfiles == 'invoices_suppliers' && ! $user->rights->fournisseur->facture->lire) continue;
-				if ($graphfiles == 'orders_suppliers' && ! $user->rights->fournisseur->commande->lire) continue;
-	
-	
-				if ($i % 2 == 0)
-				{
-					print "\n".'<div class="fichecenter"><div class="fichehalfleft">'."\n";
-				}
-				else
-				{
-					print "\n".'<div class="fichehalfright"><div class="ficheaddleft">'."\n";
-				}
-	
-				// Date generation
-				if ($graphfiles[$key]['output'] && ! $px->isGraphKo())
+
+				$graph_data = array();
+
+				if (dol_is_file($dir . '/' . $graphfiles[$key]['file']))
 				{
-				    if (file_exists($dir."/".$graphfiles[$key]['file']) && filemtime($dir."/".$graphfiles[$key]['file'])) $dategenerated=$langs->trans("GeneratedOn",dol_print_date(filemtime($dir."/".$graphfiles[$key]['file']),"dayhour"));
-				    else $dategenerated=$langs->trans("GeneratedOn",dol_print_date(dol_now(),"dayhour"));
+					// TODO Load cachefile $graphfiles[$key]['file']
 				}
 				else
 				{
-				    print $dategenerated=($mesg?'<font class="error">'.$mesg.'</font>':$langs->trans("ChartNotGenerated"));
+				    $morefilters='';
+				    if ($search_categ > 0) 
+				    {
+				        $categ=new Categorie($db);
+				        $categ->fetch($search_categ);
+				        $listofprodids = $categ->getObjectsInCateg('product', 1);
+				        $morefilters=' AND d.fk_product IN ('.((is_array($listofprodids) && count($listofprodids)) ? join(',',$listofprodids):'0').')';
+				    }
+				    if ($search_categ == -2)
+				    {
+				        $morefilters=' AND d.fk_product NOT IN (SELECT cp.fk_product from '.MAIN_DB_PREFIX.'categorie_product as cp)';
+				    }
+				    
+					if ($key == 'propal')             $graph_data = $object->get_nb_propal($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+					if ($key == 'orders')             $graph_data = $object->get_nb_order($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+					if ($key == 'invoices')           $graph_data = $object->get_nb_vente($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+					if ($key == 'proposalssuppliers') $graph_data = $object->get_nb_propalsupplier($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+					if ($key == 'invoicessuppliers')  $graph_data = $object->get_nb_achat($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+					if ($key == 'orderssuppliers')    $graph_data = $object->get_nb_ordersupplier($socid, $mode, ((string) $type != '' ? $type : -1), $search_year, $morefilters);
+
+					// TODO Save cachefile $graphfiles[$key]['file']
 				}
-				$linktoregenerate='<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).((string) $type != ''?'&amp;type='.$type:'').'&amp;action=recalcul&amp;mode='.$mode.'">'.img_picto($langs->trans("ReCalculate").' ('.$dategenerated.')','refresh').'</a>';
-				
-				// Show graph
-				print '<table class="noborder" width="100%">';
-				// Label
-				print '<tr class="liste_titre"><td>';
-				print $graphfiles[$key]['label'];
-				print '</td>';
-				print '<td align="right">'.$linktoregenerate.'</td>';
-				print '</tr>';
-				// Image
-				print '<tr class="impair"><td colspan="2" class="nohover" align="center">';
-				print $graphfiles[$key]['output'];
-				print '</td></tr>';
-				print '</table>';
-	
-				if ($i % 2 == 0)
+
+				if (is_array($graph_data))
 				{
-					print "\n".'</div>'."\n";
+					$px->SetData($graph_data);
+					$px->SetYLabel($graphfiles[$key]['label']);
+					$px->SetMaxValue($px->GetCeilMaxValue()<0?0:$px->GetCeilMaxValue());
+					$px->SetMinValue($px->GetFloorMinValue()>0?0:$px->GetFloorMinValue());
+					$px->SetWidth($WIDTH);
+					$px->SetHeight($HEIGHT);
+					$px->SetHorizTickIncrement(1);
+					$px->SetPrecisionY(0);
+					$px->SetShading(3);
+					//print 'x '.$key.' '.$graphfiles[$key]['file'];
+
+					$url=DOL_URL_ROOT.'/viewimage.php?modulepart='.$graphfiles[$key]['modulepart'].'&entity='.$object->entity.'&file='.urlencode($graphfiles[$key]['file']);
+					$px->draw($dir."/".$graphfiles[$key]['file'],$url);
+
+					$graphfiles[$key]['output']=$px->show();
 				}
 				else
 				{
-					print "\n".'</div></div></div>';
-					print '<div class="clear"><div class="fichecenter"><br></div></div>'."\n";
+					dol_print_error($db,'Error for calculating graph on key='.$key.' - '.$object->error);
 				}
-	
-				$i++;
 			}
 		}
-		// div not closed
-		if ($i % 2 == 1)
+
+		$mesg = $langs->trans("ChartGenerated");
+	}
+
+	// Show graphs
+	$i=0;
+	if ( count($graphfiles)>0)
+	{
+		foreach($graphfiles as $key => $val)
 		{
-			print "\n".'<div class="fichehalfright"><div class="ficheaddleft">'."\n";
-			print "\n".'</div></div></div>';
-			print '<div class="clear"><div class="fichecenter"><br></div></div>'."\n";
+			if (! $graphfiles[$key]['file']) continue;
+
+			if ($graphfiles == 'propal' && ! $user->rights->propale->lire) continue;
+			if ($graphfiles == 'order' && ! $user->rights->commande->lire) continue;
+			if ($graphfiles == 'invoices' && ! $user->rights->facture->lire) continue;
+			if ($graphfiles == 'proposals_suppliers' && ! $user->rights->supplier_proposal->lire) continue;
+			if ($graphfiles == 'invoices_suppliers' && ! $user->rights->fournisseur->facture->lire) continue;
+			if ($graphfiles == 'orders_suppliers' && ! $user->rights->fournisseur->commande->lire) continue;
+
+
+			if ($i % 2 == 0)
+			{
+				print "\n".'<div class="fichecenter"><div class="fichehalfleft">'."\n";
+			}
+			else
+			{
+				print "\n".'<div class="fichehalfright"><div class="ficheaddleft">'."\n";
+			}
+
+			// Date generation
+			if ($graphfiles[$key]['output'] && ! $px->isGraphKo())
+			{
+			    if (file_exists($dir."/".$graphfiles[$key]['file']) && filemtime($dir."/".$graphfiles[$key]['file'])) $dategenerated=$langs->trans("GeneratedOn",dol_print_date(filemtime($dir."/".$graphfiles[$key]['file']),"dayhour"));
+			    else $dategenerated=$langs->trans("GeneratedOn",dol_print_date(dol_now(),"dayhour"));
+			}
+			else
+			{
+			    print $dategenerated=($mesg?'<font class="error">'.$mesg.'</font>':$langs->trans("ChartNotGenerated"));
+			}
+			$linktoregenerate='<a href="'.$_SERVER["PHP_SELF"].'?id='.(GETPOST('id')?GETPOST('id'):$object->id).((string) $type != ''?'&type='.$type:'').'&action=recalcul&mode='.$mode.'&search_year='.$search_year.'&search_categ='.$search_categ.'">'.img_picto($langs->trans("ReCalculate").' ('.$dategenerated.')','refresh').'</a>';
+			
+			// Show graph
+			print '<table class="noborder" width="100%">';
+			// Label
+			print '<tr class="liste_titre"><td>';
+			print $graphfiles[$key]['label'];
+			print '</td>';
+			print '<td align="right">'.$linktoregenerate.'</td>';
+			print '</tr>';
+			// Image
+			print '<tr class="impair"><td colspan="2" class="nohover" align="center">';
+			print $graphfiles[$key]['output'];
+			print '</td></tr>';
+			print '</table>';
+
+			if ($i % 2 == 0)
+			{
+				print "\n".'</div>'."\n";
+			}
+			else
+			{
+				print "\n".'</div></div></div>';
+				print '<div class="clear"><div class="fichecenter"><br></div></div>'."\n";
+			}
+
+			$i++;
 		}
 	}
-
-	if (GETPOST('id') == 'all')
+	// div not closed
+	if ($i % 2 == 1)
 	{
-	    dol_fiche_end();
+		print "\n".'<div class="fichehalfright"><div class="ficheaddleft">'."\n";
+		print "\n".'</div></div></div>';
+		print '<div class="clear"><div class="fichecenter"><br></div></div>'."\n";
 	}
 }
-else
+
+if (! $id)
 {
-	dol_print_error();
+    dol_fiche_end();
 }
 
 llxFooter();

+ 1 - 1
htdocs/product/stats/commande.php

@@ -94,7 +94,7 @@ if ($id > 0 || ! empty($ref))
 		$head=product_prepare_head($product);
 		$titre=$langs->trans("CardProduct".$product->type);
 		$picto=($product->type==Product::TYPE_SERVICE?'service':'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$product,$action);    // Note that $action and $object may have been modified by hook
 		if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');

+ 1 - 1
htdocs/product/stats/commande_fournisseur.php

@@ -101,7 +101,7 @@ if ($id > 0 || ! empty($ref)) {
 		$head = product_prepare_head($product);
 		$titre = $langs->trans("CardProduct" . $product->type);
 		$picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook
 		if ($reshook < 0)

+ 1 - 1
htdocs/product/stats/contrat.php

@@ -84,7 +84,7 @@ if ($id > 0 || ! empty($ref))
 		$head=product_prepare_head($product);
 		$titre=$langs->trans("CardProduct".$product->type);
 		$picto=($product->type==Product::TYPE_SERVICE?'service':'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$product,$action);    // Note that $action and $object may have been modified by hook
 		if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');

+ 1 - 1
htdocs/product/stats/facture.php

@@ -111,7 +111,7 @@ if ($id > 0 || ! empty($ref))
 		$head=product_prepare_head($product);
 		$titre=$langs->trans("CardProduct".$product->type);
 		$picto=($product->type==Product::TYPE_SERVICE?'service':'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$product,$action);    // Note that $action and $object may have been modified by hook
 		if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');

+ 1 - 1
htdocs/product/stats/facture_fournisseur.php

@@ -96,7 +96,7 @@ if ($id > 0 || ! empty($ref))
 		$head = product_prepare_head($product);
 		$titre = $langs->trans("CardProduct" . $product->type);
 		$picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook
 		if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');

+ 1 - 1
htdocs/product/stats/propal.php

@@ -94,7 +94,7 @@ if ($id > 0 || ! empty($ref))
 		$head = product_prepare_head($product);
 		$titre = $langs->trans("CardProduct" . $product->type);
 		$picto = ($product->type == Product::TYPE_SERVICE ? 'service' : 'product');
-		dol_fiche_head($head, 'referers', $titre, 0, $picto);
+		dol_fiche_head($head, 'referers', $titre, -1, $picto);
 
 		$reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $product, $action); // Note that $action and $object may have been modified by hook
 		if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');

+ 2 - 1
htdocs/product/stock/class/api_stockmovements.class.php

@@ -133,7 +133,8 @@ class StockMovements extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $stockmovement_static = new MouvementStock($db);

+ 2 - 1
htdocs/product/stock/class/api_warehouses.class.php

@@ -131,7 +131,8 @@ class Warehouses extends DolibarrApi
         {
         	$i=0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $warehouse_static = new Entrepot($db);

+ 1 - 1
htdocs/projet/admin/project.php

@@ -318,7 +318,7 @@ print load_fiche_titre($langs->trans("ProjectsSetup"),$linkback,'title_setup');
 
 $head=project_admin_prepare_head();
 
-dol_fiche_head($head, 'project', $langs->trans("Projects"), 0, 'project');
+dol_fiche_head($head, 'project', $langs->trans("Projects"), -1, 'project');
 
 
 

+ 1 - 1
htdocs/projet/admin/project_extrafields.php

@@ -70,7 +70,7 @@ print load_fiche_titre($langs->trans("ProjectsSetup"),$linkback,'title_setup');
 
 $head = project_admin_prepare_head();
 
-dol_fiche_head($head, 'attributes', $langs->trans("Projects"), 0, 'project');
+dol_fiche_head($head, 'attributes', $langs->trans("Projects"), -1, 'project');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 1 - 1
htdocs/projet/admin/project_task_extrafields.php

@@ -69,7 +69,7 @@ print load_fiche_titre($langs->trans("ProjectsSetup"),$linkback,'title_setup');
 
 $head = project_admin_prepare_head();
 
-dol_fiche_head($head, 'attributes_task', $langs->trans("Projects"), 0, 'project');
+dol_fiche_head($head, 'attributes_task', $langs->trans("Projects"), -1, 'project');
 
 require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_view.tpl.php';
 

+ 2 - 1
htdocs/projet/class/api_projects.class.php

@@ -153,7 +153,8 @@ class Projects extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $project_static = new Project($db);

+ 2 - 1
htdocs/projet/class/api_tasks.class.php

@@ -160,7 +160,8 @@ class Tasks extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $task_static = new Task($db);

+ 25 - 25
htdocs/projet/list.php

@@ -141,6 +141,8 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
    }
 }
 
+$object = new Project($db);
+
 
 /*
  * Actions
@@ -200,7 +202,6 @@ if (empty($reshook))
  * View
  */
 
-$projectstatic = new Project($db);
 $socstatic = new Societe($db);
 $form = new Form($db);
 $formother = new FormOther($db);
@@ -212,12 +213,12 @@ $title=$langs->trans("Projects");
 
 // Get list of project id allowed to user (in a string list separated by coma)
 $projectsListId='';
-if (! $user->rights->projet->all->lire) $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user,0,1,$socid);
+if (! $user->rights->projet->all->lire) $projectsListId = $object->getProjectsAuthorizedForUser($user,0,1,$socid);
 
 // Get id of types of contacts for projects (This list never contains a lot of elements)
 $listofprojectcontacttype=array();
 $sql = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc";
-$sql.= " WHERE ctc.element = '" . $projectstatic->element . "'";
+$sql.= " WHERE ctc.element = '" . $object->element . "'";
 $sql.= " AND ctc.source = 'internal'";
 $resql = $db->query($sql);
 if ($resql)
@@ -232,7 +233,7 @@ if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0';
 
 
 $distinct='DISTINCT';   // We add distinct until we are added a protection to be sure a contact of a project and task is only once.
-$sql = "SELECT ".$distinct." p.rowid as projectid, p.ref, p.title, p.fk_statut, p.fk_opp_status, p.public, p.fk_user_creat";
+$sql = "SELECT ".$distinct." p.rowid as id, p.ref, p.title, p.fk_statut, p.fk_opp_status, p.public, p.fk_user_creat";
 $sql.= ", p.datec as date_creation, p.dateo as date_start, p.datee as date_end, p.opp_amount, p.opp_percent, p.tms as date_update, p.budget_amount";
 $sql.= ", s.nom as name, s.rowid as socid";
 $sql.= ", cls.code as opp_status_code";
@@ -360,8 +361,7 @@ $arrayofselected=is_array($toselect)?$toselect:array();
 if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all)
 {
     $obj = $db->fetch_object($resql);
-    $id = $obj->projectid;
-    header("Location: ".DOL_URL_ROOT.'/projet/card.php?id='.$id);
+    header("Location: ".DOL_URL_ROOT.'/projet/card.php?id='.$obj->id);
     exit;
 }
 
@@ -566,7 +566,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
             $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')))
+        	if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select')) && empty($extrafields->attribute_computed[$key]))
 			{
 			    $crit=$val;
 				$tmpkey=preg_replace('/search_options_/','',$key);
@@ -599,7 +599,7 @@ if (! empty($arrayfields['p.fk_statut']['checked']))
 {
 	print '<td class="liste_titre nowrap" align="right">';
     $arrayofstatus = array();
-    foreach($projectstatic->statuts_short as $key => $val) $arrayofstatus[$key]=$langs->trans($val);
+    foreach($object->statuts_short as $key => $val) $arrayofstatus[$key]=$langs->trans($val);
     $arrayofstatus['99']=$langs->trans("NotClosed").' ('.$langs->trans('Draft').'+'.$langs->trans('Opened').')';
 	print $form->selectarray('search_status', $arrayofstatus, $search_status, 1, 0, 0, '', 0, 0, 0, '', 'maxwidth100');
     print '</td>';
@@ -632,7 +632,9 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
         if (! empty($arrayfields["ef.".$key]['checked']))
         {
             $align=$extrafields->getAlignFlag($key);
-            print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+            $sortonfield = "ef.".$key;
+            if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+            print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
         }
     }
 }
@@ -652,15 +654,15 @@ while ($i < min($num,$limit))
 {
 	$obj = $db->fetch_object($resql);
 
-	$projectstatic->id = $obj->projectid;
-	$projectstatic->user_author_id = $obj->fk_user_creat;
-	$projectstatic->public = $obj->public;
-	$projectstatic->ref = $obj->ref;
-	$projectstatic->datee = $db->jdate($obj->date_end);
-	$projectstatic->statut = $obj->fk_statut;
-	$projectstatic->opp_status = $obj->fk_opp_status;
-	 
-	$userAccess = $projectstatic->restrictedProjectArea($user);    // why this ?
+	$object->id = $obj->id;
+	$object->user_author_id = $obj->fk_user_creat;
+	$object->public = $obj->public;
+	$object->ref = $obj->ref;
+	$object->datee = $db->jdate($obj->date_end);
+	$object->statut = $obj->fk_statut;
+	$object->opp_status = $obj->fk_opp_status;
+	
+	$userAccess = $object->restrictedProjectArea($user);    // why this ?
 	if ($userAccess >= 0)
 	{
 		print '<tr class="oddeven">';
@@ -669,8 +671,8 @@ while ($i < min($num,$limit))
     	if (! empty($arrayfields['p.ref']['checked']))
     	{
     		print '<td class="nowrap">';
-    		print $projectstatic->getNomUrl(1);
-    		if ($projectstatic->hasDelay()) print img_warning($langs->trans('Late'));
+    		print $object->getNomUrl(1);
+    		if ($object->hasDelay()) print img_warning($langs->trans('Late'));
     		print '</td>';
 		    if (! $i) $totalarray['nbfield']++;
     	}
@@ -851,8 +853,7 @@ while ($i < min($num,$limit))
 		// Status
 		if (! empty($arrayfields['p.fk_statut']['checked']))
 		{
-    		$projectstatic->statut = $obj->fk_statut;
-    		print '<td align="right">'.$projectstatic->getLibStatut(5).'</td>';
+    		print '<td align="right">'.$object->getLibStatut(5).'</td>';
 			if (! $i) $totalarray['nbfield']++;
 		}
         // Action column
@@ -860,8 +861,8 @@ while ($i < min($num,$limit))
         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->projectid, $arrayofselected)) $selected=1;
-    		print '<input id="cb'.$obj->projectid.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->projectid.'"'.($selected?' checked="checked"':'').'>';
+    		if (in_array($obj->id, $arrayofselected)) $selected=1;
+    		print '<input id="cb'.$obj->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$obj->id.'"'.($selected?' checked="checked"':'').'>';
         }
         print '</td>';
 		if (! $i) $totalarray['nbfield']++;
@@ -871,7 +872,6 @@ while ($i < min($num,$limit))
 	}
 
 	$i++;
-
 }
 
 // Show total line

+ 20 - 17
htdocs/projet/tasks/list.php

@@ -131,6 +131,8 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
     }
 }
 
+$object = new Task($db);
+
 
 /*
  * Actions
@@ -190,11 +192,11 @@ if (empty($search_projectstatus) && $search_projectstatus == '') $search_project
  * View
  */
 
+$now = dol_now();
 $form=new Form($db);
 $formother=new FormOther($db);
 $socstatic=new Societe($db);
 $projectstatic = new Project($db);
-$taskstatic = new Task($db);
 $puser=new User($db);
 $tuser=new User($db);
 if ($search_project_user > 0) $puser->fetch($search_project_user);
@@ -231,7 +233,7 @@ if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0';
 // Get id of types of contacts for tasks (This list never contains a lot of elements)
 $listoftaskcontacttype=array();
 $sql = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc";
-$sql.= " WHERE ctc.element = '" . $taskstatic->element . "'";
+$sql.= " WHERE ctc.element = '" . $object->element . "'";
 $sql.= " AND ctc.source = 'internal'";
 $resql = $db->query($sql);
 if ($resql)
@@ -549,7 +551,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
             $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')))
+        	if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select')) && empty($extrafields->attribute_computed[$key]))
 			{
 			    $crit=$val;
 				$tmpkey=preg_replace('/search_options_/','',$key);
@@ -606,7 +608,9 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
         if (! empty($arrayfields["ef.".$key]['checked']))
         {
             $align=$extrafields->getAlignFlag($key);
-            print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+            $sortonfield = "ef.".$key;
+            if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+            print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
         }
     }
 }
@@ -624,14 +628,21 @@ $plannedworkloadoutputformat='allhourmin';
 $timespentoutputformat='allhourmin';
 if (! empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) $plannedworkloadoutputformat=$conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
 if (! empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) $timespentoutputformat=$conf->global->PROJECT_TIME_SPENT_FORMAT;
- 
-$now = dol_now();
+
 $i=0;
 $totalarray=array();
 while ($i < min($num,$limit))
 {
 	$obj = $db->fetch_object($resql);
 
+	$object->id = $obj->id;
+	$object->ref = $obj->ref;
+	$object->label = $obj->label;
+	$object->fk_statut = $obj->fk_statut;
+	$object->progress = $obj->progress;
+	$object->datee = $db->jdate($obj->date_end);	// deprecated
+	$object->date_end = $db->jdate($obj->date_end);
+
 	$projectstatic->id = $obj->projectid;
 	$projectstatic->ref = $obj->projectref;
 	$projectstatic->title = $obj->projecttitle;
@@ -639,14 +650,6 @@ while ($i < min($num,$limit))
 	$projectstatic->statut = $obj->projectstatus;
 	$projectstatic->datee = $db->jdate($obj->projectdatee);
 	
-	$taskstatic->id = $obj->id;
-	$taskstatic->ref = $obj->ref;
-	$taskstatic->label = $obj->label;
-	$taskstatic->fk_statut = $obj->fk_statut;
-	$taskstatic->progress = $obj->progress;
-	$taskstatic->datee = $db->jdate($obj->date_end);	// deprecated
-	$taskstatic->date_end = $db->jdate($obj->date_end);
-	
 	$userAccess = $projectstatic->restrictedProjectArea($user);    // why this ?
 	if ($userAccess >= 0)
 	{
@@ -656,8 +659,8 @@ while ($i < min($num,$limit))
     	if (! empty($arrayfields['t.ref']['checked']))
     	{
     	    print '<td>';
-    	    print $taskstatic->getNomUrl(1,'withproject');
-    		if ($taskstatic->hasDelay()) print img_warning("Late");
+    	    print $object->getNomUrl(1,'withproject');
+    		if ($object->hasDelay()) print img_warning("Late");
     	    print '</td>';
 		    if (! $i) $totalarray['nbfield']++;
     	}        	 
@@ -665,7 +668,7 @@ while ($i < min($num,$limit))
     	if (! empty($arrayfields['t.label']['checked']))
     	{
     	    print '<td>';
-    	    print $taskstatic->label;
+    	    print $object->label;
     	    print '</td>';
 		    if (! $i) $totalarray['nbfield']++;
     	}

+ 2 - 2
htdocs/projet/tasks/time.php

@@ -96,7 +96,7 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e
 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
 
 // Purge search criteria
-if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All test are required to be compatible with all browsers
+if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") ||GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
 {
     $search_date='';
     $search_datehour='';
@@ -305,7 +305,7 @@ if (($id > 0 || ! empty($ref)) || $projectidforalltimes > 0)
 			// Tabs for project
 			$tab='tasks';
 			$head=project_prepare_head($projectstatic);
-			dol_fiche_head($head, $tab, $langs->trans("Project"), 0, ($projectstatic->public?'projectpub':'project'));
+			dol_fiche_head($head, $tab, $langs->trans("Project"), -1, ($projectstatic->public?'projectpub':'project'));
 
 			$param=($mode=='mine'?'&mode=mine':'');
 

+ 3 - 0
htdocs/public/opensurvey/studs.php

@@ -47,6 +47,9 @@ $nblignes=$object->fetch_lines();
 //If the survey has not yet finished, then it can be modified
 $canbemodified = ((empty($object->date_fin) || $object->date_fin > dol_now()) && $object->status != Opensurveysondage::STATUS_CLOSED);
 
+// Security check
+if (empty($conf->opensurvey->enabled)) accessforbidden('',0,0,1);
+
 
 /*
  * Actions

+ 28 - 11
htdocs/resource/card.php

@@ -221,29 +221,41 @@ if ( $object->fetch($id) > 0 )
 	}
 	else
 	{
-		dol_fiche_head($head, 'resource', $langs->trans("ResourceSingular"),0,'resource');
+		dol_fiche_head($head, 'resource', $langs->trans("ResourceSingular"), -1, 'resource');
 
+		$formconfirm = '';
+		
 		// Confirm deleting resource line
 	    if ($action == 'delete')
 	    {
-	        print $form->formconfirm("card.php?&id=".$id,$langs->trans("DeleteResource"),$langs->trans("ConfirmDeleteResource"),"confirm_delete_resource",'','',1);
+	        $formconfirm = $form->formconfirm("card.php?&id=".$id,$langs->trans("DeleteResource"),$langs->trans("ConfirmDeleteResource"),"confirm_delete_resource",'','',1);
 	    }
 
-
+	    // Print form confirm
+	    print $formconfirm;
+	    
+	    
+	    $linkback = '<a href="' . DOL_URL_ROOT . '/resource/list.php' . (! empty($socid) ? '?id=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	    
+	    
+	    $morehtmlref='<div class="refidno">';
+	    $morehtmlref.='</div>';
+	    
+	    
+	    dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref);
+	    
+	    
+	    print '<div class="fichecenter">';
+	    print '<div class="underbanner clearboth"></div>';
+	    
 		/*---------------------------------------
 		 * View object
 		 */
 		print '<table width="100%" class="border">';
 
-		print '<tr><td class="titlefield">'.$langs->trans("ResourceFormLabel_ref").'</td><td>';
-		$linkback = $objet->ref.' <a href="list.php">'.$langs->trans("BackToList").'</a>';
-		print $form->showrefnav($object, 'id', $linkback,1,"rowid");
-		print '</td>';
-		print '</tr>';
-
 		// Resource type
 		print '<tr>';
-		print '<td>' . $langs->trans("ResourceType") . '</td>';
+		print '<td class="titlefield">' . $langs->trans("ResourceType") . '</td>';
 		print '<td>';
 		print $object->type_label;
 		print '</td>';
@@ -267,9 +279,14 @@ if ( $object->fetch($id) > 0 )
 		print '</tr>';
 
 		print '</table>';
+		
+		print '</div>';
+		
+		print '<div class="clearboth"></div><br>';
+		
+		dol_fiche_end();
 	}
 
-	print '</div>';
 
 	/*
 	 * Boutons actions

+ 39 - 12
htdocs/resource/class/dolresource.class.php

@@ -30,18 +30,19 @@ require_once DOL_DOCUMENT_ROOT."/core/lib/functions2.lib.php";
  */
 class Dolresource extends CommonObject
 {
-	var $element='dolresource';			//!< Id that identify managed objects
-	var $table_element='resource';	//!< Name of table without prefix where object is stored
-
-	var $resource_id;
-	var $resource_type;
-	var $element_id;
-	var $element_type;
-	var $busy;
-	var $mandatory;
-	var $fk_user_create;
-	var $type_label;
-	var $tms='';
+	public $element='dolresource';			//!< Id that identify managed objects
+	public $table_element='resource';	//!< Name of table without prefix where object is stored
+    public $picto = 'resource';
+    
+	public $resource_id;
+	public $resource_type;
+	public $element_id;
+	public $element_type;
+	public $busy;
+	public $mandatory;
+	public $fk_user_create;
+	public $type_label;
+	public $tms='';
 
     /**
      *  Constructor
@@ -974,4 +975,30 @@ class Dolresource extends CommonObject
         $result.=$link.$this->ref.$linkend;
         return $result;
     }
+    
+    
+    /**
+     *  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)
+    {
+        return $this->LibStatut($this->status,$mode);
+    }
+    
+    /**
+     *  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 $langs;
+    
+        return '';
+    }    
 }

+ 21 - 12
htdocs/resource/contact.php

@@ -119,23 +119,30 @@ if ($id > 0 || ! empty($ref))
 
 
 	$head = resource_prepare_head($object);
-	dol_fiche_head($head, 'contact', $langs->trans("ResourceSingular"), 0, 'resource');
+	dol_fiche_head($head, 'contact', $langs->trans("ResourceSingular"), -1, 'resource');
+
+
+	$linkback = '<a href="' . DOL_URL_ROOT . '/resource/list.php' . (! empty($socid) ? '?id=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	 
+	 
+	$morehtmlref='<div class="refidno">';
+	$morehtmlref.='</div>';
+	 
+	 
+	dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref);
+	 
+	 
+	print '<div class="fichecenter">';
+	print '<div class="underbanner clearboth"></div>';
+	 
+	
+	// Object
 
-
-	/*
-	*   Resource synthese pour rappel
-	*/
 	print '<table width="100%" class="border">';
 
-	print '<tr><td class="titlefield">'.$langs->trans("ResourceFormLabel_ref").'</td><td>';
-	$linkback = $objet->ref.' <a href="list.php">'.$langs->trans("BackToList").'</a>';
-	print $form->showrefnav($object, 'id', $linkback,1,"rowid");
-	print '</td>';
-	print '</tr>';
-
 	// Resource type
 	print '<tr>';
-	print '<td>' . $langs->trans("ResourceType") . '</td>';
+	print '<td class="titlefield">' . $langs->trans("ResourceType") . '</td>';
 	print '<td>';
 	print $object->type_label;
 	print '</td>';
@@ -144,6 +151,8 @@ if ($id > 0 || ! empty($ref))
 	print '</table>';
 	print '</div>';
 
+	dol_fiche_end();
+	
 	print '<br>';
 
 	if (! empty($conf->global->RESOURCE_HIDE_ADD_CONTACT_USER))     $hideaddcontactforuser=1;

+ 18 - 10
htdocs/resource/document.php

@@ -89,7 +89,7 @@ if ($object->id)
 
 	$head=resource_prepare_head($object);
 
-	dol_fiche_head($head, 'documents',  $langs->trans("ResourceSingular"), 0, 'resource');
+	dol_fiche_head($head, 'documents',  $langs->trans("ResourceSingular"), -1, 'resource');
 
 
 	// Construit liste des fichiers
@@ -100,19 +100,25 @@ if ($object->id)
 		$totalsize+=$file['size'];
 	}
 
-
+	
+	$linkback = '<a href="' . DOL_URL_ROOT . '/resource/list.php' . (! empty($socid) ? '?id=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	 
+	 
+	$morehtmlref='<div class="refidno">';
+	$morehtmlref.='</div>';
+	 
+	 
+	dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref);
+	 
+	 
+	print '<div class="fichecenter">';
+	print '<div class="underbanner clearboth"></div>';
+	 
     print '<table class="border" width="100%">';
 
-
-	print '<tr><td class="titlefield">'.$langs->trans("ResourceFormLabel_ref").'</td><td>';
-	$linkback = $objet->ref.' <a href="list.php">'.$langs->trans("BackToList").'</a>';
-	print $form->showrefnav($object, 'id', $linkback,1,"rowid");
-	print '</td>';
-	print '</tr>';
-
 	// Resource type
 	print '<tr>';
-	print '<td>' . $langs->trans("ResourceType") . '</td>';
+	print '<td class="titlefield">' . $langs->trans("ResourceType") . '</td>';
 	print '<td>';
 	print $object->type_label;
 	print '</td>';
@@ -124,6 +130,8 @@ if ($object->id)
 
     print '</div>';
 
+    dol_fiche_end();
+    
     $modulepart = 'dolresource';
     $permission = $user->rights->resource->write;
     $param = '&id=' . $object->id;

+ 21 - 10
htdocs/resource/note.php

@@ -64,24 +64,35 @@ $form = new Form($db);
 if ($id > 0 || ! empty($ref))
 {
 	$head = resource_prepare_head($object);
-	dol_fiche_head($head, 'note', $langs->trans('ResourceSingular'), 0, 'resource');
-
+	dol_fiche_head($head, 'note', $langs->trans('ResourceSingular'), -1, 'resource');
+
+	$linkback = '<a href="' . DOL_URL_ROOT . '/resource/list.php' . (! empty($socid) ? '?id=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
+	 
+	 
+	$morehtmlref='<div class="refidno">';
+	$morehtmlref.='</div>';
+	 
+	 
+	dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref);
+	 
+	 
+	print '<div class="fichecenter">';
+	print '<div class="underbanner clearboth"></div>';
+	 
 	print '<table class="border" width="100%">';
-	print '<tr><td class="titlefield">'.$langs->trans("ResourceFormLabel_ref").'</td><td>';
-	$linkback = $objet->ref.' <a href="list.php">'.$langs->trans("BackToList").'</a>';
-	print $form->showrefnav($object, 'id', $linkback,1,"rowid");
-	print '</td>';
-	print '</tr>';
 
 	// Resource type
 	print '<tr>';
-	print '<td>' . $langs->trans("ResourceType") . '</td>';
+	print '<td class="titlefield">' . $langs->trans("ResourceType") . '</td>';
 	print '<td>';
 	print $object->type_label;
 	print '</td>';
-	print '</tr>';		print "</table>";
+	print '</tr>';
+	
+	print "</table>";
 
-	print '<br>';
+	print '</div>';
+	
 	$permission=$user->rights->resource->write;
 	$cssclass='titlefield';
 	include DOL_DOCUMENT_ROOT.'/core/tpl/notes.tpl.php';

+ 5 - 3
htdocs/societe/card.php

@@ -1544,7 +1544,7 @@ else
 
             dol_fiche_head($head, 'card', $langs->trans("ThirdParty"), 0, 'company');
 
-
+            print '<div class="fichecenter2">'; 
             print '<table class="border" width="100%">';
 
             // Ref/ID
@@ -1934,7 +1934,8 @@ else
             print '</tr>';
 
             print '</table>';
-
+            print '</div>';
+            
 	        dol_fiche_end();
 
             print '<div align="center">';
@@ -1951,13 +1952,14 @@ else
         /*
          * View
          */
+        
         if (!empty($object->id)) $res=$object->fetch_optionals($object->id,$extralabels);
         //if ($res < 0) { dol_print_error($db); exit; }
 
 
         $head = societe_prepare_head($object);
 
-        dol_fiche_head($head, 'card', $langs->trans("ThirdParty"), 0, 'company');
+        dol_fiche_head($head, 'card', $langs->trans("ThirdParty"), -1, 'company');
 
         // Confirm delete third party
         if ($action == 'delete' || ($conf->use_javascript_ajax && empty($conf->dol_use_jmobile)))

+ 2 - 1
htdocs/societe/class/api_contacts.class.php

@@ -153,7 +153,8 @@ class Contacts extends DolibarrApi
 		if ($result)
 		{
 			$num = $db->num_rows($result);
-			while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+			$min = min($num, ($limit <= 0 ? $num : $limit));
+			while ($i < $min)
 			{
 				$obj = $db->fetch_object($result);
 				$contact_static = new Contact($db);

+ 2 - 1
htdocs/societe/class/api_deprecated_contact.class.php

@@ -167,7 +167,8 @@ class ContactApi extends DolibarrApi
 		{
 			$i = 0;
 		    $num = $db->num_rows($result);
-			while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+		    $min = min($num, ($limit <= 0 ? $num : $limit));
+			while ($i < $min)
 			{
 				$obj = $db->fetch_object($result);
 				$contact_static = new Contact($db);

+ 2 - 1
htdocs/societe/class/api_deprecated_thirdparty.class.php

@@ -214,7 +214,8 @@ class ThirdpartyApi extends DolibarrApi
         {
 			$i = 0;
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $soc_static = new Societe($db);

+ 22 - 2
htdocs/societe/class/api_thirdparties.class.php

@@ -156,7 +156,8 @@ class Thirdparties extends DolibarrApi
         if ($result)
         {
             $num = $db->num_rows($result);
-            while ($i < min($num, ($limit <= 0 ? $num : $limit)))
+            $min = min($num, ($limit <= 0 ? $num : $limit));
+            while ($i < $min)
             {
                 $obj = $db->fetch_object($result);
                 $soc_static = new Societe($db);
@@ -310,7 +311,26 @@ class Thirdparties extends DolibarrApi
       return $this->company;
     }
 
-    /**
+	/**
+	 * Clean sensible object datas
+	 *
+	 * @param   object  $object    Object to clean
+	 * @return    array    Array of cleaned object properties
+	 */
+	function _cleanObjectDatas($object) {
+	
+	    $object = parent::_cleanObjectDatas($object);
+	
+	    unset($object->total_ht);
+	    unset($object->total_tva);
+	    unset($object->total_localtax1);
+	    unset($object->total_localtax2);
+	    unset($object->total_ttc);
+	    
+	    return $object;
+	}	
+	
+	/**
      * Validate fields before create or update object
      * 
      * @param array $data   Datas to validate

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

@@ -389,8 +389,6 @@ class Societe extends CommonObject
         $this->forme_juridique_code  = 0;
         $this->tva_assuj = 1;
         $this->status = 1;
-
-        return 1;
     }
 
 

+ 9 - 5
htdocs/societe/list.php

@@ -187,6 +187,8 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
    }
 }
 
+$object = new Societe($db);
+
 
 /*
  * Actions
@@ -196,7 +198,7 @@ if (GETPOST('cancel')) { $action='list'; $massaction=''; }
 if (! GETPOST('confirmmassaction') && $massaction != 'presend' && $massaction != 'confirm_presend') { $massaction=''; }
 
 $parameters=array();
-$reshook=$hookmanager->executeHooks('doActions',$parameters);    // Note that $action and $object may have been modified by some hooks
+$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))
@@ -204,7 +206,7 @@ if (empty($reshook))
     // Selection of new fields
     include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php';
 
-    // Do we click on purge search criteria ?
+    // Did we click on purge search criteria ?
     if (GETPOST("button_removefilter_x") || GETPOST("button_removefilter.x") || GETPOST("button_removefilter")) // All tests are required to be compatible with all browsers
     {
         $search_nom='';
@@ -603,7 +605,7 @@ if ($user->rights->societe->client->voir || $socid)
 	$moreforfilter.=$formother->select_salesrepresentatives($search_sale,'search_sale',$user, 0, 1, 'maxwidth300');
 	$moreforfilter.='</div>';
 }
-if (! empty($moreforfilter))
+if ($moreforfilter)
 {
 	print '<div class="liste_titre liste_titre_bydiv centpercent">';
 	print $moreforfilter;
@@ -829,7 +831,7 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
             $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')))
+		    if (in_array($typeofextrafield, array('varchar', 'int', 'double', 'select')) && empty($extrafields->attribute_computed[$key]))
 			{
 			    $crit=$val;
 				$tmpkey=preg_replace('/search_options_/','',$key);
@@ -905,7 +907,9 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
         if (! empty($arrayfields["ef.".$key]['checked']))
         {
             $align=$extrafields->getAlignFlag($key);
-            print_liste_field_titre($extralabels[$key],$_SERVER["PHP_SELF"],"ef.".$key,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
+            $sortonfield = "ef.".$key;
+            if (! empty($extrafields->attribute_computed[$key])) $sortonfield='';
+            print_liste_field_titre($langs->trans($extralabels[$key]),$_SERVER["PHP_SELF"],$sortonfield,"",$param,($align?'align="'.$align.'"':''),$sortfield,$sortorder);
         }
     }
 }

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

@@ -698,7 +698,7 @@ div.fiche>form>div.div-table-responsive {
     justify-content: flex-start;
 }
 .thumbstat {
-	flex: 1 1 114px;
+	flex: 1 1 116px;
 }
 .thumbstat150 {
 	flex: 1 1 170px;

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.