Browse Source

Merge branch 'develop' into patch-301

Laurent Destailleur 5 years ago
parent
commit
b66c2a29a2
100 changed files with 4525 additions and 2185 deletions
  1. 10 0
      .github/ISSUE_TEMPLATE/custom.md
  2. 38 44
      .travis.yml
  3. 15 0
      ChangeLog
  4. 2 1
      build/docker/Dockerfile
  5. 231 0
      dev/initdata/dbf/import-dbf.php
  6. 241 0
      dev/initdata/dbf/importdb-products.php
  7. 355 0
      dev/initdata/dbf/importdb-thirdparties.php
  8. 402 0
      dev/initdata/dbf/includes/dbase.class.php
  9. 1 1
      dev/initdata/generate-invoice.php
  10. 1 1
      dev/initdata/generate-order.php
  11. 1 1
      dev/initdata/generate-product.php
  12. 1 1
      dev/initdata/generate-proposal.php
  13. 1 1
      dev/initdata/generate-thirdparty.php
  14. 1 1
      dev/initdata/import-products.php
  15. 1 1
      dev/initdata/import-thirdparties.php
  16. 1 1
      dev/initdata/import-users.php
  17. 1 0
      dev/setup/codesniffer/ruleset.xml
  18. 23 7
      htdocs/accountancy/admin/account.php
  19. 16 2
      htdocs/accountancy/admin/card.php
  20. 10 1
      htdocs/accountancy/bookkeeping/list.php
  21. 6 6
      htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php
  22. 8 8
      htdocs/accountancy/bookkeeping/thirdparty_lettering_supplier.php
  23. 27 8
      htdocs/accountancy/class/accountingaccount.class.php
  24. 19 19
      htdocs/accountancy/class/bookkeeping.class.php
  25. 3 2
      htdocs/accountancy/class/lettering.class.php
  26. 2 2
      htdocs/adherents/card.php
  27. 297 241
      htdocs/adherents/class/adherent.class.php
  28. 20 0
      htdocs/adherents/class/subscription.class.php
  29. 1 1
      htdocs/adherents/subscription.php
  30. 8 4
      htdocs/adherents/type.php
  31. 2 2
      htdocs/admin/agenda_other.php
  32. 1 0
      htdocs/admin/agenda_xcal.php
  33. 5 3
      htdocs/admin/bom.php
  34. 15 12
      htdocs/admin/commande.php
  35. 57 23
      htdocs/admin/company.php
  36. 13 10
      htdocs/admin/contract.php
  37. 4 0
      htdocs/admin/delais.php
  38. 126 123
      htdocs/admin/facture.php
  39. 4 1
      htdocs/admin/fichinter.php
  40. 5 2
      htdocs/admin/holiday.php
  41. 4 2
      htdocs/admin/ihm.php
  42. 74 41
      htdocs/admin/limits.php
  43. 1 1
      htdocs/admin/mails.php
  44. 7 7
      htdocs/admin/mails_senderprofile_list.php
  45. 66 64
      htdocs/admin/mrp.php
  46. 1 0
      htdocs/admin/notification.php
  47. 9 9
      htdocs/admin/order_extrafields.php
  48. 9 9
      htdocs/admin/orderdet_extrafields.php
  49. 76 37
      htdocs/admin/perms.php
  50. 7 4
      htdocs/admin/propal.php
  51. 7 4
      htdocs/admin/reception_setup.php
  52. 7 4
      htdocs/admin/stock.php
  53. 8 5
      htdocs/admin/supplier_invoice.php
  54. 6 3
      htdocs/admin/supplier_order.php
  55. 5 2
      htdocs/admin/supplier_payment.php
  56. 7 4
      htdocs/admin/supplier_proposal.php
  57. 110 6
      htdocs/admin/system/phpinfo.php
  58. 2 2
      htdocs/admin/ticket.php
  59. 42 42
      htdocs/admin/tools/dolibarr_export.php
  60. 85 85
      htdocs/admin/tools/listevents.php
  61. 1 1
      htdocs/asset/class/asset.class.php
  62. 11 0
      htdocs/asset/class/asset_type.class.php
  63. 124 118
      htdocs/asset/list.php
  64. 1 1
      htdocs/bom/class/bom.class.php
  65. 5 0
      htdocs/categories/class/api_categories.class.php
  66. 8 0
      htdocs/categories/class/categorie.class.php
  67. 36 2
      htdocs/categories/index.php
  68. 56 2
      htdocs/categories/viewcat.php
  69. 36 0
      htdocs/comm/action/card.php
  70. 284 143
      htdocs/comm/action/class/actioncomm.class.php
  71. 105 1
      htdocs/comm/action/index.php
  72. 1 1
      htdocs/comm/action/list.php
  73. 5 5
      htdocs/comm/card.php
  74. 1 1
      htdocs/comm/index.php
  75. 42 18
      htdocs/comm/propal/class/propal.class.php
  76. 131 120
      htdocs/comm/propal/list.php
  77. 285 285
      htdocs/commande/class/commande.class.php
  78. 107 69
      htdocs/commande/list.php
  79. 1 1
      htdocs/compta/bank/card.php
  80. 109 77
      htdocs/compta/bank/various_payment/list.php
  81. 27 27
      htdocs/compta/cashcontrol/report.php
  82. 35 16
      htdocs/compta/facture/card.php
  83. 77 4
      htdocs/compta/facture/class/facture-rec.class.php
  84. 104 7
      htdocs/compta/facture/class/facture.class.php
  85. 37 31
      htdocs/compta/facture/list.php
  86. 7 5
      htdocs/compta/paiement.php
  87. 0 22
      htdocs/compta/paiement/class/paiement.class.php
  88. 7 7
      htdocs/compta/prelevement/card.php
  89. 42 42
      htdocs/compta/prelevement/create.php
  90. 37 37
      htdocs/compta/prelevement/demandes.php
  91. 1 1
      htdocs/compta/recap-compta.php
  92. 43 43
      htdocs/compta/sociales/card.php
  93. 44 44
      htdocs/compta/sociales/class/chargesociales.class.php
  94. 23 23
      htdocs/compta/tva/document.php
  95. 1 1
      htdocs/contact/card.php
  96. 6 2
      htdocs/contact/class/contact.class.php
  97. 1 1
      htdocs/contrat/card.php
  98. 51 45
      htdocs/contrat/class/contrat.class.php
  99. 101 101
      htdocs/contrat/services_list.php
  100. 24 20
      htdocs/core/actions_setmoduleoptions.inc.php

+ 10 - 0
.github/ISSUE_TEMPLATE/custom.md

@@ -0,0 +1,10 @@
+---
+name: Custom issue template
+about: Describe this issue template's purpose here.
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+

+ 38 - 44
.travis.yml

@@ -2,8 +2,8 @@
 # from Dolibarr GitHub repository.
 # For syntax, see http://about.travis-ci.org/docs/user/languages/php/
 
-# We use dist: trusty to have php 5.4+ available
-dist: trusty
+# We use dist: xenial to have php 5.6+ available
+dist: xenial
 sudo: required
 
 language: php
@@ -11,14 +11,16 @@ language: php
 # Start on every boot
 services:
 - memcached
+- mysql
+- postgresql
 
 addons:
-  mariadb: '10.0'
-  postgresql: '9.3'
+  # Force postgresql to 9.4 (the oldest availablable on xenial)
+  postgresql: '9.4'
   apt:
     sources:
-    # To use the last version of pgloader, we add repo of postgresql
-    - pgdg-trusty
+    # To use the last version of pgloader, we add repo of postgresql with a name available in http://apt.postgresql.org/pub/repos/apt/
+    - pgdg-xenial
     packages:
     # We need a webserver to test the webservices
     # Let's install Apache with.
@@ -29,7 +31,6 @@ addons:
     - pgloader
 
 php:
-- '5.5'
 - '5.6'
 - '7.0'
 - '7.1'
@@ -44,11 +45,9 @@ env:
   - DEBUG=false
   matrix:
   # MariaDB overrides MySQL installation so it's not possible to test both yet
-  #- DB=mysql
-  - DB=mariadb
+  #- DB=mariadb
+  - DB=mysql
   - DB=postgresql
-  # TODO
-  #- DB=sqlite
   # See https://docs.travis-ci.com/user/languages/php/#Apache-%2B-PHP
   #- WS=apache
   # See https://github.com/DracoBlue/travis-ci-nginx-php-fpm-test
@@ -60,18 +59,14 @@ matrix:
   - php: nightly
   # We exclude some combinations not usefull to save Travis CPU
   exclude:
-  - php: '5.6'
-    env: DB=mariadb
   - php: '7.0'
-    env: DB=mariadb
+    env: DB=mysql
   - php: '7.1'
-    env: DB=mariadb
+    env: DB=mysql
   - php: '7.2'
-    env: DB=mariadb
+    env: DB=mysql
   - php: '7.3'
-    env: DB=mariadb
-  - php: '5.6'
-    env: DB=postgresql
+    env: DB=mysql
   - php: '7.0'
     env: DB=postgresql
   - php: '7.1'
@@ -188,32 +183,31 @@ before_script:
     # Check Apache version
     echo "Apache version"
     apache2 -v | head -
-    # Check MariaDb
-    echo "MariaDb version"
+    # Check Database
+    echo "Database version"
     mysql --version | head -
     mysql -e "SELECT VERSION();"  | head -
+    psql --version
     echo
 
   - |
     echo "Setting up database"
     if [ "$DB" = 'mysql' ] || [ "$DB" = 'mariadb' ] || [ "$DB" = 'postgresql' ]; then
       echo "MySQL"
-      mysql -e 'DROP DATABASE IF EXISTS travis;'
-      mysql -e 'CREATE DATABASE IF NOT EXISTS travis;'
-      mysql -e 'GRANT ALL PRIVILEGES ON travis.* TO travis@127.0.0.1;'
-      mysql -e 'FLUSH PRIVILEGES;'
-      mysql -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql
+      mysql -u root -e 'DROP DATABASE IF EXISTS travis;'
+      mysql -u root -e 'CREATE DATABASE IF NOT EXISTS travis;'
+      mysql -u root -e 'GRANT ALL PRIVILEGES ON travis.* TO travis@127.0.0.1;'
+      mysql -u root -e 'FLUSH PRIVILEGES;'
+      mysql -u root -D travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql
     fi
     if [ "$DB" = 'postgresql' ]; then
-      #pgsql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql
-      #pgloader mysql://root:pass@127.0.0.1/dolibarr_9 postgresql://dolibarrowner:dolibarrownerpass@127.0.0.1/dolibarr_dev
-      echo pgloader mysql://root@127.0.0.1/travis postgresql:///travis
-      pgloader mysql://root@127.0.0.1/travis postgresql:///travis
-      echo 'ALTER SEQUENCE llx_accountingaccount_rowid_seq RENAME TO llx_accounting_account_rowid_seq' | psql travis
-      echo 'ALTER SEQUENCE llx_accounting_account_rowid_seq RESTART WITH 1000001;' | psql travis
-      #echo 'select * from INFORMATION_SCHEMA.COLUMNS where table_name = 'llx_accountingaccount' | psql travis
-      #echo 'select * from information_schema.table_constraints;' | psql travis
-      #echo 'ALTER TABLE "llx_accounting_account" DROP CONSTRAINT "idx_16390_primary"' | psql travis
+      #psql -c 'create database travis;' -U postgres
+      #psql travis < dev/initdemo/mysqldump_dolibarr_3.5.0.sql
+      #pgloader mysql://root:pass@127.0.0.1/dolibarr_src postgresql://dolibarrowner:dolibarrownerpass@127.0.0.1/dolibarr_dest
+      echo pgloader mysql://root@127.0.0.1/travis postgresql://postgres@/travis
+      pgloader mysql://root@127.0.0.1/travis postgresql://postgres@/travis
+      echo 'ALTER SEQUENCE llx_accountingaccount_rowid_seq RENAME TO llx_accounting_account_rowid_seq' | psql -U postgres travis
+      echo 'ALTER SEQUENCE llx_accounting_account_rowid_seq RESTART WITH 1000001;' | psql -U postgres travis
     fi
     echo
 
@@ -262,10 +256,7 @@ before_script:
   - sudo sed -i -e "s,www-data,travis,g" /etc/apache2/envvars
   - sudo chown -R travis:travis /var/lib/apache2/fastcgi
   - ~/.phpenv/versions/$(phpenv version-name)/sbin/php-fpm
-  # configure apache virtual hosts for precise
-  #- sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default
-  #- sudo cat /etc/apache2/sites-available/default
-  # configure apache virtual hosts for trusty
+  # configure apache virtual hosts
   - sudo cp -f build/travis-ci/apache.conf /etc/apache2/sites-available/000-default.conf
   - sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/000-default.conf
   - sudo cat /etc/apache2/sites-available/000-default.conf
@@ -290,7 +281,7 @@ script:
   # Ensure we catch errors
   set -e
   #parallel-lint --exclude htdocs/includes --blame .
-  parallel-lint --exclude dev/namespacemig --exclude htdocs/includes/sabre --exclude htdocs/includes/phpoffice/phpexcel/Classes/PHPExcel/Shared --exclude htdocs/includes/phpoffice/PhpSpreadsheet --exclude htdocs/includes/sebastian --exclude htdocs/includes/squizlabs/php_codesniffer/tests --exclude htdocs/includes/jakub-onderka/php-parallel-lint/tests --exclude htdocs/includes/mike42/escpos-php/example --exclude htdocs/includes/phpunit/php-token-stream/tests --exclude htdocs/includes/composer/autoload_static.php --blame .
+  parallel-lint --exclude dev/namespacemig --exclude dev/initdata/dbf/includes --exclude htdocs/includes/sabre --exclude htdocs/includes/phpoffice/phpexcel/Classes/PHPExcel/Shared --exclude htdocs/includes/phpoffice/PhpSpreadsheet --exclude htdocs/includes/sebastian --exclude htdocs/includes/squizlabs/php_codesniffer --exclude htdocs/includes/jakub-onderka --exclude htdocs/includes/mike42/escpos-php/example --exclude htdocs/includes/phpunit/ --exclude htdocs/includes/composer/autoload_static.php --blame .
   set +e
   echo
 
@@ -406,9 +397,12 @@ script:
   php upgrade.php 9.0.0 10.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade9001000.log
   php upgrade2.php 9.0.0 10.0.0 > $TRAVIS_BUILD_DIR/upgrade9001000-2.log
   php step5.php 9.0.0 10.0.0 > $TRAVIS_BUILD_DIR/upgrade9001000-3.log
-  php upgrade.php 10.0.0 11.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade9001000.log
-  php upgrade2.php 10.0.0 11.0.0 > $TRAVIS_BUILD_DIR/upgrade9001000-2.log
-  php step5.php 10.0.0 11.0.0 > $TRAVIS_BUILD_DIR/upgrade9001000-3.log
+  php upgrade.php 10.0.0 11.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade10001100.log
+  php upgrade2.php 10.0.0 11.0.0 > $TRAVIS_BUILD_DIR/upgrade10001100-2.log
+  php step5.php 10.0.0 11.0.0 > $TRAVIS_BUILD_DIR/upgrade10001100-3.log
+  php upgrade.php 11.0.0 12.0.0 ignoredbversion > $TRAVIS_BUILD_DIR/upgrade11001200.log
+  php upgrade2.php 11.0.0 12.0.0 > $TRAVIS_BUILD_DIR/upgrade11001200-2.log
+  php step5.php 11.0.0 12.0.0 > $TRAVIS_BUILD_DIR/upgrade11001200-3.log
   # Enable modules not enabled into original dump
   php upgrade2.php 0.0.0 0.0.0 MAIN_MODULE_API,MAIN_MODULE_SUPPLIERPROPOSAL,MAIN_MODULE_WEBSITE,MAIN_MODULE_TICKETSUP,MAIN_MODULE_ACCOUNTING > $TRAVIS_BUILD_DIR/enablemodule.log
   echo $?
@@ -455,7 +449,7 @@ after_failure:
     # Dolibarr log file
     echo "Debugging informations for file dolibarr.log (latest 50 lines)"
     tail -n 50 $TRAVIS_BUILD_DIR/documents/dolibarr.log
-    # MariaDB log file
+    # Database log file
     echo "Debugging informations for file mysql error.log"
     sudo tail -n 50 /var/log/mysql/error.log
     # TODO: PostgreSQL log file

+ 15 - 0
ChangeLog

@@ -3,6 +3,21 @@ English Dolibarr ChangeLog
 --------------------------------------------------------------
 
 
+***** ChangeLog for 12.0.0 compared to 11.0.0 *****
+For Users:
+
+
+For Developers or integrators:
+
+
+
+WARNING:
+
+Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
+* PHP 5.5 is no more supported. Minimum PHP is now 5.6+.
+
+  
+  
 ***** ChangeLog for 11.0.0 compared to 10.0.0 *****
 For Users:
 

+ 2 - 1
build/docker/Dockerfile

@@ -3,10 +3,11 @@ FROM php:7.2-apache
 ENV HOST_USER_ID 33
 ENV PHP_INI_DATE_TIMEZONE 'UTC'
 
-RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev libldap2-dev zlib1g-dev libicu-dev g++\
+RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev libldap2-dev libzip-dev zlib1g-dev libicu-dev g++\
 	&& rm -rf /var/lib/apt/lists/* \
 	&& docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \
 	&& docker-php-ext-install gd \
+	&& docker-php-ext-install zip \
 	&& docker-php-ext-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
         && docker-php-ext-install ldap \
         && docker-php-ext-install mysqli \

+ 231 - 0
dev/initdata/dbf/import-dbf.php

@@ -0,0 +1,231 @@
+#!/usr/bin/env php
+<?php
+/* Copyright (C) 2016 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2016 Juanjo Menent        <jmenent@2byte.es>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
+ */
+
+/**
+ *  \file       dev/initdata/import-dbf.php
+ * 	\brief      Script example to create a table from a large DBF file (openoffice)
+ *              To purge data, you can have a look at purge-data.php
+ */
+// Test si mode batch
+$sapi_type = php_sapi_name();
+$script_file = basename(__FILE__);
+
+$path = dirname(__FILE__) . '/';
+if (substr($sapi_type, 0, 3) == 'cgi') {
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
+    exit;
+}
+
+// Recupere root dolibarr
+$path = dirname($_SERVER["PHP_SELF"]);
+require $path . "./../htdocs/master.inc.php";
+require $path . "/includes/dbase.class.php";
+
+// Global variables
+$version = DOL_VERSION;
+$confirmed = 1;
+$error = 0;
+
+
+/*
+ * Main
+ */
+
+@set_time_limit(0);
+print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
+dol_syslog($script_file . " launched with arg " . implode(',', $argv));
+
+
+$filepath = $argv[1];
+$filepatherr = $filepath . '.err';
+$startchar = empty($argv[2]) ? 0 : (int) $argv[2];
+$deleteTable = empty($argv[3]) ? 1 : 0;
+$startlinenb = empty($argv[3]) ? 1 : (int) $argv[3];
+$endlinenb = empty($argv[4]) ? 0 : (int) $argv[4];
+
+if (empty($filepath)) {
+    print "Usage: php $script_file myfilepath.dbf [removeChatColumnName] [startlinenb] [endlinenb]\n";
+    print "Example: php $script_file myfilepath.dbf 0 2 1002\n";
+    print "\n";
+    exit(-1);
+}
+if (!file_exists($filepath)) {
+    print "Error: File " . $filepath . " not found.\n";
+    print "\n";
+    exit(-1);
+}
+
+$ret = $user->fetch('', 'admin');
+if (!$ret > 0) {
+    print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
+    exit;
+}
+$user->getrights();
+
+// Ask confirmation
+if (!$confirmed) {
+    print "Hit Enter to continue or CTRL+C to stop...\n";
+    $input = trim(fgets(STDIN));
+}
+
+// Open input and output files
+$fhandle = dbase_open($filepath, 0);
+if (!$fhandle) {
+    print 'Error: Failed to open file ' . $filepath . "\n";
+    exit(1);
+}
+$fhandleerr = fopen($filepatherr, 'w');
+if (!$fhandleerr) {
+    print 'Error: Failed to open file ' . $filepatherr . "\n";
+    exit(1);
+}
+
+$langs->setDefaultLang($defaultlang);
+
+$record_numbers = dbase_numrecords($fhandle);
+$table_name = substr(basename($filepath), 0, strpos(basename($filepath), '.'));
+print 'Info: ' . $record_numbers . " lines in file \n";
+$header = dbase_get_header_info($fhandle);
+if ($deleteTable) {
+    $db->query("DROP TABLE IF EXISTS `$table_name`");
+}
+$sqlCreate = "CREATE TABLE IF NOT EXISTS `$table_name` ( `id` INT(11) NOT NULL AUTO_INCREMENT ";
+$fieldArray = array("`id`");
+foreach ($header as $value) {
+    $fieldName = substr(str_replace('_', '', $value['name']), $startchar);
+    $fieldArray[] = "`$fieldName`";
+    $sqlCreate .= ", `" . $fieldName . "` VARCHAR({$value['length']}) NULL DEFAULT NULL ";
+}
+$sqlCreate .= ", PRIMARY KEY (`id`)) ENGINE = InnoDB";
+$resql = $db->query($sqlCreate);
+if ($resql !== false) {
+    print "Table $table_name created\n";
+} else {
+    var_dump($db->errno());
+    print "Impossible : " . $sqlCreate . "\n";
+    die();
+}
+
+$i = 0;
+$nboflines++;
+
+$fields = implode(',', $fieldArray);
+//var_dump($fieldArray);die();
+$maxLength = 0;
+for ($i = 1; $i <= $record_numbers; $i++) {
+    if ($startlinenb && $i < $startlinenb)
+        continue;
+    if ($endlinenb && $i > $endlinenb)
+        continue;
+    $row = dbase_get_record_with_names($fhandle, $i);
+    if ($row === false || (isset($row["deleted"]) && $row["deleted"] == '1'))
+        continue;
+    $sqlInsert = "INSERT INTO `$table_name`($fields) VALUES (null,";
+    array_shift($row); // remove delete column
+    foreach ($row as $value) {
+        $sqlInsert .= "'" . $db->escape(utf8_encode($value)) . "', ";
+    }
+    replaceable_echo(implode("\t", $row));
+    $sqlInsert = rtrim($sqlInsert, ', ');
+    $sqlInsert .= ")";
+    $resql = $db->query($sqlInsert);
+    if ($resql === false) {
+        print "Impossible : " . $sqlInsert . "\n";
+        var_dump($row, $db->errno());
+        die();
+    }
+	//    $fields = (object) $row;
+	//    var_dump($fields);
+    continue;
+}
+die();
+
+
+
+
+
+// commit or rollback
+print "Nb of lines qualified: " . $nboflines . "\n";
+print "Nb of errors: " . $error . "\n";
+if ($mode != 'confirmforced' && ($error || $mode != 'confirm')) {
+    print "Rollback any changes.\n";
+    $db->rollback();
+} else {
+    print "Commit all changes.\n";
+    $db->commit();
+}
+
+$db->close();
+fclose($fhandle);
+fclose($fhandleerr);
+
+exit($error);
+
+
+/**
+ * replaceable_echo
+ *
+ * @param string 	$message			Message
+ * @param int 		$force_clear_lines	Force clear messages
+ * @return void
+ */
+function replaceable_echo($message, $force_clear_lines = null)
+{
+    static $last_lines = 0;
+
+    if (!is_null($force_clear_lines)) {
+        $last_lines = $force_clear_lines;
+    }
+
+    $toss = array();
+    $status = 0;
+    $term_width = exec('tput cols', $toss, $status);
+    if ($status) {
+        $term_width = 64; // Arbitrary fall-back term width.
+    }
+
+    $line_count = 0;
+    foreach (explode("\n", $message) as $line) {
+        $line_count += count(str_split($line, $term_width));
+    }
+
+    // Erasure MAGIC: Clear as many lines as the last output had.
+    for ($i = 0; $i < $last_lines; $i++) {
+        // Return to the beginning of the line
+        echo "\r";
+        // Erase to the end of the line
+        echo "\033[K";
+        // Move cursor Up a line
+        echo "\033[1A";
+        // Return to the beginning of the line
+        echo "\r";
+        // Erase to the end of the line
+        echo "\033[K";
+        // Return to the beginning of the line
+        echo "\r";
+        // Can be consolodated into
+        // echo "\r\033[K\033[1A\r\033[K\r";
+    }
+
+    $last_lines = $line_count;
+
+    echo $message . "\n";
+}

+ 241 - 0
dev/initdata/dbf/importdb-products.php

@@ -0,0 +1,241 @@
+#!/usr/bin/env php
+<?php
+/* Copyright (C) 2016 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2016 Juanjo Menent        <jmenent@2byte.es>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
+ */
+
+/**
+ *      \file       dev/initdata/import-product.php
+ * 		\brief      Script example to insert products from a csv file.
+ *                  To purge data, you can have a look at purge-data.php
+ */
+// Test si mode batch
+$sapi_type = php_sapi_name();
+$script_file = basename(__FILE__);
+$path = dirname(__FILE__) . '/';
+if (substr($sapi_type, 0, 3) == 'cgi') {
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
+    exit;
+}
+
+// Recupere root dolibarr
+$path = preg_replace('/importdb-products.php/i', '', $_SERVER["PHP_SELF"]);
+require $path . "../../htdocs/master.inc.php";
+require $path . "includes/dbase.class.php";
+include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
+include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
+
+//$delimiter = ',';
+//$enclosure = '"';
+//$linelength = 10000;
+//$escape = '/';
+// Global variables
+$version = DOL_VERSION;
+$confirmed = 1;
+$error = 0;
+
+$tvas = [
+    '1' => "20.00",
+    '2' => "5.50",
+    '3' => "0.00",
+    '4' => "20.60",
+    '5' => "19.60",
+];
+$tvasD = [
+    '1' => "20",
+    '2' => "5.5",
+    '3' => "0",
+    '4' => "20",
+    '5' => "20",
+];
+
+/*
+ * Main
+ */
+
+@set_time_limit(0);
+print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
+dol_syslog($script_file . " launched with arg " . implode(',', $argv));
+
+$table = $argv[1];
+
+if (empty($argv[1])) {
+    print "Error: Which table ?\n";
+    print "\n";
+    exit(-1);
+}
+
+$ret = $user->fetch('', 'admin');
+if (!$ret > 0) {
+    print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
+    exit;
+}
+
+$sql = "SELECT * FROM `$table` WHERE 1";
+$resql = $db->query($sql);
+if ($resql)
+while ($fields = $db->fetch_array($resql)) {
+	$errorrecord = 0;
+	if ($fields === false)
+		continue;
+	$nboflines++;
+
+	$produit = new Product($db);
+	$produit->type = 0;
+	$produit->status = 1;
+	$produit->ref = trim($fields['REF']);
+	if ($produit->ref == '')
+		continue;
+	print "Process line nb " . $j . ", ref " . $produit->ref;
+	$produit->label = trim($fields['LIBELLE']);
+	if ($produit->label == '')
+		$produit->label = $produit->ref;
+	if (empty($produit->label))
+		continue;
+	//$produit->description = trim($fields[4] . "\n" . ($fields[5] ? $fields[5] . ' x ' . $fields[6] . ' x ' . $fields[7] : ''));
+	//        $produit->volume = price2num($fields[8]);
+	//        $produit->volume_unit = 0;
+	$produit->weight = price2num($fields['MASSE']);
+	$produit->weight_units = 0;          // -3 = g
+	//$produit->customcode = $fields[10];
+	$produit->barcode = str_pad($fields['CODE'], 12, "0", STR_PAD_LEFT);
+	$produit->barcode_type = '2';
+	$produit->import_key = $fields['CODE'];
+
+	$produit->status = 1;
+	$produit->status_buy = 1;
+
+	$produit->finished = 1;
+
+	//        $produit->multiprices[0] = price2num($fields['TARIF0']);
+	//        $produit->multiprices[1] = price2num($fields['TARIF1']);
+	//        $produit->multiprices[2] = price2num($fields['TARIF2']);
+	//        $produit->multiprices[3] = price2num($fields['TARIF3']);
+	//        $produit->multiprices[4] = price2num($fields['TARIF4']);
+	//        $produit->multiprices[5] = price2num($fields['TARIF5']);
+	//        $produit->multiprices[6] = price2num($fields['TARIF6']);
+	//        $produit->multiprices[7] = price2num($fields['TARIF7']);
+	//        $produit->multiprices[8] = price2num($fields['TARIF8']);
+	//        $produit->multiprices[9] = price2num($fields['TARIF9']);
+	//        $produit->price_min = null;
+	//        $produit->price_min_ttc = null;
+	//        $produit->price = price2num($fields[11]);
+	//        $produit->price_ttc = price2num($fields[12]);
+	//        $produit->price_base_type = 'TTC';
+	//        $produit->tva_tx = price2num($fields[13]);
+	$produit->tva_tx = (int) ($tvas[$fields['CODTVA']]);
+	$produit->tva_npr = 0;
+	//        $produit->cost_price = price2num($fields[16]);
+	//compta
+
+	$produit->accountancy_code_buy = trim($fields['COMACH']);
+	$produit->accountancy_code_sell = trim($fields['COMVEN']);
+	//        $produit->accountancy_code_sell_intra=trim($fields['COMVEN']);
+	//        $produit->accountancy_code_sell_export=trim($fields['COMVEN']);
+	// Extrafields
+	//        $produit->array_options['options_ecotaxdeee'] = price2num($fields[17]);
+
+	$produit->seuil_stock_alerte = $fields['STALERTE'];
+	$ret = $produit->create($user, 0);
+	if ($ret < 0) {
+		print " - Error in create result code = " . $ret . " - " . $produit->errorsToString();
+		$errorrecord++;
+	} else {
+		print " - Creation OK with ref " . $produit->ref . " - id = " . $ret;
+	}
+
+	dol_syslog("Add prices");
+
+	// If we use price level, insert price for each level
+	if (!$errorrecord && 1) {
+		//$ret1 = $produit->updatePrice($produit->price_ttc, $produit->price_base_type, $user, $produit->tva_tx, $produit->price_min, 1, $produit->tva_npr, 0, 0, array());
+		$ret1 = false;
+		for ($i = 0; $i < 10; $i++) {
+			if ($fields['TARIF' . ($i)] == 0)
+				continue;
+			$ret1 = $ret1 || $produit->updatePrice(price2num($fields['TARIF' . ($i)]), 'HT', $user, $produit->tva_tx, $produit->price_min, $i + 1, $produit->tva_npr, 0, 0, array()) < 0;
+		}
+		if ($ret1) {
+			print " - Error in updatePrice result " . $produit->errorsToString();
+			$errorrecord++;
+		} else {
+			print " - updatePrice OK";
+		}
+	}
+
+
+	//        dol_syslog("Add multilangs");
+	// Add alternative languages
+	//        if (!$errorrecord && 1) {
+	//            $produit->multilangs['fr_FR'] = array('label' => $produit->label, 'description' => $produit->description, 'note' => $produit->note_private);
+	//            $produit->multilangs['en_US'] = array('label' => $fields[3], 'description' => $produit->description, 'note' => $produit->note_private);
+	//
+	//            $ret = $produit->setMultiLangs($user);
+	//            if ($ret < 0) {
+	//                print " - Error in setMultiLangs result code = " . $ret . " - " . $produit->errorsToString();
+	//                $errorrecord++;
+	//            } else {
+	//                print " - setMultiLangs OK";
+	//            }
+	//        }
+
+
+	dol_syslog("Add stocks");
+	// stocks
+	if (!$errorrecord && $fields['STOCK'] != 0) {
+		$rets = $produit->correct_stock($user, 1, $fields['STOCK'], 0, 'Stock importé');
+		if ($rets < 0) {
+			print " - Error in correct_stock result " . $produit->errorsToString();
+			$errorrecord++;
+		} else {
+			print " - correct_stock OK";
+		}
+	}
+
+	//update date créa
+	if (!$errorrecord) {
+		$date = substr($fields['DATCREA'], 0, 4) . '-' . substr($fields['DATCREA'], 4, 2) . '-' . substr($fields['DATCREA'], 6, 2);
+		$retd = $db->query("UPDATE `llx_product` SET `datec` = '$date 00:00:00' WHERE `llx_product`.`rowid` = $produit->id");
+		if ($retd < 1) {
+			print " - Error in update date créa result " . $produit->errorsToString();
+			$errorrecord++;
+		} else {
+			print " - update date créa OK";
+		}
+	}
+	print "\n";
+
+	if ($errorrecord) {
+		print( 'Error on record nb ' . $i . " - " . $produit->errorsToString() . "\n");
+		var_dump($db);
+		die();
+		$error++;    // $errorrecord will be reset
+	}
+	$j++;
+} else
+    die("error : $sql");
+
+
+
+
+// commit or rollback
+print "Nb of lines qualified: " . $nboflines . "\n";
+print "Nb of errors: " . $error . "\n";
+$db->close();
+
+exit($error);

+ 355 - 0
dev/initdata/dbf/importdb-thirdparties.php

@@ -0,0 +1,355 @@
+#!/usr/bin/env php
+<?php
+/* Copyright (C) 2016 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2016 Juanjo Menent        <jmenent@2byte.es>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * WARNING, THIS WILL LOAD MASS DATA ON YOUR INSTANCE
+ */
+
+/**
+ *      \file       dev/initdata/import-product.php
+ * 		\brief      Script example to insert products from a csv file.
+ *                  To purge data, you can have a look at purge-data.php
+ */
+// Test si mode batch
+$sapi_type = php_sapi_name();
+$script_file = basename(__FILE__);
+$path = dirname(__FILE__) . '/';
+if (substr($sapi_type, 0, 3) == 'cgi') {
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
+    exit;
+}
+
+// Recupere root dolibarr
+$path = preg_replace('/importdb-thirdparties.php/i', '', $_SERVER["PHP_SELF"]);
+require $path . "../../htdocs/master.inc.php";
+require $path . "includes/dbase.class.php";
+include_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php';
+include_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php';
+
+//$delimiter = ',';
+//$enclosure = '"';
+//$linelength = 10000;
+//$escape = '/';
+// Global variables
+$version = DOL_VERSION;
+$confirmed = 1;
+$error = 0;
+
+$civilPrivate = array("MLLE",
+    "MM",
+    "MM/MADAME",
+    "MME",
+    "MME.",
+    "MME²",
+    "MMONSIEUR",
+    "MMR",
+    "MOBNSIEUR",
+    "MOMSIEUR",
+    "MON SIEUR",
+    "MONDIAL",
+    "MONIEUR",
+    "MONJSIEUR",
+    "MONNSIEUR",
+    "MONRIEUR",
+    "MONS",
+    "MONSIEÕR",
+    "MONSIER",
+    "MONSIERU",
+    "MONSIEU",
+    "monsieue",
+    "MONSIEUR",
+    "Monsieur     \"",
+    "MONSIEUR    \"",
+    "MONSIEUR   E",
+    "MONSIEUR  DENIS",
+    "MONSIEUR ET MME",
+    "MONSIEUR!",
+    "MONSIEUR.",
+    "MONSIEUR.MADAME",
+    "MONSIEUR3",
+    "MONSIEURN",
+    "MONSIEURT",
+    "MONSIEUR£",
+    "MONSIEYR",
+    "Monsigur",
+    "MONSIIEUR",
+    "MONSIUER",
+    "MONSIZEUR",
+    "MOPNSIEUR",
+    "MOSIEUR",
+    "MR",
+    "Mr  Mme",
+    "Mr - MME",
+    "MR BLANC",
+    "MR ET MME",
+    "mr mm",
+    "MR OU MME",
+    "Mr.",
+    "MR/MME",
+    "MRME",
+    "MRR",
+    "Mrs",
+    "Mademoiselle",
+    "MADAOME",
+    "madamme",
+    "MADAME",
+    "M0NSIEUR",
+    "M.et Madame",
+    "M. ET MR",
+    "M.",
+    "M%",
+    "M MME",
+    "M ET MME",
+    "M",
+    "M CROCE",
+    "M DIEVART",
+);
+
+/*
+ * Main
+ */
+
+@set_time_limit(0);
+print "***** " . $script_file . " (" . $version . ") pid=" . dol_getmypid() . " *****\n";
+dol_syslog($script_file . " launched with arg " . implode(',', $argv));
+
+$table = $argv[1];
+
+if (empty($argv[1])) {
+    print "Error: Quelle table ?\n";
+    print "\n";
+    exit(-1);
+}
+
+$ret = $user->fetch('', 'admin');
+if (!$ret > 0) {
+    print 'A user with login "admin" and all permissions must be created to use this script.' . "\n";
+    exit;
+}
+
+$sql = "SELECT * FROM `$table` WHERE 1 "; //ORDER BY REMISE DESC,`LCIVIL` DESC";
+$resql = $db->query($sql);
+//$db->begin();
+if ($resql)
+while ($fields = $db->fetch_array($resql)) {
+	$i++;
+	$errorrecord = 0;
+
+	if ($startlinenb && $i < $startlinenb)
+		continue;
+	if ($endlinenb && $i > $endlinenb)
+		continue;
+
+	$nboflines++;
+
+	$object = new Societe($db);
+	$object->import_key = $fields['CODE'];
+	$object->state = 1;
+	$object->client = 3;
+	$object->fournisseur = 0;
+
+	$object->name = $fields['FCIVIL'] . ' ' . $fields['FNOM'];
+	//$object->name_alias = $fields[0] != $fields[13] ? trim($fields[0]) : '';
+
+	$date = $fields['DATCREA'] ? $fields['DATCREA'] : ($fields['DATMOD'] ? $fields['DATMOD'] : '20200101');
+	$object->code_client = 'CU' . substr($date, 2, 2) . substr($date, 4, 2) . '-' . str_pad(substr($fields['CODE'], 0, 5), 5, "0", STR_PAD_LEFT);
+
+
+	$object->address = trim($fields['FADR1']);
+	if ($fields['FADR2'])
+		$object->address .= "\n" . trim($fields['FADR2']);
+	if ($fields['FADR3'])
+		$object->address .= "\n" . trim($fields['FADR3']);
+
+	$object->zip = trim($fields['FPOSTE']);
+	$object->town = trim($fields['FVILLE']);
+	if ($fields['FPAYS'])
+		$object->country_id = dol_getIdFromCode($db, trim(ucwords(strtolower($fields['FPAYS']))), 'c_country', 'label', 'rowid');
+	else
+		$object->country_id = 1;
+	$object->phone = trim($fields['FTEL']) ? trim($fields['FTEL']) : trim($fields['FCONTACT']);
+	$object->phone = substr($object->phone, 0, 20);
+	$object->fax = trim($fields['FFAX']) ? trim($fields['FFAX']) : trim($fields['FCONTACT']);
+	$object->fax = substr($object->fax, 0, 20);
+	$object->email = trim($fields['FMAIL']);
+	//        $object->idprof2 = trim($fields[29]);
+	$object->tva_intra = str_replace(['.', ' '], '', $fields['TVAINTRA']);
+	$object->tva_intra = substr($object->tva_intra, 0, 20);
+	$object->default_lang = 'fr_FR';
+
+	$object->cond_reglement_id = dol_getIdFromCode($db, 'PT_ORDER', 'c_payment_term', 'code', 'rowid', 1);
+	$object->multicurrency_code = 'EUR';
+
+	if ($fields['REMISE'] != '0.00') {
+		$object->remise_percent = abs($fields['REMISE']);
+	}
+
+	//        $object->code_client = $fields[9];
+	//        $object->code_fournisseur = $fields[10];
+
+
+	if ($fields['FCIVIL']) {
+		$labeltype = in_array($fields['FCIVIL'], $civilPrivate) ? 'TE_PRIVATE' : 'TE_SMALL';
+		$object->typent_id = dol_getIdFromCode($db, $labeltype, 'c_typent', 'code');
+	}
+
+	// Set price level
+	$object->price_level = $fields['TARIF'] + 1;
+	//        if ($labeltype == 'Revendeur')
+	//            $object->price_level = 2;
+
+	print "Process line nb " . $i . ", code " . $fields['CODE'] . ", name " . $object->name;
+
+
+	// Extrafields
+	$object->array_options['options_banque'] = $fields['BANQUE'];
+	$object->array_options['options_banque2'] = $fields['BANQUE2'];
+	$object->array_options['options_banquevalid'] = $fields['VALID'];
+
+	if (!$errorrecord) {
+		$ret = $object->create($user);
+		if ($ret < 0) {
+			print " - Error in create result code = " . $ret . " - " . $object->errorsToString();
+			$errorrecord++;
+			var_dump($object->code_client, $db);
+			die();
+		} else {
+			print " - Creation OK with name " . $object->name . " - id = " . $ret;
+		}
+	}
+
+	if (!$errorrecord) {
+		dol_syslog("Set price level");
+		$object->set_price_level($object->price_level, $user);
+	}
+	if (!$errorrecord && @$object->remise_percent) {
+		dol_syslog("Set remise client");
+		$object->set_remise_client($object->remise_percent, 'Importé', $user);
+	}
+
+	dol_syslog("Add contact");
+	// Insert an invoice contact if there is an invoice email != standard email
+	if (!$errorrecord && ($fields['LCIVIL'] || $fields['LNOM'])) {
+		$madame = array("MADAME",
+			"MADEMOISELLE",
+			"MELLE",
+			"MLLE",
+			"MM",
+			"Mme",
+			"MNE",
+		);
+		$monsieur = array("M",
+			"M ET MME",
+			"M MME",
+			"M.",
+			"M. MME",
+			"M. OU Mme",
+			"M.ou Madame",
+			"MONSEUR",
+			"MONSIER",
+			"MONSIEU",
+			"MONSIEUR",
+			"monsieur:mme",
+			"MONSIEUR¨",
+			"MONSIEZUR",
+			"MONSIUER",
+			"MONSKIEUR",
+			"MR",
+		);
+		$ret1 = $ret2 = 0;
+
+		$contact = new Contact($db);
+		if (in_array($fields['LCIVIL'], $madame)) {
+			// une dame
+			$contact->civility_id = 'MME';
+			$contact->lastname = $fields['LNOM'];
+		} elseif (in_array($fields['LCIVIL'], $monsieur)) {
+			// un monsieur
+			$contact->civility_id = 'MR';
+			$contact->lastname = $fields['LNOM'];
+		} elseif (in_array($fields['LCIVIL'], ['DOCTEUR'])) {
+			// un monsieur
+			$contact->civility_id = 'DR';
+			$contact->lastname = $fields['LNOM'];
+		} else {
+			// un a rattraper
+			$contact->lastname = $fields['LCIVIL'] . " " . $fields['LNOM'];
+		}
+		$contact->address = trim($fields['LADR1']);
+		if ($fields['LADR2'])
+			$contact->address .= "\n" . trim($fields['LADR2']);
+		if ($fields['LADR3'])
+			$contact->address .= "\n" . trim($fields['LADR3']);
+
+		$contact->zip = trim($fields['LPOSTE']);
+		$contact->town = trim($fields['LVILLE']);
+		if ($fields['FPAYS'])
+			$contact->country_id = dol_getIdFromCode($db, trim(ucwords(strtolower($fields['LPAYS']))), 'c_country', 'label', 'rowid');
+		else
+			$contact->country_id = 1;
+		$contact->email = $fields['LMAIL'];
+		$contact->phone = trim($fields['LTEL']) ? trim($fields['LTEL']) : trim($fields['LCONTACT']);
+		$contact->fax = trim($fields['LFAX']) ? trim($fields['LFAX']) : trim($fields['LCONTACT']);
+		$contact->socid = $object->id;
+
+		$ret1 = $contact->create($user);
+		if ($ret1 > 0) {
+			//$ret2=$contact->add_contact($object->id, 'BILLING');
+		}
+		if ($ret1 < 0 || $ret2 < 0) {
+			print " - Error in create contact result code = " . $ret1 . " " . $ret2 . " - " . $contact->errorsToString();
+			$errorrecord++;
+		} else {
+			print " - create contact OK";
+		}
+	}
+
+
+	//update date créa
+	if (!$errorrecord) {
+		$datec = substr($date, 0, 4) . '-' . substr($date, 4, 2) . '-' . substr($date, 6, 2);
+		$retd = $db->query("UPDATE `llx_societe` SET `datec` = '$datec 00:00:00' WHERE `rowid` = $object->id");
+		if ($retd < 1) {
+			print " - Error in update date créa result " . $object->errorsToString();
+			$errorrecord++;
+		} else {
+			print " - update date créa OK";
+		}
+	}
+	print "\n";
+
+	if ($errorrecord) {
+		print( 'Error on record nb ' . $i . " - " . $object->errorsToString() . "\n");
+		var_dump($db, $object, $contact);
+		//            $db->rollback();
+		die();
+		$error++;    // $errorrecord will be reset
+	}
+	$j++;
+} else
+    die("error : $sql");
+
+$db->commit();
+
+
+
+// commit or rollback
+print "Nb of lines qualified: " . $nboflines . "\n";
+print "Nb of errors: " . $error . "\n";
+$db->close();
+
+exit($error);

+ 402 - 0
dev/initdata/dbf/includes/dbase.class.php

@@ -0,0 +1,402 @@
+<?php
+/**
+ * \file        dev/initdata/dbf/includes/dbase.class.php
+ * \ingroup     dev
+ * \brief       Class to manage DBF databases
+ */
+
+// source : https://github.com/donfbecker/php-dbase
+
+define('DBASE_RDONLY', 0);
+define('DBASE_WRONLY', 1);
+define('DBASE_RDWR', 2);
+define('DBASE_TYPE_DBASE', 0);
+define('DBASE_TYPE_FOXPRO', 1);
+
+/**
+ * Class for DBase
+ */
+class DBase
+{
+    private $fd;
+    private $headerLength = 0;
+    private $fields = array();
+    private $fieldCount = 0;
+    private $recordLength = 0;
+    private $recordCount = 0;
+
+    //resource dbase_open ( string $filename , int $mode )
+    public static function open($filename, $mode)
+	{
+        if (!file_exists($filename))
+            return false;
+        $modes = array('r', 'w', 'r+');
+        $mode = $modes[$mode];
+        $fd = fopen($filename, $mode);
+        if (!$fd)
+            return false;
+        return new DBase($fd);
+    }
+
+    //resource dbase_create ( string $filename , array $fields [, int $type = DBASE_TYPE_DBASE ] )
+    public static function create($filename, $fields, $type = DBASE_TYPE_DBASE)
+	{
+        if (file_exists($filename))
+            return false;
+        $fd = fopen($filename, 'c+');
+        if (!$fd)
+            return false;
+        // Byte 0 (1 byte): Valid dBASE for DOS file; bits 0-2 indicate version number, bit 3
+        // indicates the presence of a dBASE for DOS memo file, bits 4-6 indicate the
+        // presence of a SQL table, bit 7 indicates the presence of any memo file
+        // (either dBASE m PLUS or dBASE for DOS)
+        self::putChar8($fd, 5);
+        // Byte 1-3 (3 bytes): Date of last update; formatted as YYMMDD
+        self::putChar8($fd, date('Y') - 1900);
+        self::putChar8($fd, date('m'));
+        self::putChar8($fd, date('d'));
+        // Byte 4-7 (32-bit number): Number of records in the database file.  Currently 0
+        self::putInt32($fd, 0);
+        // Byte 8-9 (16-bit number): Number of bytes in the header.
+        self::putInt16($fd, 32 + (32 * count($fields)) + 1);
+        // Byte 10-11 (16-bit number): Number of bytes in record.
+        // Make sure the include the byte for deleted flag
+        $len = 1;
+        foreach ($fields as &$field)
+            $len += self::length($field);
+        self::putInt16($fd, $len);
+        // Byte 12-13 (2 bytes): Reserved, 0 filled.
+        self::putInt16($fd, 0);
+        // Byte 14 (1 byte): Flag indicating incomplete transaction
+        // The ISMARKEDO function checks this flag. BEGIN TRANSACTION sets it to 1, END TRANSACTION and ROLLBACK reset it to 0.
+        self::putChar8($fd, 0);
+        // Byte 15 (1 byte): Encryption flag. If this flag is set to 1, the message Database encrypted appears. Changing this flag to 0 removes the message, but does not decrypt the file.
+        self::putChar8($fd, 0);
+        // Byte 16-27 (12 bytes): Reserved for dBASE for DOS in a multi-user environment
+        self::putInt32($fd, 0);
+        self::putInt32($fd, 0);
+        self::putInt32($fd, 0);
+        // Byte 28 (1 byte): Production .mdx file flag; 0x01 if there is a production .mdx file, 0x00 if not
+        self::putChar8($fd, 0);
+        // Byte 29 (1 byte): Language driver ID
+        // (no clue what this is)
+        self::putChar8($fd, 0);
+        // Byte 30-31 (2 bytes): Reserved, 0 filled.
+        self::putInt16($fd, 0);
+        // Byte 32 - n (32 bytes each): Field descriptor array
+        foreach ($fields as &$field) {
+            self::putString($fd, $field[0], 11);       // Byte 0 - 10 (11 bytes): Field name in ASCII (zero-filled)
+            self::putString($fd, $field[1], 1);       // Byte 11 (1 byte): Field type in ASCII (C, D, F, L, M, or N)
+            self::putInt32($fd, 0);                    // Byte 12 - 15 (4 bytes): Reserved
+            self::putChar8($fd, self::length($field)); // Byte 16 (1 byte): Field length in binary. The maximum length of a field is 254 (0xFE).
+            self::putChar8($fd, $field[3]);            // Byte 17 (1 byte): Field decimal count in binary
+            self::putInt16($fd, 0);                    // Byte 18 - 19 (2 bytes): Work area ID
+            self::putChar8($fd, 0);                    // Byte 20 (1 byte): Example (??)
+            self::putInt32($fd, 0);                    // Byte 21 - 30 (10 bytes): Reserved
+            self::putInt32($fd, 0);
+            self::putInt16($fd, 0);
+            self::putChar8($fd, 0);                    // Byte 31 (1 byte): Production MDX field flag; 1 if field has an index tag in the production MDX file, 0 if not
+        }
+        // Byte n + 1 (1 byte): 0x0D as the field descriptor array terminator
+        self::putChar8($fd, 0x0D);
+        return new DBase($fd);
+    }
+
+    // Create DBase instance
+    private function __construct($fd)
+	{
+        $this->fd = $fd;
+        // Byte 4-7 (32-bit number): Number of records in the database file.  Currently 0
+        fseek($this->fd, 4, SEEK_SET);
+        $this->recordCount = self::getInt32($fd);
+        // Byte 8-9 (16-bit number): Number of bytes in the header.
+        fseek($this->fd, 8, SEEK_SET);
+        $this->headerLength = self::getInt16($fd);
+        // Number of fields is (headerLength - 33) / 32)
+        $this->fieldCount = ($this->headerLength - 33) / 32;
+        // Byte 10-11 (16-bit number): Number of bytes in record.
+        fseek($this->fd, 10, SEEK_SET);
+        $this->recordLength = self::getInt16($fd);
+        // Byte 32 - n (32 bytes each): Field descriptor array
+        fseek($fd, 32, SEEK_SET);
+        for ($i = 0; $i < $this->fieldCount; $i++) {
+            $data = fread($this->fd, 32);
+            $field = array_map('trim', unpack('a11name/a1type/c4/c1length/c1precision/s1workid/c1example/c10/c1production', $data));
+            $this->fields[] = $field;
+        }
+    }
+
+    //bool dbase_close ( resource $dbase_identifier )
+    public function close()
+	{
+        fclose($this->fd);
+    }
+
+    //array dbase_get_header_info ( resource $dbase_identifier )
+    public function get_header_info()
+	{
+        return $this->fields;
+    }
+
+    //int dbase_numfields ( resource $dbase_identifier )
+    public function numfields()
+	{
+        return $this->fieldCount;
+    }
+
+    //int dbase_numrecords ( resource $dbase_identifier )
+    public function numrecords()
+	{
+        return $this->recordCount;
+    }
+
+    //bool dbase_add_record ( resource $dbase_identifier , array $record )
+    public function add_record($record)
+	{
+        if (count($record) != $this->fieldCount)
+            return false;
+        // Seek to end of file, minus the end of file marker
+        fseek($this->fd, 0, SEEK_END);
+        // Put the deleted flag
+        self::putChar8($this->fd, 0x20);
+        // Put the record
+        if (!$this->putRecord($record))
+            return false;
+        // Update the record count
+        fseek($this->fd, 4);
+        self::putInt32($this->fd, ++$this->recordCount);
+        return true;
+    }
+
+    //bool dbase_replace_record ( resource $dbase_identifier , array $record , int $record_number )
+    public function replace_record($record, $record_number)
+	{
+        if (count($record) != $this->fieldCount)
+            return false;
+        if ($record_number < 1 || $record_number > $this->recordCount)
+            return false;
+        // Skip to the record location, plus the 1 byte for the deleted flag
+        fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)) + 1);
+        return $this->putRecord($record);
+    }
+
+    //bool dbase_delete_record ( resource $dbase_identifier , int $record_number )
+    public function delete_record($record_number)
+	{
+        if ($record_number < 1 || $record_number > $this->recordCount)
+            return false;
+        fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)));
+        self::putChar8($this->fd, 0x2A);
+        return true;
+    }
+
+    //array dbase_get_record ( resource $dbase_identifier , int $record_number )
+    public function get_record($record_number)
+	{
+        if ($record_number < 1 || $record_number > $this->recordCount)
+            return false;
+        fseek($this->fd, $this->headerLength + ($this->recordLength * ($record_number - 1)));
+        $record = array(
+            'deleted' => self::getChar8($this->fd) == 0x2A ? 1 : 0
+        );
+        foreach ($this->fields as $i => &$field) {
+            $value = trim(fread($this->fd, $field['length']));
+            if ($field['type'] == 'L') {
+                $value = strtolower($value);
+                if ($value == 't' || $value == 'y')
+                    $value = true;
+                elseif ($value == 'f' || $value == 'n')
+                    $value = false;
+                else
+                    $value = null;
+            }
+            $record[$i] = $value;
+        }
+        return $record;
+    }
+
+    //array dbase_get_record_with_names ( resource $dbase_identifier , int $record_number )
+    public function get_record_with_names($record_number)
+	{
+        if ($record_number < 1 || $record_number > $this->recordCount)
+            return false;
+        $record = $this->get_record($record_number);
+        foreach ($this->fields as $i => &$field) {
+            $record[$field['name']] = $record[$i];
+            unset($record[$i]);
+        }
+        return $record;
+    }
+
+    //bool dbase_pack ( resource $dbase_identifier )
+    public function pack()
+	{
+        $in_offset = $out_offset = $this->headerLength;
+        $new_count = 0;
+        $rec_count = $this->recordCount;
+        while ($rec_count > 0) {
+            fseek($this->fd, $in_offset, SEEK_SET);
+            $record = fread($this->fd, $this->recordLength);
+            $deleted = substr($record, 0, 1);
+            if ($deleted != '*') {
+                fseek($this->fd, $out_offset, SEEK_SET);
+                fwrite($this->fd, $record);
+                $out_offset += $this->recordLength;
+                $new_count++;
+            }
+            $in_offset += $this->recordLength;
+            $rec_count--;
+        }
+        ftruncate($this->fd, $out_offset);
+        // Update the record count
+        fseek($this->fd, 4);
+        self::putInt32($this->fd, $new_count);
+    }
+
+    /*
+     * A few utilitiy functions
+     */
+
+    private static function length($field)
+	{
+        switch ($field[1]) {
+            case 'D': // Date: Numbers and a character to separate month, day, and year (stored internally as 8 digits in YYYYMMDD format)
+                return 8;
+            case 'T': // DateTime (YYYYMMDDhhmmss.uuu) (FoxPro)
+                return 18;
+            case 'M': // Memo (ignored): All ASCII characters (stored internally as 10 digits representing a .dbt block number, right justified, padded with whitespaces)
+            case 'N': // Number: -.0123456789 (right justified, padded with whitespaces)
+            case 'F': // Float: -.0123456789 (right justified, padded with whitespaces)
+            case 'C': // String: All ASCII characters (padded with whitespaces up to the field's length)
+                return $field[2];
+            case 'L': // Boolean: YyNnTtFf? (? when not initialized)
+                return 1;
+        }
+        return 0;
+    }
+
+    /*
+     * Functions for reading and writing bytes
+     */
+
+    private static function getChar8($fd)
+	{
+        return ord(fread($fd, 1));
+    }
+
+    private static function putChar8($fd, $value)
+	{
+        return fwrite($fd, chr($value));
+    }
+
+    private static function getInt16($fd, $n = 1)
+	{
+        $data = fread($fd, 2 * $n);
+        $i = unpack("S$n", $data);
+        if ($n == 1)
+            return (int) $i[1];
+        else
+            return array_merge($i);
+    }
+
+    private static function putInt16($fd, $value)
+	{
+        return fwrite($fd, pack('S', $value));
+    }
+
+    private static function getInt32($fd, $n = 1)
+	{
+        $data = fread($fd, 4 * $n);
+        $i = unpack("L$n", $data);
+        if ($n == 1)
+            return (int) $i[1];
+        else
+            return array_merge($i);
+    }
+
+    private static function putInt32($fd, $value)
+	{
+        return fwrite($fd, pack('L', $value));
+    }
+
+    private static function putString($fd, $value, $length = 254)
+	{
+        $ret = fwrite($fd, pack('A' . $length, $value));
+    }
+
+    private function putRecord($record)
+	{
+        foreach ($this->fields as $i => &$field) {
+            $value = $record[$i];
+            // Number types are right aligned with spaces
+            if ($field['type'] == 'N' || $field['type'] == 'F' && strlen($value) < $field['length']) {
+                $value = str_repeat(' ', $field['length'] - strlen($value)) . $value;
+            }
+            self::putString($this->fd, $value, $field['length']);
+        }
+        return true;
+    }
+}
+
+if (!function_exists('dbase_open')) {
+
+    function dbase_open($filename, $mode)
+	{
+        return DBase::open($filename, $mode);
+    }
+
+    function dbase_create($filename, $fields, $type = DBASE_TYPE_DBASE)
+	{
+        return DBase::create($filename, $fields, $type);
+    }
+
+    function dbase_close($dbase_identifier)
+	{
+        return $dbase_identifier->close();
+    }
+
+    function dbase_get_header_info($dbase_identifier)
+	{
+        return $dbase_identifier->get_header_info();
+    }
+
+    function dbase_numfields($dbase_identifier)
+	{
+        $dbase_identifier->numfields();
+    }
+
+    function dbase_numrecords($dbase_identifier)
+	{
+        return $dbase_identifier->numrecords();
+    }
+
+    function dbase_add_record($dbase_identifier, $record)
+	{
+        return $dbase_identifier->add_record($record);
+    }
+
+    function dbase_delete_record($dbase_identifier, $record_number)
+	{
+        return $dbase_identifier->delete_record($record_number);
+    }
+
+    function dbase_replace_record($dbase_identifier, $record, $record_number)
+	{
+        return $dbase_identifier->replace_record($record, $record_number);
+    }
+
+    function dbase_get_record($dbase_identifier, $record_number)
+	{
+        return $dbase_identifier->get_record($record_number);
+    }
+
+    function dbase_get_record_with_names($dbase_identifier, $record_number)
+	{
+        return $dbase_identifier->get_record_with_names($record_number);
+    }
+
+    function dbase_pack($dbase_identifier)
+	{
+        return $dbase_identifier->pack();
+    }
+}

+ 1 - 1
dev/initdata/generate-invoice.php

@@ -26,7 +26,7 @@
 // Test si mode batch
 $sapi_type = php_sapi_name();
 if (substr($sapi_type, 0, 3) == 'cgi') {
-	echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+	echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
 	exit;
 }
 

+ 1 - 1
dev/initdata/generate-order.php

@@ -27,7 +27,7 @@
 // Test si mode batch
 $sapi_type = php_sapi_name();
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 1
dev/initdata/generate-product.php

@@ -27,7 +27,7 @@
 // Test si mode batch
 $sapi_type = php_sapi_name();
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 1
dev/initdata/generate-proposal.php

@@ -27,7 +27,7 @@
 // Test si mode batch
 $sapi_type = php_sapi_name();
 if (substr($sapi_type, 0, 3) == 'cgi') {
-	echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+	echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
 	exit;
 }
 

+ 1 - 1
dev/initdata/generate-thirdparty.php

@@ -27,7 +27,7 @@
 // Test si mode batch
 $sapi_type = php_sapi_name();
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 1
dev/initdata/import-products.php

@@ -30,7 +30,7 @@ $sapi_type = php_sapi_name();
 $script_file = basename(__FILE__);
 $path=dirname(__FILE__).'/';
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 1
dev/initdata/import-thirdparties.php

@@ -30,7 +30,7 @@ $sapi_type = php_sapi_name();
 $script_file = basename(__FILE__);
 $path=dirname(__FILE__).'/';
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 1
dev/initdata/import-users.php

@@ -30,7 +30,7 @@ $sapi_type = php_sapi_name();
 $script_file = basename(__FILE__);
 $path=dirname(__FILE__).'/';
 if (substr($sapi_type, 0, 3) == 'cgi') {
-    echo "Erreur: Vous utilisez l'interpreteur PHP pour le mode CGI. Pour executer mailing-send.php en ligne de commande, vous devez utiliser l'interpreteur PHP pour le mode CLI.\n";
+    echo "Error: You are using PHP for CGI. To execute ".$script_file." from command line, you must use PHP for CLI mode.\n";
     exit;
 }
 

+ 1 - 0
dev/setup/codesniffer/ruleset.xml

@@ -6,6 +6,7 @@
 	<exclude-pattern type="relative">build/html</exclude-pattern>
 	<exclude-pattern type="relative">build/aps</exclude-pattern>
 	<exclude-pattern type="relative">dev/namespacemig</exclude-pattern>
+	<exclude-pattern type="relative">dev/initdata/dbf/includes</exclude-pattern>
 	<exclude-pattern type="relative">documents</exclude-pattern>
 	<exclude-pattern type="relative">htdocs/core/class/lessc.class.php</exclude-pattern>
 	<exclude-pattern type="relative">htdocs/custom</exclude-pattern>

+ 23 - 7
htdocs/accountancy/admin/account.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2013-2016 Olivier Geffroy      <jeff@jeffinfo.com>
- * Copyright (C) 2013-2017 Alexandre Spangaro   <aspangaro@open-dsi.fr>
+ * Copyright (C) 2013-2020 Alexandre Spangaro   <aspangaro@open-dsi.fr>
  * Copyright (C) 2016-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -42,16 +42,17 @@ $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'acc
 
 $search_account = GETPOST('search_account', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
+$search_labelshort = GETPOST('search_labelshort', 'alpha');
 $search_accountparent = GETPOST('search_accountparent', 'alpha');
 $search_pcgtype = GETPOST('search_pcgtype', 'alpha');
 $search_pcgsubtype = GETPOST('search_pcgsubtype', 'alpha');
 
 // Security check
 if ($user->socid > 0) accessforbidden();
-if (! $user->rights->accounting->chartofaccount) accessforbidden();
+if (!$user->rights->accounting->chartofaccount) accessforbidden();
 
 // Load variable for pagination
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'alpha');
 $sortorder = GETPOST('sortorder', 'alpha');
 $page = GETPOST('page', 'int');
@@ -65,6 +66,7 @@ if (!$sortorder) $sortorder = "ASC";
 $arrayfields = array(
     'aa.account_number'=>array('label'=>$langs->trans("AccountNumber"), 'checked'=>1),
     'aa.label'=>array('label'=>$langs->trans("Label"), 'checked'=>1),
+	'aa.labelshort'=>array('label'=>$langs->trans("LabelToShow"), 'checked'=>1),
 	'aa.account_parent'=>array('label'=>$langs->trans("Accountparent"), 'checked'=>1),
     'aa.pcg_type'=>array('label'=>$langs->trans("Pcgtype"), 'checked'=>1, 'help'=>'PcgtypeDesc'),
     'aa.pcg_subtype'=>array('label'=>$langs->trans("Pcgsubtype"), 'checked'=>0, 'help'=>'PcgtypeDesc'),
@@ -96,7 +98,8 @@ if (empty($reshook))
     {
     	$search_account = "";
     	$search_label = "";
-    	$search_accountparent = "";
+		$search_labelshort = "";
+		$search_accountparent = "";
     	$search_pcgtype = "";
     	$search_pcgsubtype = "";
 		$search_array_options = array();
@@ -192,7 +195,7 @@ if ($action == 'delete') {
 
 $pcgver = $conf->global->CHARTOFACCOUNTS;
 
-$sql = "SELECT aa.rowid, aa.fk_pcg_version, aa.pcg_type, aa.pcg_subtype, aa.account_number, aa.account_parent , aa.label, aa.active, ";
+$sql = "SELECT aa.rowid, aa.fk_pcg_version, aa.pcg_type, aa.pcg_subtype, aa.account_number, aa.account_parent , aa.label, aa.labelshort, aa.active, ";
 $sql .= " a2.rowid as rowid2, a2.label as label2, a2.account_number as account_number2";
 $sql .= " FROM ".MAIN_DB_PREFIX."accounting_account as aa";
 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version AND aa.entity = ".$conf->entity;
@@ -208,7 +211,7 @@ if (strlen(trim($search_account))) {
 	$search_account_tmp = $search_account;
 	$weremovedsomezero = 0;
 	if (strlen($search_account_tmp) <= $lengthpaddingaccount) {
-		for($i = 0; $i < $lengthpaddingaccount; $i++) {
+		for ($i = 0; $i < $lengthpaddingaccount; $i++) {
 			if (preg_match('/0$/', $search_account_tmp)) {
 				$weremovedsomezero++;
 				$search_account_tmp = preg_replace('/0$/', '', $search_account_tmp);
@@ -235,6 +238,7 @@ if (strlen(trim($search_account))) {
 	}
 }
 if (strlen(trim($search_label)))			$sql .= natural_search("aa.label", $search_label);
+if (strlen(trim($search_labelshort)))       $sql .= natural_search("aa.labelshort", $search_labelshort);
 if (strlen(trim($search_accountparent)) && $search_accountparent != '-1')	$sql .= natural_search("aa.account_parent", $search_accountparent, 2);
 if (strlen(trim($search_pcgtype)))			$sql .= natural_search("aa.pcg_type", $search_pcgtype);
 if (strlen(trim($search_pcgsubtype)))		$sql .= natural_search("aa.pcg_subtype", $search_pcgsubtype);
@@ -267,6 +271,7 @@ if ($resql)
 	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.$limit;
 	if ($search_account) $param .= '&search_account='.urlencode($search_account);
 	if ($search_label) $param .= '&search_label='.urlencode($search_label);
+	if ($search_labelshort) $param .= '&search_labelshort='.urlencode($search_labelshort);
 	if ($search_accountparent > 0 || $search_accountparent == '0') $param .= '&search_accountparent='.urlencode($search_accountparent);
 	if ($search_pcgtype) $param .= '&search_pcgtype='.urlencode($search_pcgtype);
 	if ($search_pcgsubtype) $param .= '&search_pcgsubtype='.urlencode($search_pcgsubtype);
@@ -351,6 +356,7 @@ if ($resql)
 	print '<tr class="liste_titre_filter">';
 	if (!empty($arrayfields['aa.account_number']['checked']))	print '<td class="liste_titre"><input type="text" class="flat" size="10" name="search_account" value="'.$search_account.'"></td>';
 	if (!empty($arrayfields['aa.label']['checked']))			print '<td class="liste_titre"><input type="text" class="flat" size="20" name="search_label" value="'.$search_label.'"></td>';
+	if (!empty($arrayfields['aa.labelshort']['checked']))		print '<td class="liste_titre"><input type="text" class="flat" size="20" name="search_labelshort" value="'.$search_labelshort.'"></td>';
 	if (!empty($arrayfields['aa.account_parent']['checked'])) {
 		print '<td class="liste_titre">';
 		print $formaccounting->select_account($search_accountparent, 'search_accountparent', 2);
@@ -368,8 +374,9 @@ if ($resql)
     print '<tr class="liste_titre">';
 	if (!empty($arrayfields['aa.account_number']['checked']))	print_liste_field_titre($arrayfields['aa.account_number']['label'], $_SERVER["PHP_SELF"], "aa.account_number", "", $param, '', $sortfield, $sortorder);
 	if (!empty($arrayfields['aa.label']['checked']))			print_liste_field_titre($arrayfields['aa.label']['label'], $_SERVER["PHP_SELF"], "aa.label", "", $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['aa.labelshort']['checked']))		print_liste_field_titre($arrayfields['aa.labelshort']['label'], $_SERVER["PHP_SELF"], "aa.labelshort", "", $param, '', $sortfield, $sortorder);
 	if (!empty($arrayfields['aa.account_parent']['checked']))	print_liste_field_titre($arrayfields['aa.account_parent']['label'], $_SERVER["PHP_SELF"], "aa.account_parent", "", $param, '', $sortfield, $sortorder, 'left ');
-	if (!empty($arrayfields['aa.pcg_type']['checked']))		print_liste_field_titre($arrayfields['aa.pcg_type']['label'], $_SERVER["PHP_SELF"], 'aa.pcg_type', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.pcg_type']['help']);
+	if (!empty($arrayfields['aa.pcg_type']['checked']))			print_liste_field_titre($arrayfields['aa.pcg_type']['label'], $_SERVER["PHP_SELF"], 'aa.pcg_type', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.pcg_type']['help']);
 	if (!empty($arrayfields['aa.pcg_subtype']['checked']))		print_liste_field_titre($arrayfields['aa.pcg_subtype']['label'], $_SERVER["PHP_SELF"], 'aa.pcg_subtype', '', $param, '', $sortfield, $sortorder, '', $arrayfields['aa.pcg_subtype']['help']);
 	if (!empty($arrayfields['aa.active']['checked']))			print_liste_field_titre($arrayfields['aa.active']['label'], $_SERVER["PHP_SELF"], 'aa.active', '', $param, '', $sortfield, $sortorder);
 	print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch ');
@@ -408,6 +415,15 @@ if ($resql)
 			if (!$i) $totalarray['nbfield']++;
 		}
 
+		// Account label to show (label short)
+		if (!empty($arrayfields['aa.labelshort']['checked']))
+		{
+			print "<td>";
+			print $obj->labelshort;
+			print "</td>\n";
+			if (!$i) $totalarray['nbfield']++;
+		}
+
 		// Account parent
 		if (!empty($arrayfields['aa.account_parent']['checked']))
 		{

+ 16 - 2
htdocs/accountancy/admin/card.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2013-2014  Olivier Geffroy     <jeff@jeffinfo.com>
- * Copyright (C) 2013-2018  Alexandre Spangaro  <aspangaro@open-dsi.fr>
+ * Copyright (C) 2013-2020  Alexandre Spangaro  <aspangaro@open-dsi.fr>
  * Copyright (C) 2014       Florian Henry       <florian.henry@open-concept.pro>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -97,6 +97,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount)
 		$object->account_parent = $account_parent;
 		$object->account_category = GETPOST('account_category', 'alpha');
 		$object->label = GETPOST('label', 'alpha');
+		$object->labelshort = GETPOST('labelshort', 'alpha');
 		$object->active = 1;
 
 		$res = $object->create($user);
@@ -162,6 +163,7 @@ if ($action == 'add' && $user->rights->accounting->chartofaccount)
 		$object->account_parent = $account_parent;
 		$object->account_category = GETPOST('account_category', 'alpha');
 		$object->label = GETPOST('label', 'alpha');
+		$object->labelshort = GETPOST('labelshort', 'alpha');
 
 		$result = $object->update($user);
 
@@ -236,6 +238,10 @@ if ($action == 'create') {
 	print '<tr><td><span class="fieldrequired">'.$langs->trans("Label").'</span></td>';
 	print '<td><input name="label" size="70" value="'.$object->label.'"></td></tr>';
 
+	// Label short
+	print '<tr><td>' . $langs->trans("LabelToShow") . '</td>';
+	print '<td><input name="labelshort" size="70" value="' . $object->labelshort . '"></td></tr>';
+
 	// Account parent
 	print '<tr><td>'.$langs->trans("Accountparent").'</td>';
 	print '<td>';
@@ -254,7 +260,7 @@ if ($action == 'create') {
 	print '<input type="text" name="pcg_type" value="'.dol_escape_htmltag(isset($_POST['pcg_type']) ?GETPOST('pcg_type', 'alpha') : $object->pcg_type).'">';
 	print '</td></tr>';
 
-	// Chart of acounts subtype
+	// Chart of accounts subtype
 	print '<tr><td>'.$langs->trans("Pcgsubtype").'</td>';
 	print '<td>';
 	print '<input type="text" name="pcg_subtype" value="'.dol_escape_htmltag(isset($_POST['pcg_subtype']) ?GETPOST('pcg_subtype', 'alpha') : $object->pcg_subtype).'">';
@@ -301,6 +307,10 @@ elseif ($id > 0 || $ref) {
 			print '<tr><td><span class="fieldrequired">'.$langs->trans("Label").'</span></td>';
 			print '<td><input name="label" size="70" value="'.$object->label.'"</td></tr>';
 
+			// Label short
+			print '<tr><td>' . $langs->trans("LabelToShow") . '</td>';
+			print '<td><input name="labelshort" size="70" value="' . $object->labelshort . '"</td></tr>';
+
 			// Account parent
 			print '<tr><td>'.$langs->trans("Accountparent").'</td>';
 			print '<td>';
@@ -354,6 +364,10 @@ elseif ($id > 0 || $ref) {
 			print '<tr><td class="titlefield">'.$langs->trans("Label").'</td>';
 			print '<td colspan="2">'.$object->label.'</td></tr>';
 
+			// Label to show
+			print '<tr><td class="titlefield">' . $langs->trans("LabelToShow") . '</td>';
+			print '<td colspan="2">' . $object->labelshort . '</td></tr>';
+
 			// Account parent
 			$accp = new AccountingAccount($db);
 			if (!empty($object->account_parent)) {

+ 10 - 1
htdocs/accountancy/bookkeeping/list.php

@@ -1,7 +1,7 @@
 <?php
 /* Copyright (C) 2013-2016  Olivier Geffroy         <jeff@jeffinfo.com>
  * Copyright (C) 2013-2016  Florian Henry           <florian.henry@open-concept.pro>
- * Copyright (C) 2013-2019  Alexandre Spangaro      <aspangaro@open-dsi.fr>
+ * Copyright (C) 2013-2020  Alexandre Spangaro      <aspangaro@open-dsi.fr>
  * Copyright (C) 2016-2017  Laurent Destailleur     <eldy@users.sourceforge.net>
  * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
  *
@@ -86,6 +86,7 @@ $search_debit = GETPOST('search_debit', 'alpha');
 $search_credit = GETPOST('search_credit', 'alpha');
 $search_ledger_code = GETPOST('search_ledger_code', 'alpha');
 $search_lettering_code = GETPOST('search_lettering_code', 'alpha');
+$search_not_reconciled = GETPOST('search_reconciled_option', 'alpha');
 
 // Load variable for pagination
 $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : (empty($conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION) ? $conf->liste_limit : $conf->global->ACCOUNTING_LIMIT_LIST_VENTILATION);
@@ -202,6 +203,7 @@ if (empty($reshook))
         $search_debit = '';
         $search_credit = '';
         $search_lettering_code = '';
+		$search_not_reconciled='';
     }
 
     // Must be after the remove filter action, before the export.
@@ -312,6 +314,10 @@ if (empty($reshook))
         $filter['t.lettering_code'] = $search_lettering_code;
         $param .= '&search_lettering_code='.urlencode($search_lettering_code);
     }
+	if (! empty($search_not_reconciled)) {
+		$filter['t.reconciled_option'] = $search_not_reconciled;
+		$param .= '&search_not_reconciled=' . urlencode($search_not_reconciled);
+	}
 }
 
 if ($action == 'delbookkeeping' && $user->rights->accounting->mouvements->supprimer) {
@@ -444,6 +450,8 @@ if (count($filter) > 0) {
 			$sqlwhere[] = $key.'\''.$db->idate($value).'\'';
 		} elseif ($key == 't.credit' || $key == 't.debit') {
 			$sqlwhere[] = natural_search($key, $value, 1, 1);
+		} elseif ($key == 't.reconciled_option') {
+			$sqlwhere[] = 't.lettering_code IS NULL';
 		} else {
 			$sqlwhere[] = natural_search($key, $value, 0, 1);
 		}
@@ -758,6 +766,7 @@ if (!empty($arrayfields['t.lettering_code']['checked']))
 {
 	print '<td class="liste_titre center">';
 	print '<input type="text" size="3" class="flat" name="search_lettering_code" value="'.$search_lettering_code.'"/>';
+	print '<br><span class="nowrap"><input type="checkbox" name="search_reconciled_option" value="notreconciled"'.($search_not_reconciled == 'notreconciled'?' checked':'').'>'.$langs->trans("NotReconciled").'</span>';
 	print '</td>';
 }
 // Code journal

+ 6 - 6
htdocs/accountancy/bookkeeping/thirdparty_lettering_customer.php

@@ -260,9 +260,9 @@ if ($resql) {
 		print '<td class="center">' . dol_print_date($db->jdate($obj->doc_date), 'day') . '</td>';
 		print '<td>' . $obj->doc_ref . '</td>';
 		print '<td>' . $obj->label_compte . '</td>';
-		print '<td class="right">' . price($obj->debit) . '</td>';
-		print '<td class="right">' . price($obj->credit) . '</td>';
-		print '<td class="right">' . price(round($solde, 2)) . '</td>';
+		print '<td class="nowrap right">' . price($obj->debit) . '</td>';
+		print '<td class="nowrap right">' . price($obj->credit) . '</td>';
+		print '<td class="nowrap right">' . price(round($solde, 2)) . '</td>';
 
 		// Journal
         $accountingjournal = new AccountingJournal($db);
@@ -285,15 +285,15 @@ if ($resql) {
 
 	print '<tr class="oddeven">';
 	print '<td class="right" colspan="3">'.$langs->trans("Total").':</td>' . "\n";
-	print '<td class="right"><strong>' . price($debit) . '</strong></td>';
-	print '<td class="right"><strong>' . price($credit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($debit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($credit) . '</strong></td>';
 	print '<td colspan="4"></td>';
 	print "</tr>\n";
 
 	print '<tr class="oddeven">';
 	print '<td class="right" colspan="3">'.$langs->trans("Balancing").':</td>' . "\n";
 	print '<td colspan="2">&nbsp;</td>';
-	print '<td class="right"><strong>' . price($credit - $debit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($credit - $debit) . '</strong></td>';
 	print '<td colspan="6"></td>';
 	print "</tr>\n";
 

+ 8 - 8
htdocs/accountancy/bookkeeping/thirdparty_lettering_supplier.php

@@ -144,7 +144,7 @@ dol_fiche_end();
 
 $sql = "SELECT bk.rowid, bk.doc_date, bk.doc_type, bk.doc_ref, ";
 $sql .= " bk.subledger_account, bk.numero_compte , bk.label_compte, bk.debit, ";
-$sql .= " bk.credit, bk.montant , bk.sens , bk.code_journal , bk.piece_num, bk.lettering_code ";
+$sql .= " bk.credit, bk.montant , bk.sens , bk.code_journal , bk.piece_num, bk.lettering_code, bk.date_validated ";
 $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as bk";
 $sql .= " WHERE (bk.subledger_account =  '" . $object->code_compta_fournisseur . "' AND bk.numero_compte = '" . $conf->global->ACCOUNTING_ACCOUNT_SUPPLIER . "' )";
 if (dol_strlen($search_date_start) || dol_strlen($search_date_end)) {
@@ -257,9 +257,9 @@ if ($resql) {
 		print '<td class="center">' . dol_print_date($db->jdate($obj->doc_date), 'day') . '</td>';
 		print '<td>' . $obj->doc_ref . '</td>';
 		print '<td>' . $obj->label_compte . '</td>';
-		print '<td class="right">' . price($obj->debit) . '</td>';
-		print '<td class="right">' . price($obj->credit) . '</td>';
-		print '<td class="right">' . price(round($solde, 2)) . '</td>';
+		print '<td class="nowrap right">' . price($obj->debit) . '</td>';
+		print '<td class="nowrap right">' . price($obj->credit) . '</td>';
+		print '<td class="nowrap right">' . price(round($solde, 2)) . '</td>';
 
         // Journal
         $accountingjournal = new AccountingJournal($db);
@@ -267,7 +267,7 @@ if ($resql) {
         $journaltoshow = (($result > 0)?$accountingjournal->getNomUrl(0, 0, 0, '', 0) : $obj->code_journal);
         print '<td class="center">' . $journaltoshow . '</td>';
 
-		if (empty($obj->lettering_code)) {
+		if (empty($obj->lettering_code)  && empty($obj->date_validated) ) {
 			print '<td class="nowrap center"><input type="checkbox" class="flat checkforselect" name="toselect[]" id="toselect[]" value="' . $obj->rowid . '" /></td>';
 		    print '<td><a href="'.DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?piece_num=' . $obj->piece_num . '">';
 		    print img_edit();
@@ -282,15 +282,15 @@ if ($resql) {
 
 	print '<tr class="oddeven">';
 	print '<td class="right" colspan="3">'.$langs->trans("Total").':</td>' . "\n";
-	print '<td class="right"><strong>' . price($debit) . '</strong></td>';
-	print '<td class="right"><strong>' . price($credit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($debit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($credit) . '</strong></td>';
 	print '<td colspan="6"></td>';
 	print "</tr>\n";
 
 	print '<tr class="oddeven">';
 	print '<td class="right" colspan="3">'.$langs->trans("Balancing").':</td>' . "\n";
 	print '<td colspan="2">&nbsp;</td>';
-	print '<td class="right"><strong>' . price($credit - $debit) . '</strong></td>';
+	print '<td class="nowrap right"><strong>' . price($credit - $debit) . '</strong></td>';
 	print '<td colspan="4"></td>';
 	print "</tr>\n";
 

+ 27 - 8
htdocs/accountancy/class/accountingaccount.class.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2013-2014  Olivier Geffroy      <jeff@jeffinfo.com>
- * Copyright (C) 2013-2016  Alexandre Spangaro   <aspangaro@open-dsi.fr>
+ * Copyright (C) 2013-2020  Alexandre Spangaro   <aspangaro@open-dsi.fr>
  * Copyright (C) 2013-2014  Florian Henry        <florian.henry@open-concept.pro>
  * Copyright (C) 2014       Juanjo Menent        <jmenent@2byte.es>
  * Copyright (C) 2015       Ari Elbaz (elarifr)  <github@accedinfo.com>
@@ -120,7 +120,12 @@ class AccountingAccount extends CommonObject
      */
     public $label;
 
-    /**
+	/**
+	 * @var string Label short of account
+	 */
+	public $labelshort;
+
+	/**
      * @var int ID
      */
     public $fk_user_author;
@@ -162,7 +167,7 @@ class AccountingAccount extends CommonObject
 		global $conf;
 
 		if ($rowid || $account_number) {
-			$sql  = "SELECT a.rowid as rowid, a.datec, a.tms, a.fk_pcg_version, a.pcg_type, a.pcg_subtype, a.account_number, a.account_parent, a.label, a.fk_accounting_category, a.fk_user_author, a.fk_user_modif, a.active";
+			$sql  = "SELECT a.rowid as rowid, a.datec, a.tms, a.fk_pcg_version, a.pcg_type, a.pcg_subtype, a.account_number, a.account_parent, a.label, a.labelshort, a.fk_accounting_category, a.fk_user_author, a.fk_user_modif, a.active";
 			$sql .= ", ca.label as category_label";
 			$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as a";
 			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_accounting_category as ca ON a.fk_accounting_category = ca.rowid";
@@ -197,6 +202,7 @@ class AccountingAccount extends CommonObject
 					$this->account_number = $obj->account_number;
 					$this->account_parent = $obj->account_parent;
 					$this->label = $obj->label;
+					$this->labelshort = $obj->labelshort;
 					$this->account_category = $obj->fk_accounting_category;
 					$this->account_category_label = $obj->category_label;
 					$this->fk_user_author = $obj->fk_user_author;
@@ -240,6 +246,8 @@ class AccountingAccount extends CommonObject
 			$this->account_number = trim($this->account_number);
 		if (isset($this->label))
 			$this->label = trim($this->label);
+		if (isset($this->labelshort))
+			$this->labelshort = trim($this->labelshort);
 
 		if (empty($this->pcg_type) || $this->pcg_type == '-1')
 		{
@@ -262,6 +270,7 @@ class AccountingAccount extends CommonObject
 		$sql .= ", account_number";
 		$sql .= ", account_parent";
 		$sql .= ", label";
+		$sql .= ", labelshort";
 		$sql .= ", fk_accounting_category";
 		$sql .= ", fk_user_author";
 		$sql .= ", active";
@@ -274,6 +283,7 @@ class AccountingAccount extends CommonObject
 		$sql .= ", " . (empty($this->account_number) ? 'NULL' : "'" . $this->db->escape($this->account_number) . "'");
 		$sql .= ", " . (empty($this->account_parent) ? 0 : (int) $this->account_parent);
 		$sql .= ", " . (empty($this->label) ? "''" : "'" . $this->db->escape($this->label) . "'");
+		$sql .= ", " . (empty($this->labelshort) ? "''" : "'" . $this->db->escape($this->labelshort) . "'");
 		$sql .= ", " . (empty($this->account_category) ? 0 : (int) $this->account_category);
 		$sql .= ", " . $user->id;
 		$sql .= ", " . (int) $this->active;
@@ -345,6 +355,7 @@ class AccountingAccount extends CommonObject
 		$sql .= " , account_number = '" . $this->db->escape($this->account_number) . "'";
 		$sql .= " , account_parent = " . (int) $this->account_parent;
 		$sql .= " , label = " . ($this->label ? "'" . $this->db->escape($this->label) . "'" : "''");
+		$sql .= " , labelshort = " . ($this->labelshort ? "'" . $this->db->escape($this->labelshort) . "'" : "''");
 		$sql .= " , fk_accounting_category = " . (empty($this->account_category) ? 0 : (int) $this->account_category);
 		$sql .= " , fk_user_modif = " . $user->id;
 		$sql .= " , active = " . (int) $this->active;
@@ -462,10 +473,11 @@ class AccountingAccount extends CommonObject
 	 * @param	string  $moretitle					Add more text to title tooltip
 	 * @param	int  	$notooltip					1=Disable tooltip
      * @param	int     $save_lastsearch_value		-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
+	 * @param	int     $withcompletelabel		    0=Short label (field short label), 1=Complete label (field label)
 	 * @return  string	String with URL
 	 */
-    public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1)
-    {
+    public function getNomUrl($withpicto = 0, $withlabel = 0, $nourl = 0, $moretitle = '', $notooltip = 0, $save_lastsearch_value = -1, $withcompletelabel = 0)
+	{
 		global $langs, $conf, $user;
 		require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
 
@@ -483,11 +495,18 @@ class AccountingAccount extends CommonObject
 		$picto = 'billr';
 		$label='';
 
+		if (empty($this->labelshort) || $withcompletelabel == 1)
+		{
+			$labeltoshow = $this->label;
+		} else {
+			$labeltoshow = $this->labelshort;
+		}
+
 		$label = '<u>' . $langs->trans("ShowAccountingAccount") . '</u>';
 		if (! empty($this->account_number))
 			$label .= '<br><b>'.$langs->trans('AccountAccounting') . ':</b> ' . length_accountg($this->account_number);
-		if (! empty($this->label))
-			$label .= '<br><b>'.$langs->trans('Label') . ':</b> ' . $this->label;
+		if (! empty($labeltoshow))
+			$label .= '<br><b>'.$langs->trans('Label') . ':</b> ' . $labeltoshow;
 		if ($moretitle) $label.=' - '.$moretitle;
 
 		$linkclose='';
@@ -514,7 +533,7 @@ class AccountingAccount extends CommonObject
 		}
 
 		$label_link = length_accountg($this->account_number);
-		if ($withlabel) $label_link .= ' - ' . $this->label;
+		if ($withlabel) $label_link .= ' - ' . $labeltoshow;
 
 		if ($withpicto) $result.=($linkstart.img_object(($notooltip?'':$label), $picto, ($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).$linkend);
 		if ($withpicto && $withpicto != 2) $result .= ' ';

+ 19 - 19
htdocs/accountancy/class/bookkeeping.class.php

@@ -357,25 +357,25 @@ class BookKeeping extends CommonObject
 				$sql .= ") VALUES (";
 				$sql .= "'".$this->db->idate($this->doc_date)."'";
 				$sql .= ", ".(!isset($this->date_lim_reglement) || dol_strlen($this->date_lim_reglement) == 0 ? 'NULL' : "'".$this->db->idate($this->date_lim_reglement)."'");
-				$sql .= ",'".$this->db->escape($this->doc_type)."'";
-				$sql .= ",'".$this->db->escape($this->doc_ref)."'";
-				$sql .= ",".$this->fk_doc;
-				$sql .= ",".$this->fk_docdet;
-				$sql .= ",'".$this->db->escape($this->thirdparty_code)."'";
-				$sql .= ",'".$this->db->escape($this->subledger_account)."'";
-				$sql .= ",'".$this->db->escape($this->subledger_label)."'";
-				$sql .= ",'".$this->db->escape($this->numero_compte)."'";
-				$sql .= ",'".$this->db->escape($this->label_compte)."'";
-				$sql .= ",'".$this->db->escape($this->label_operation)."'";
-				$sql .= ",".$this->debit;
-				$sql .= ",".$this->credit;
-				$sql .= ",".$this->montant;
-				$sql .= ",'".$this->db->escape($this->sens)."'";
-				$sql .= ",'".$this->db->escape($this->fk_user_author)."'";
-				$sql .= ",'".$this->db->idate($now)."'";
-				$sql .= ",'".$this->db->escape($this->code_journal)."'";
-				$sql .= ",'".$this->db->escape($this->journal_label)."'";
-				$sql .= ",".$this->db->escape($this->piece_num);
+				$sql .= ", '".$this->db->escape($this->doc_type)."'";
+				$sql .= ", '".$this->db->escape($this->doc_ref)."'";
+				$sql .= ", ".$this->fk_doc;
+				$sql .= ", ".$this->fk_docdet;
+				$sql .= ", ".(!empty($this->thirdparty_code)?("'".$this->db->escape($this->thirdparty_code)."'"):"NULL");
+				$sql .= ", ".(!empty($this->subledger_account)?("'".$this->db->escape($this->subledger_account)."'"):"NULL");
+				$sql .= ", ".(!empty($this->subledger_label)?("'".$this->db->escape($this->subledger_label)."'"):"NULL");
+				$sql .= ", '".$this->db->escape($this->numero_compte)."'";
+				$sql .= ", ".(!empty($this->label_operation)?("'".$this->db->escape($this->label_operation)."'"):"NULL");
+				$sql .= ", '".$this->db->escape($this->label_operation)."'";
+				$sql .= ", ".$this->debit;
+				$sql .= ", ".$this->credit;
+				$sql .= ", ".$this->montant;
+				$sql .= ", ".(!empty($this->sens)?("'".$this->db->escape($this->sens)."'"):"NULL");
+				$sql .= ", '".$this->db->escape($this->fk_user_author)."'";
+				$sql .= ", '".$this->db->idate($now)."'";
+				$sql .= ", '".$this->db->escape($this->code_journal)."'";
+				$sql .= ", ".(!empty($this->journal_label)?("'".$this->db->escape($this->journal_label)."'"):"NULL");
+				$sql .= ", ".$this->db->escape($this->piece_num);
 				$sql .= ", ".(!isset($this->entity) ? $conf->entity : $this->entity);
 				$sql .= ")";
 

+ 3 - 2
htdocs/accountancy/class/lettering.class.php

@@ -76,6 +76,7 @@ class Lettering extends BookKeeping
 
 		$sql .= " ) AND (bk.date_lettering ='' OR bk.date_lettering IS NULL) ";
 		$sql .= "  AND (bk.lettering_code != '' OR bk.lettering_code IS NULL) ";
+		$sql .= ' AND bk.date_validated IS NULL ';
 		$sql .= $this->db->order('bk.doc_date', 'DESC');
 
 		// echo $sql;
@@ -253,7 +254,7 @@ class Lettering extends BookKeeping
 		}
 
 		$sql = "SELECT SUM(ABS(debit)) as deb, SUM(ABS(credit)) as cred FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping WHERE ";
-		$sql .= " rowid IN (" . implode(',', $ids) . ") ";
+		$sql .= " rowid IN (" . implode(',', $ids) . ") AND date_validated IS NULL ";
 		$result = $this->db->query($sql);
 		if ($result) {
 			$obj = $this->db->fetch_object($result);
@@ -275,7 +276,7 @@ class Lettering extends BookKeeping
 			$sql = "UPDATE " . MAIN_DB_PREFIX . "accounting_bookkeeping SET";
 			$sql .= " lettering_code='" . $lettre . "'";
 			$sql .= " , date_lettering = '" . $this->db->idate($now) . "'"; // todo correct date it's false
-			$sql .= "  WHERE rowid IN (" . implode(',', $ids) . ") ";
+			$sql .= "  WHERE rowid IN (" . implode(',', $ids) . ") AND date_validated IS NULL ";
 			$this->db->begin();
 
 			dol_syslog(get_class($this) . "::update sql=" . $sql, LOG_DEBUG);

+ 2 - 2
htdocs/adherents/card.php

@@ -202,7 +202,7 @@ if (empty($reshook))
 		{
 			// Creation user
 			$nuser = new User($db);
-			$result = $nuser->create_from_member($object, GETPOST('login'));
+			$result = $nuser->create_from_member($object, GETPOST('login', 'alphanohtml'));
 
 			if ($result < 0)
 			{
@@ -1747,7 +1747,7 @@ else
 		{
 			print '<tr><td>'.$langs->trans("Categories").'</td>';
 			print '<td colspan="2">';
-			print $form->showCategories($object->id, 'member', 1);
+			print $form->showCategories($object->id, Categorie::TYPE_MEMBER, 1);
 			print '</td></tr>';
 		}
 

File diff suppressed because it is too large
+ 297 - 241
htdocs/adherents/class/adherent.class.php


+ 20 - 0
htdocs/adherents/class/subscription.class.php

@@ -42,6 +42,11 @@ class Subscription extends CommonObject
      */
     public $table_element='subscription';
 
+    /**
+     * @var int  Does myobject support multicompany module ? 0=No test on entity, 1=Test with field entity, 2=Test with link by fk_soc, 'field@table'=Test with link by field@table
+     */
+    public $ismultientitymanaged = 'fk_adherent@adherent';
+
     /**
      * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
      */
@@ -88,6 +93,21 @@ class Subscription extends CommonObject
      */
     public $fk_bank;
 
+    public $fields=array(
+    	'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
+    	'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>15),
+    	'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>20),
+    	'fk_adherent' =>array('type'=>'integer', 'label'=>'Member', 'enabled'=>1, 'visible'=>-1, 'position'=>25),
+    	'dateadh' =>array('type'=>'datetime', 'label'=>'DateSubscription', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
+    	'datef' =>array('type'=>'date', 'label'=>'DateEndSubscription', 'enabled'=>1, 'visible'=>-1, 'position'=>35),
+    	'subscription' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'position'=>40, 'isameasure'=>1),
+    	'fk_bank' =>array('type'=>'integer', 'label'=>'BankId', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
+    	'note' =>array('type'=>'text', 'label'=>'Note', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
+    	'fk_type' =>array('type'=>'integer', 'label'=>'MemberType', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
+    	'fk_user_creat' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-2, 'position'=>60),
+    	'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
+    );
+
 
     /**
      *	Constructor

+ 1 - 1
htdocs/adherents/subscription.php

@@ -531,7 +531,7 @@ if ($rowid > 0)
 	{
 		print '<tr><td>'.$langs->trans("Categories").'</td>';
 		print '<td colspan="2">';
-		print $form->showCategories($object->id, 'member', 1);
+		print $form->showCategories($object->id, Categorie::TYPE_MEMBER, 1);
 		print '</td></tr>';
 	}
 

+ 8 - 4
htdocs/adherents/type.php

@@ -65,7 +65,7 @@ $subscription = GETPOST("subscription", "int");
 $duration_value = GETPOST('duration_value', 'int');
 $duration_unit = GETPOST('duration_unit', 'alpha');
 $vote = GETPOST("vote", "int");
-$comment = GETPOST("comment", 'alphanohtml');
+$comment = GETPOST("comment", 'none');
 $mail_valid = GETPOST("mail_valid", 'none');
 
 // Security check
@@ -364,7 +364,9 @@ if ($action == 'create')
 	print '</td></tr>';
 
 	print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
-	print '<textarea name="comment" wrap="soft" class="centpercent" rows="3"></textarea></td></tr>';
+	require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
+	$doleditor = new DolEditor('comment', $object->note, '', 280, 'dolibarr_notes', '', false, true, $conf->fckeditor->enabled, 15, '90%');
+	$doleditor->Create();
 
 	print '<tr><td class="tdtop">'.$langs->trans("WelcomeEMail").'</td><td>';
 	require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
@@ -807,10 +809,12 @@ if ($rowid > 0)
 		print '</td></tr>';
 
 		print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
-		print '<textarea name="comment" wrap="soft" class="centpercent" rows="3">'.$object->note.'</textarea></td></tr>';
+		require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
+		$doleditor = new DolEditor('comment', $object->note, '', 280, 'dolibarr_notes', '', false, true, $conf->fckeditor->enabled, 15, '90%');
+		$doleditor->Create();
+		print "</td></tr>";
 
 		print '<tr><td class="tdtop">'.$langs->trans("WelcomeEMail").'</td><td>';
-		require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
 		$doleditor = new DolEditor('mail_valid', $object->mail_valid, '', 280, 'dolibarr_notes', '', false, true, $conf->fckeditor->enabled, 15, '90%');
 		$doleditor->Create();
 		print "</td></tr>";

+ 2 - 2
htdocs/admin/agenda_other.php

@@ -235,7 +235,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
 
     foreach ($dirmodels as $reldir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/action/doc/");
+    	$dir = dol_buildpath($reldir."core/modules/action/doc");
 
         if (is_dir($dir))
         {
@@ -257,7 +257,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
             			print (empty($module->name) ? $name : $module->name);
             			print "</td>\n";
             			print "<td>\n";
-            			require_once $dir.$file;
+            			require_once $dir.'/'.$file;
             			$module = new $classname($db, $specimenthirdparty);
             			if (method_exists($module, 'info'))
             				print $module->info($langs);

+ 1 - 0
htdocs/admin/agenda_xcal.php

@@ -178,6 +178,7 @@ $message .= $langs->trans("AgendaUrlOptionsNotAdmin", $user->login, $user->login
 $message .= $langs->trans("AgendaUrlOptions4", $user->login, $user->login).'<br>';
 $message .= $langs->trans("AgendaUrlOptionsProject", $user->login, $user->login).'<br>';
 $message .= $langs->trans("AgendaUrlOptionsNotAutoEvent", 'systemauto', 'systemauto').'<br>';
+$message .= $langs->trans("AgendaUrlOptionsIncludeHolidays", '1', '1').'<br>';
 
 print info_admin($message);
 

+ 5 - 3
htdocs/admin/bom.php

@@ -350,7 +350,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/bom".$valdir);
+    	$realpath = $reldir."core/modules/bom".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -382,7 +383,6 @@ foreach ($dirmodels as $reldir)
 
 	                        if ($modulequalified)
 	                        {
-	                            $var = !$var;
 	                            print '<tr class="oddeven"><td width="100">';
 	                            print (empty($module->name) ? $name : $module->name);
 	                            print "</td><td>\n";
@@ -425,7 +425,9 @@ foreach ($dirmodels as $reldir)
 			                    {
 			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 					    		$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
 					    		$htmltooltip .= '<br>'.$langs->trans("WatermarkOnDraftBOMs").': '.yn($module->option_draft_watermark, 1, 1);
 

+ 15 - 12
htdocs/admin/commande.php

@@ -403,7 +403,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/commande".$valdir);
+    	$realpath = $reldir."core/modules/commande".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -471,20 +472,22 @@ foreach ($dirmodels as $reldir)
 	                            print '</td>';
 
 	                            // Info
-		    					$htmltooltip =    ''.$langs->trans("Name").': '.$module->name;
-					    		$htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown"));
+		    					$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
+					    		$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
 			                    if ($module->type == 'pdf')
 			                    {
-			                        $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
-					    		$htmltooltip.='<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
-					    		//$htmltooltip.='<br>'.$langs->trans("Discounts").': '.yn($module->option_escompte,1,1);
-					    		//$htmltooltip.='<br>'.$langs->trans("CreditNote").': '.yn($module->option_credit_note,1,1);
-					    		$htmltooltip.='<br>'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark, 1, 1);
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+					    		$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
+					    		//$htmltooltip .= '<br>'.$langs->trans("Discounts").': '.yn($module->option_escompte,1,1);
+					    		//$htmltooltip .= '<br>'.$langs->trans("CreditNote").': '.yn($module->option_credit_note,1,1);
+					    		$htmltooltip .= '<br>'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark, 1, 1);
 
 
 	                            print '<td class="center">';

+ 57 - 23
htdocs/admin/company.php

@@ -181,6 +181,13 @@ if (($action == 'update' && !GETPOST("cancel", 'alpha'))
 		}
 	}
 
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_FACEBOOK_URL", GETPOST("facebookurl", 'alpha'), 'chaine', 0, '', $conf->entity);
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_TWITTER_URL", GETPOST("twitterurl", 'alpha'), 'chaine', 0, '', $conf->entity);
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_LINKEDIN_URL", GETPOST("linkedinurl", 'alpha'), 'chaine', 0, '', $conf->entity);
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_INSTAGRAM_URL", GETPOST("instagramurl", 'alpha'), 'chaine', 0, '', $conf->entity);
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_YOUTUBE_URL", GETPOST("youtubeurl", 'alpha'), 'chaine', 0, '', $conf->entity);
+	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_GITHUB_URL", GETPOST("githuburl", 'alpha'), 'chaine', 0, '', $conf->entity);
+
 	dolibarr_set_const($db, "MAIN_INFO_SOCIETE_MANAGERS", GETPOST("MAIN_INFO_SOCIETE_MANAGERS", 'nohtml'), 'chaine', 0, '', $conf->entity);
 	dolibarr_set_const($db, "MAIN_INFO_GDPR", GETPOST("MAIN_INFO_GDPR", 'nohtml'), 'chaine', 0, '', $conf->entity);
 	dolibarr_set_const($db, "MAIN_INFO_CAPITAL", GETPOST("capital", 'nohtml'), 'chaine', 0, '', $conf->entity);
@@ -407,32 +414,26 @@ print '<table class="noborder centpercent">';
 print '<tr class="liste_titre"><th class="titlefield wordbreak">'.$langs->trans("CompanyInfo").'</th><th>'.$langs->trans("Value").'</th></tr>'."\n";
 
 // Name
-
 print '<tr class="oddeven"><td class="fieldrequired"><label for="name">'.$langs->trans("CompanyName").'</label></td><td>';
-print '<input name="nom" id="name" class="minwidth200" value="'. dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM?$conf->global->MAIN_INFO_SOCIETE_NOM: GETPOST("nom", 'nohtml')) . '"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' : ' autofocus="autofocus"').'></td></tr>'."\n";
-
-// Addresse
+print '<input name="nom" id="name" class="minwidth200" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM ? $conf->global->MAIN_INFO_SOCIETE_NOM : GETPOST("nom", 'nohtml')).'"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' : ' autofocus="autofocus"').'></td></tr>'."\n";
 
+// Address
 print '<tr class="oddeven"><td><label for="MAIN_INFO_SOCIETE_ADDRESS">'.$langs->trans("CompanyAddress").'</label></td><td>';
-print '<textarea name="MAIN_INFO_SOCIETE_ADDRESS" id="MAIN_INFO_SOCIETE_ADDRESS" class="quatrevingtpercent" rows="'.ROWS_3.'">'. ($conf->global->MAIN_INFO_SOCIETE_ADDRESS?$conf->global->MAIN_INFO_SOCIETE_ADDRESS:GETPOST("MAIN_INFO_SOCIETE_ADDRESS", 'nohtml')) . '</textarea></td></tr>'."\n";
-
+print '<textarea name="MAIN_INFO_SOCIETE_ADDRESS" id="MAIN_INFO_SOCIETE_ADDRESS" class="quatrevingtpercent" rows="'.ROWS_3.'">'.($conf->global->MAIN_INFO_SOCIETE_ADDRESS ? $conf->global->MAIN_INFO_SOCIETE_ADDRESS : GETPOST("MAIN_INFO_SOCIETE_ADDRESS", 'nohtml')).'</textarea></td></tr>'."\n";
 
 print '<tr class="oddeven"><td><label for="MAIN_INFO_SOCIETE_ZIP">'.$langs->trans("CompanyZip").'</label></td><td>';
-print '<input class="minwidth100" name="MAIN_INFO_SOCIETE_ZIP" id="MAIN_INFO_SOCIETE_ZIP" value="'. dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_ZIP?$conf->global->MAIN_INFO_SOCIETE_ZIP:GETPOST("MAIN_INFO_SOCIETE_ZIP", 'alpha')) . '"></td></tr>'."\n";
-
+print '<input class="minwidth100" name="MAIN_INFO_SOCIETE_ZIP" id="MAIN_INFO_SOCIETE_ZIP" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_ZIP ? $conf->global->MAIN_INFO_SOCIETE_ZIP : GETPOST("MAIN_INFO_SOCIETE_ZIP", 'alpha')).'"></td></tr>'."\n";
 
 print '<tr class="oddeven"><td><label for="MAIN_INFO_SOCIETE_TOWN">'.$langs->trans("CompanyTown").'</label></td><td>';
-print '<input name="MAIN_INFO_SOCIETE_TOWN" class="minwidth100" id="MAIN_INFO_SOCIETE_TOWN" value="'. dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TOWN?$conf->global->MAIN_INFO_SOCIETE_TOWN:GETPOST("MAIN_INFO_SOCIETE_TOWN", 'nohtml')) . '"></td></tr>'."\n";
+print '<input name="MAIN_INFO_SOCIETE_TOWN" class="minwidth100" id="MAIN_INFO_SOCIETE_TOWN" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TOWN ? $conf->global->MAIN_INFO_SOCIETE_TOWN : GETPOST("MAIN_INFO_SOCIETE_TOWN", 'nohtml')).'"></td></tr>'."\n";
 
 // Country
-
 print '<tr class="oddeven"><td class="fieldrequired"><label for="selectcountry_id">'.$langs->trans("Country").'</label></td><td class="maxwidthonsmartphone">';
 //if (empty($country_selected)) $country_selected=substr($langs->defaultlang,-2);    // By default, country of localization
 print $form->select_country($mysoc->country_id, 'country_id');
 if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
 print '</td></tr>'."\n";
 
-
 print '<tr class="oddeven"><td><label for="state_id">'.$langs->trans("State").'</label></td><td class="maxwidthonsmartphone">';
 $state_id = 0;
 if (!empty($conf->global->MAIN_INFO_SOCIETE_STATE))
@@ -443,22 +444,22 @@ if (!empty($conf->global->MAIN_INFO_SOCIETE_STATE))
 $formcompany->select_departement($state_id, $mysoc->country_code, 'state_id');
 print '</td></tr>'."\n";
 
-
+// Currency
 print '<tr class="oddeven"><td><label for="currency">'.$langs->trans("CompanyCurrency").'</label></td><td>';
 print $form->selectCurrency($conf->currency, "currency");
 print '</td></tr>'."\n";
 
-
+// Phone
 print '<tr class="oddeven"><td><label for="phone">'.$langs->trans("Phone").'</label></td><td>';
 print '<input name="tel" id="phone" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TEL).'"></td></tr>';
 print '</td></tr>'."\n";
 
-
+// Fax
 print '<tr class="oddeven"><td><label for="fax">'.$langs->trans("Fax").'</label></td><td>';
 print '<input name="fax" id="fax" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_FAX).'"></td></tr>';
 print '</td></tr>'."\n";
 
-
+// Email
 print '<tr class="oddeven"><td><label for="email">'.$langs->trans("EMail").'</label></td><td>';
 print '<input name="mail" id="email" class="minwidth200" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MAIL).'"></td></tr>';
 print '</td></tr>'."\n";
@@ -516,6 +517,45 @@ print '</td></tr>';
 
 print '</table>';
 
+// Social networks
+print '<br>';
+print '<table class="noborder centpercent">';
+print '<tr class="liste_titre">';
+print '<td class="titlefield">'.$langs->trans("SocialNetworksInformation").'</td><td>'.$langs->trans("Value").'</td>';
+print "</tr>\n";
+
+// Facebook
+print '<tr class="oddeven"><td><label for="facebookurl">'.$langs->trans("SocialNetworksFacebookURL").'</label></td><td>';
+print '<input name="facebookurl" id="facebookurl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_FACEBOOK_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+// Twitter
+print '<tr class="oddeven"><td><label for="twitterurl">'.$langs->trans("SocialNetworksTwitterURL").'</label></td><td>';
+print '<input name="twitterurl" id="twitterurl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TWITTER_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+// LinkedIn
+print '<tr class="oddeven"><td><label for="linkedinurl">'.$langs->trans("SocialNetworksLinkedinURL").'</label></td><td>';
+print '<input name="linkedinurl" id="linkedinurl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_LINKEDIN_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+// Instagram
+print '<tr class="oddeven"><td><label for="instagramurl">'.$langs->trans("SocialNetworksInstagramURL").'</label></td><td>';
+print '<input name="instagramurl" id="instagramurl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_INSTAGRAM_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+// Youtube
+print '<tr class="oddeven"><td><label for="youtubeurl">'.$langs->trans("SocialNetworksYoutubeURL").'</label></td><td>';
+print '<input name="youtubeurl" id="youtubeurl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_YOUTUBE_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+// Github
+print '<tr class="oddeven"><td><label for="githuburl">'.$langs->trans("SocialNetworksGithubURL").'</label></td><td>';
+print '<input name="githuburl" id="githuburl" class="minwidth300" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_GITHUB_URL).'"></td></tr>';
+print '</td></tr>'."\n";
+
+print "</table>";
+
 print '<br>';
 
 // IDs of the company (country-specific)
@@ -525,24 +565,20 @@ print '<tr class="liste_titre"><td class="titlefield">'.$langs->trans("CompanyId
 $langs->load("companies");
 
 // Managing Director(s)
-
 print '<tr class="oddeven"><td><label for="director">'.$langs->trans("ManagingDirectors").'</label></td><td>';
 print '<input name="MAIN_INFO_SOCIETE_MANAGERS" id="director" class="minwidth200" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MANAGERS).'"></td></tr>';
 
 // GDPR contact
-
 print '<tr class="oddeven"><td>';
 print $form->textwithpicto($langs->trans("GDPRContact"), $langs->trans("GDPRContactDesc"));
 print '</td><td>';
 print '<input name="MAIN_INFO_GDPR" id="director" class="minwidth500" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_GDPR).'"></td></tr>';
 
 // Capital
-
 print '<tr class="oddeven"><td><label for="capital">'.$langs->trans("Capital").'</label></td><td>';
 print '<input name="capital" id="capital" class="minwidth100" value="'.dol_escape_htmltag($conf->global->MAIN_INFO_CAPITAL).'"></td></tr>';
 
 // Juridical Status
-
 print '<tr class="oddeven"><td><label for="forme_juridique_code">'.$langs->trans("JuridicalStatus").'</label></td><td>';
 if ($mysoc->country_code) {
 	print $formcompany->select_juridicalstatus($conf->global->MAIN_INFO_SOCIETE_FORME_JURIDIQUE, $mysoc->country_code, '', 'forme_juridique_code');
@@ -551,7 +587,7 @@ if ($mysoc->country_code) {
 }
 print '</td></tr>';
 
-// ProfID1
+// ProfId1
 if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-')
 {
 	print '<tr class="oddeven"><td><label for="profid1">'.$langs->transcountry("ProfId1", $mysoc->country_code).'</label></td><td>';
@@ -641,14 +677,12 @@ if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-')
 	print '</td></tr>';
 }
 
-// TVA Intra
-
+// Intra-community VAT number
 print '<tr class="oddeven"><td><label for="intra_vat">'.$langs->trans("VATIntra").'</label></td><td>';
 print '<input name="tva" id="intra_vat" class="minwidth200" value="'.dol_escape_htmltag(!empty($conf->global->MAIN_INFO_TVAINTRA) ? $conf->global->MAIN_INFO_TVAINTRA : '').'">';
 print '</td></tr>';
 
 // Object of the company
-
 print '<tr class="oddeven"><td><label for="object">'.$langs->trans("CompanyObject").'</label></td><td>';
 print '<textarea class="flat quatrevingtpercent" name="object" id="object" rows="'.ROWS_5.'">'.(!empty($conf->global->MAIN_INFO_SOCIETE_OBJECT) ? $conf->global->MAIN_INFO_SOCIETE_OBJECT : '').'</textarea></td></tr>';
 print '</td></tr>';

+ 13 - 10
htdocs/admin/contract.php

@@ -339,7 +339,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/contract".$valdir);
+    	$realpath = $reldir."core/modules/contract".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -407,18 +408,20 @@ foreach ($dirmodels as $reldir)
 	                            print '</td>';
 
 	                            // Info
-		    					$htmltooltip =    ''.$langs->trans("Name").': '.$module->name;
-					    		$htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown"));
+		    					$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
+					    		$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
 			                    if ($module->type == 'pdf')
 			                    {
-			                        $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
-					    		$htmltooltip.='<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark, 1, 1);
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+					    		$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("WatermarkOnDraftOrders").': '.yn($module->option_draft_watermark, 1, 1);
 
 
 	                            print '<td class="center">';

+ 4 - 0
htdocs/admin/delais.php

@@ -107,6 +107,10 @@ $modules = array(
 				array(
 						'code' => 'MAIN_DELAY_MEMBERS',
 						'img' => 'user'
+				),
+        array(
+						'code' => 'MAIN_DELAY_MEMBERS_SHIFT',
+						'img' => 'user'
 				)
 		),
 		'expensereport' => array(

+ 126 - 123
htdocs/admin/facture.php

@@ -36,13 +36,13 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
 // Load translation files required by the page
 $langs->loadLangs(array('admin', 'errors', 'other', 'bills'));
 
-if (! $user->admin) accessforbidden();
+if (!$user->admin) accessforbidden();
 
 $action = GETPOST('action', 'alpha');
 $value = GETPOST('value', 'alpha');
 $label = GETPOST('label', 'alpha');
 $scandir = GETPOST('scan_dir', 'alpha');
-$type='invoice';
+$type = 'invoice';
 
 
 /*
@@ -53,22 +53,22 @@ include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
 
 if ($action == 'updateMask')
 {
-    $maskconstinvoice=GETPOST('maskconstinvoice', 'alpha');
-    $maskconstreplacement=GETPOST('maskconstreplacement', 'alpha');
-    $maskconstcredit=GETPOST('maskconstcredit', 'alpha');
-	$maskconstdeposit=GETPOST('maskconstdeposit', 'alpha');
-    $maskinvoice=GETPOST('maskinvoice', 'alpha');
-    $maskreplacement=GETPOST('maskreplacement', 'alpha');
-    $maskcredit=GETPOST('maskcredit', 'alpha');
-	$maskdeposit=GETPOST('maskdeposit', 'alpha');
+    $maskconstinvoice = GETPOST('maskconstinvoice', 'alpha');
+    $maskconstreplacement = GETPOST('maskconstreplacement', 'alpha');
+    $maskconstcredit = GETPOST('maskconstcredit', 'alpha');
+	$maskconstdeposit = GETPOST('maskconstdeposit', 'alpha');
+    $maskinvoice = GETPOST('maskinvoice', 'alpha');
+    $maskreplacement = GETPOST('maskreplacement', 'alpha');
+    $maskcredit = GETPOST('maskcredit', 'alpha');
+	$maskdeposit = GETPOST('maskdeposit', 'alpha');
     if ($maskconstinvoice) $res = dolibarr_set_const($db, $maskconstinvoice, $maskinvoice, 'chaine', 0, '', $conf->entity);
     if ($maskconstreplacement) $res = dolibarr_set_const($db, $maskconstreplacement, $maskreplacement, 'chaine', 0, '', $conf->entity);
     if ($maskconstcredit)  $res = dolibarr_set_const($db, $maskconstcredit, $maskcredit, 'chaine', 0, '', $conf->entity);
 	if ($maskconstdeposit)  $res = dolibarr_set_const($db, $maskconstdeposit, $maskdeposit, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -79,20 +79,20 @@ if ($action == 'updateMask')
 }
 elseif ($action == 'specimen')
 {
-    $modele=GETPOST('module', 'alpha');
+    $modele = GETPOST('module', 'alpha');
 
     $facture = new Facture($db);
     $facture->initAsSpecimen();
 
 	// Search template files
-	$file=''; $classname=''; $filefound=0;
-	$dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
-	foreach($dirmodels as $reldir)
+	$file = ''; $classname = ''; $filefound = 0;
+	$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
+	foreach ($dirmodels as $reldir)
 	{
-	    $file=dol_buildpath($reldir."core/modules/facture/doc/pdf_".$modele.".modules.php", 0);
+	    $file = dol_buildpath($reldir."core/modules/facture/doc/pdf_".$modele.".modules.php", 0);
     	if (file_exists($file))
     	{
-    		$filefound=1;
+    		$filefound = 1;
     		$classname = "pdf_".$modele;
     		break;
     	}
@@ -167,9 +167,9 @@ elseif ($action == 'setribchq')
 	$res = dolibarr_set_const($db, "FACTURE_RIB_NUMBER", $rib, 'chaine', 0, '', $conf->entity);
     $res = dolibarr_set_const($db, "FACTURE_CHQ_NUMBER", $chq, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -184,9 +184,9 @@ elseif ($action == 'set_FACTURE_DRAFT_WATERMARK')
 
     $res = dolibarr_set_const($db, "FACTURE_DRAFT_WATERMARK", trim($draft), 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -198,13 +198,13 @@ elseif ($action == 'set_FACTURE_DRAFT_WATERMARK')
 
 elseif ($action == 'set_INVOICE_FREE_TEXT')
 {
-	$freetext = GETPOST('INVOICE_FREE_TEXT', 'none');	// No alpha here, we want exact string
+	$freetext = GETPOST('INVOICE_FREE_TEXT', 'none'); // No alpha here, we want exact string
 
     $res = dolibarr_set_const($db, "INVOICE_FREE_TEXT", $freetext, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -219,9 +219,9 @@ elseif ($action == 'setforcedate')
 
     $res = dolibarr_set_const($db, "FAC_FORCE_DATE_VALIDATION", $forcedate, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -232,19 +232,19 @@ elseif ($action == 'setforcedate')
 }
 elseif ($action == 'setDefaultPDFModulesByType')
 {
-    $invoicetypemodels =  GETPOST('invoicetypemodels');
+    $invoicetypemodels = GETPOST('invoicetypemodels');
 
-    if(!empty($invoicetypemodels) && is_array($invoicetypemodels))
+    if (!empty($invoicetypemodels) && is_array($invoicetypemodels))
     {
         $error = 0;
 
         foreach ($invoicetypemodels as $type => $value)
         {
             $res = dolibarr_set_const($db, 'FACTURE_ADDON_PDF_'.intval($type), $value, 'chaine', 0, '', $conf->entity);
-            if (! $res > 0) $error++;
+            if (!$res > 0) $error++;
         }
 
-        if (! $error)
+        if (!$error)
         {
             setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
         }
@@ -260,14 +260,14 @@ elseif ($action == 'setDefaultPDFModulesByType')
  * View
  */
 
-$dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
+$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
 
 llxHeader("", $langs->trans("BillsSetup"), 'EN:Invoice_Configuration|FR:Configuration_module_facture|ES:ConfiguracionFactura');
 
-$form=new Form($db);
+$form = new Form($db);
 
 
-$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
+$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
 print load_fiche_titre($langs->trans("BillsSetup"), $linkback, 'title_setup');
 
 $head = invoice_admin_prepare_head();
@@ -298,24 +298,24 @@ foreach ($dirmodels as $reldir)
         $handle = opendir($dir);
         if (is_resource($handle))
         {
-            while (($file = readdir($handle))!==false)
+            while (($file = readdir($handle)) !== false)
             {
-                if (! is_dir($dir.$file) || (substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS'))
+                if (!is_dir($dir.$file) || (substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS'))
                 {
                     $filebis = $file;
                     $classname = preg_replace('/\.php$/', '', $file);
                     // For compatibility
-                    if (! is_file($dir.$filebis))
+                    if (!is_file($dir.$filebis))
                     {
                         $filebis = $file."/".$file.".modules.php";
                         $classname = "mod_facture_".$file;
                     }
                     // Check if there is a filter on country
                     preg_match('/\-(.*)_(.*)$/', $classname, $reg);
-                    if (! empty($reg[2]) && $reg[2] != strtoupper($mysoc->country_code)) continue;
+                    if (!empty($reg[2]) && $reg[2] != strtoupper($mysoc->country_code)) continue;
 
                     $classname = preg_replace('/\-.*$/', '', $classname);
-                    if (! class_exists($classname) && is_readable($dir.$filebis) && (preg_match('/mod_/', $filebis) || preg_match('/mod_/', $classname)) && substr($filebis, dol_strlen($filebis)-3, 3) == 'php')
+                    if (!class_exists($classname) && is_readable($dir.$filebis) && (preg_match('/mod_/', $filebis) || preg_match('/mod_/', $classname)) && substr($filebis, dol_strlen($filebis) - 3, 3) == 'php')
                     {
                         // Charging the numbering class
                         require_once $dir.$filebis;
@@ -323,7 +323,7 @@ foreach ($dirmodels as $reldir)
                         $module = new $classname($db);
 
                         // Show modules according to features level
-                        if ($module->version == 'development'  && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
+                        if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
                         if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue;
 
                         if ($module->isEnabled())
@@ -338,9 +338,9 @@ foreach ($dirmodels as $reldir)
 
                             // Show example of numbering module
                             print '<td class="nowrap">';
-                            $tmp=$module->getExample();
+                            $tmp = $module->getExample();
                             if (preg_match('/^Error/', $tmp)) print '<div class="error">'.$langs->trans($tmp).'</div>';
-                            elseif ($tmp=='NotConfigured') print $langs->trans($tmp);
+                            elseif ($tmp == 'NotConfigured') print $langs->trans($tmp);
                             else print $tmp;
                             print '</td>'."\n";
 
@@ -356,62 +356,62 @@ foreach ($dirmodels as $reldir)
                             }
                             print '</td>';
 
-                            $facture=new Facture($db);
+                            $facture = new Facture($db);
                             $facture->initAsSpecimen();
 
                             // Example for standard invoice
-                            $htmltooltip='';
-                            $htmltooltip.=''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
-                            $facture->type=0;
-                            $nextval=$module->getNextValue($mysoc, $facture);
+                            $htmltooltip = '';
+                            $htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
+                            $facture->type = 0;
+                            $nextval = $module->getNextValue($mysoc, $facture);
                             if ("$nextval" != $langs->trans("NotAvailable")) {  // Keep " on nextval
-                                $htmltooltip.=$langs->trans("NextValueForInvoices").': ';
+                                $htmltooltip .= $langs->trans("NextValueForInvoices").': ';
                                 if ($nextval) {
-                                    if (preg_match('/^Error/', $nextval) || $nextval=='NotConfigured')
+                                    if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured')
                                         $nextval = $langs->trans($nextval);
-                                    $htmltooltip.=$nextval.'<br>';
+                                    $htmltooltip .= $nextval.'<br>';
                                 } else {
-                                    $htmltooltip.=$langs->trans($module->error).'<br>';
+                                    $htmltooltip .= $langs->trans($module->error).'<br>';
                                 }
                             }
                             // Example for remplacement
-                            $facture->type=1;
-                            $nextval=$module->getNextValue($mysoc, $facture);
+                            $facture->type = 1;
+                            $nextval = $module->getNextValue($mysoc, $facture);
                             if ("$nextval" != $langs->trans("NotAvailable")) {  // Keep " on nextval
-                                $htmltooltip.=$langs->trans("NextValueForReplacements").': ';
+                                $htmltooltip .= $langs->trans("NextValueForReplacements").': ';
                                 if ($nextval) {
-                                    if (preg_match('/^Error/', $nextval) || $nextval=='NotConfigured')
+                                    if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured')
                                         $nextval = $langs->trans($nextval);
-                                    $htmltooltip.=$nextval.'<br>';
+                                    $htmltooltip .= $nextval.'<br>';
                                 } else {
-                                    $htmltooltip.=$langs->trans($module->error).'<br>';
+                                    $htmltooltip .= $langs->trans($module->error).'<br>';
                                 }
                             }
 
                             // Example for credit invoice
-                            $facture->type=2;
-                            $nextval=$module->getNextValue($mysoc, $facture);
+                            $facture->type = 2;
+                            $nextval = $module->getNextValue($mysoc, $facture);
                             if ("$nextval" != $langs->trans("NotAvailable")) {  // Keep " on nextval
-                                $htmltooltip.=$langs->trans("NextValueForCreditNotes").': ';
+                                $htmltooltip .= $langs->trans("NextValueForCreditNotes").': ';
                                 if ($nextval) {
-                                    if (preg_match('/^Error/', $nextval) || $nextval=='NotConfigured')
+                                    if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured')
                                         $nextval = $langs->trans($nextval);
-                                    $htmltooltip.=$nextval.'<br>';
+                                    $htmltooltip .= $nextval.'<br>';
                                 } else {
-                                    $htmltooltip.=$langs->trans($module->error).'<br>';
+                                    $htmltooltip .= $langs->trans($module->error).'<br>';
                                 }
                             }
                             // Example for deposit invoice
-                            $facture->type=3;
-                            $nextval=$module->getNextValue($mysoc, $facture);
+                            $facture->type = 3;
+                            $nextval = $module->getNextValue($mysoc, $facture);
                             if ("$nextval" != $langs->trans("NotAvailable")) {  // Keep " on nextval
-                                $htmltooltip.=$langs->trans("NextValueForDeposit").': ';
+                                $htmltooltip .= $langs->trans("NextValueForDeposit").': ';
                                 if ($nextval) {
-                                    if (preg_match('/^Error/', $nextval) || $nextval=='NotConfigured')
+                                    if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured')
                                         $nextval = $langs->trans($nextval);
-                                    $htmltooltip.=$nextval;
+                                    $htmltooltip .= $nextval;
                                 } else {
-                                    $htmltooltip.=$langs->trans($module->error);
+                                    $htmltooltip .= $langs->trans($module->error);
                                 }
                             }
 
@@ -420,7 +420,7 @@ foreach ($dirmodels as $reldir)
 
                             if ($conf->global->FACTURE_ADDON.'.php' == $file)  // If module is the one used, we show existing errors
                             {
-                                if (! empty($module->error)) dol_htmloutput_mesg($module->error, '', 'error', 1);
+                                if (!empty($module->error)) dol_htmloutput_mesg($module->error, '', 'error', 1);
                             }
 
                             print '</td>';
@@ -445,17 +445,17 @@ print '<br>';
 print load_fiche_titre($langs->trans("BillsPDFModules"), '', '');
 
 // Load array def with activated templates
-$type='invoice';
+$type = 'invoice';
 $def = array();
 $sql = "SELECT nom";
-$sql.= " FROM ".MAIN_DB_PREFIX."document_model";
-$sql.= " WHERE type = '".$type."'";
-$sql.= " AND entity = ".$conf->entity;
-$resql=$db->query($sql);
+$sql .= " FROM ".MAIN_DB_PREFIX."document_model";
+$sql .= " WHERE type = '".$type."'";
+$sql .= " AND entity = ".$conf->entity;
+$resql = $db->query($sql);
 if ($resql)
 {
     $i = 0;
-    $num_rows=$db->num_rows($resql);
+    $num_rows = $db->num_rows($resql);
     while ($i < $num_rows)
     {
         $array = $db->fetch_array($resql);
@@ -484,42 +484,43 @@ $activatedModels = array();
 
 foreach ($dirmodels as $reldir)
 {
-    foreach (array('','/doc') as $valdir)
+    foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/facture".$valdir);
+    	$realpath = $reldir."core/modules/facture".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
-            $handle=opendir($dir);
+            $handle = opendir($dir);
             if (is_resource($handle))
             {
-                while (($file = readdir($handle))!==false)
+                while (($file = readdir($handle)) !== false)
                 {
-                    $filelist[]=$file;
+                    $filelist[] = $file;
                 }
                 closedir($handle);
                 arsort($filelist);
 
-                foreach($filelist as $file)
+                foreach ($filelist as $file)
                 {
                     if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file))
                     {
                     	if (file_exists($dir.'/'.$file))
                     	{
-                    		$name = substr($file, 4, dol_strlen($file) -16);
-	                        $classname = substr($file, 0, dol_strlen($file) -12);
+                    		$name = substr($file, 4, dol_strlen($file) - 16);
+	                        $classname = substr($file, 0, dol_strlen($file) - 12);
 
 	                        require_once $dir.'/'.$file;
 	                        $module = new $classname($db);
 
-	                        $modulequalified=1;
-	                        if ($module->version == 'development'  && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified=0;
-	                        if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified=0;
+	                        $modulequalified = 1;
+	                        if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified = 0;
+	                        if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified = 0;
 
 	                        if ($modulequalified)
 	                        {
 	                            print '<tr class="oddeven"><td width="100">';
-	                            print (empty($module->name)?$name:$module->name);
+	                            print (empty($module->name) ? $name : $module->name);
 	                            print "</td><td>\n";
 	                            if (method_exists($module, 'info')) print $module->info($langs);
 	                            else print $module->description;
@@ -554,20 +555,22 @@ foreach ($dirmodels as $reldir)
 	                            print '</td>';
 
 	                            // Info
-	                            $htmltooltip =    ''.$langs->trans("Name").': '.$module->name;
-	                            $htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown"));
+	                            $htmltooltip = ''.$langs->trans("Name").': '.$module->name;
+	                            $htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
 	                            if ($module->type == 'pdf')
 	                            {
-	                                $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+	                                $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 	                            }
-	                            $htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
-	                            $htmltooltip.='<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("Discounts").': '.yn($module->option_escompte, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("CreditNote").': '.yn($module->option_credit_note, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
-	                            $htmltooltip.='<br>'.$langs->trans("WatermarkOnDraftInvoices").': '.yn($module->option_draft_watermark, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+	                            $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+	                            $htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("Discounts").': '.yn($module->option_escompte, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("CreditNote").': '.yn($module->option_credit_note, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
+	                            $htmltooltip .= '<br>'.$langs->trans("WatermarkOnDraftInvoices").': '.yn($module->option_draft_watermark, 1, 1);
 
 
 	                            print '<td class="center">';
@@ -597,7 +600,7 @@ foreach ($dirmodels as $reldir)
 }
 print '</table>';
 
-if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
+if (!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
 {
     /*
      *  Document templates generators
@@ -614,13 +617,13 @@ if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
     print '<td class="right"><input type="submit" class="button" value="'.$langs->trans("Modify").'"></td>';
     print "</tr>\n";
 
-    $listtype=array(
+    $listtype = array(
         Facture::TYPE_STANDARD=>$langs->trans("InvoiceStandard"),
         Facture::TYPE_REPLACEMENT=>$langs->trans("InvoiceReplacement"),
         Facture::TYPE_CREDIT_NOTE=>$langs->trans("InvoiceAvoir"),
         Facture::TYPE_DEPOSIT=>$langs->trans("InvoiceDeposit"),
     );
-    if (! empty($conf->global->INVOICE_USE_SITUATION))
+    if (!empty($conf->global->INVOICE_USE_SITUATION))
     {
         $listtype[Facture::TYPE_SITUATION] = $langs->trans("InvoiceSituation");
     }
@@ -628,7 +631,7 @@ if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf
     foreach ($listtype as $type => $trans)
     {
         $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type;
-        $current = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF;
+        $current = !empty($conf->global->{$thisTypeConfName}) ? $conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF;
         print '<tr >';
         print '<td>'.$trans.'</td>';
         print '<td colspan="2" >'.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db), $current, 0, 0, 0).'</td>';
@@ -660,14 +663,14 @@ print "</tr>\n";
 print '<tr class="oddeven">';
 print "<td>".$langs->trans("SuggestPaymentByRIBOnAccount")."</td>";
 print "<td>";
-if (! empty($conf->banque->enabled))
+if (!empty($conf->banque->enabled))
 {
     $sql = "SELECT rowid, label";
-    $sql.= " FROM ".MAIN_DB_PREFIX."bank_account";
-    $sql.= " WHERE clos = 0";
-    $sql.= " AND courant = 1";
-    $sql.= " AND entity IN (".getEntity('bank_account').")";
-    $resql=$db->query($sql);
+    $sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
+    $sql .= " WHERE clos = 0";
+    $sql .= " AND courant = 1";
+    $sql .= " AND entity IN (".getEntity('bank_account').")";
+    $resql = $db->query($sql);
     if ($resql)
     {
         $num = $db->num_rows($resql);
@@ -681,7 +684,7 @@ if (! empty($conf->banque->enabled))
                 $row = $db->fetch_row($resql);
 
                 print '<option value="'.$row[0].'"';
-                print $conf->global->FACTURE_RIB_NUMBER == $row[0] ? ' selected':'';
+                print $conf->global->FACTURE_RIB_NUMBER == $row[0] ? ' selected' : '';
                 print '>'.$row[1].'</option>';
 
                 $i++;
@@ -705,15 +708,15 @@ print "<td>".$langs->trans("SuggestPaymentByChequeToAddress")."</td>";
 print "<td>";
 print '<select class="flat" name="chq" id="chq">';
 print '<option value="0">'.$langs->trans("DoNotSuggestPaymentMode").'</option>';
-print '<option value="-1"'.($conf->global->FACTURE_CHQ_NUMBER?' selected':'').'>'.$langs->trans("MenuCompanySetup").' ('.($mysoc->name?$mysoc->name:$langs->trans("NotDefined")).')</option>';
+print '<option value="-1"'.($conf->global->FACTURE_CHQ_NUMBER ? ' selected' : '').'>'.$langs->trans("MenuCompanySetup").' ('.($mysoc->name ? $mysoc->name : $langs->trans("NotDefined")).')</option>';
 
 $sql = "SELECT rowid, label";
-$sql.= " FROM ".MAIN_DB_PREFIX."bank_account";
-$sql.= " WHERE clos = 0";
-$sql.= " AND courant = 1";
-$sql.= " AND entity IN (".getEntity('bank_account').")";
+$sql .= " FROM ".MAIN_DB_PREFIX."bank_account";
+$sql .= " WHERE clos = 0";
+$sql .= " AND courant = 1";
+$sql .= " AND entity IN (".getEntity('bank_account').")";
 
-$resql=$db->query($sql);
+$resql = $db->query($sql);
 if ($resql)
 {
     $num = $db->num_rows($resql);
@@ -723,7 +726,7 @@ if ($resql)
         $row = $db->fetch_row($resql);
 
         print '<option value="'.$row[0].'"';
-        print $conf->global->FACTURE_CHQ_NUMBER == $row[0] ? ' selected':'';
+        print $conf->global->FACTURE_CHQ_NUMBER == $row[0] ? ' selected' : '';
         print '>'.$langs->trans("OwnerOfBankAccount", $row[1]).'</option>';
 
         $i++;
@@ -758,18 +761,18 @@ print '<input type="submit" class="button" value="'.$langs->trans("Modify").'" /
 print "</td></tr>\n";
 print '</form>';
 
-$substitutionarray=pdf_getSubstitutionArray($langs, null, null, 2);
-$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation");
+$substitutionarray = pdf_getSubstitutionArray($langs, null, null, 2);
+$substitutionarray['__(AnyTranslationKey)__'] = $langs->trans("Translation");
 $htmltext = '<i>'.$langs->trans("AvailableVariables").':<br>';
-foreach($substitutionarray as $key => $val)	$htmltext.=$key.'<br>';
-$htmltext.='</i>';
+foreach ($substitutionarray as $key => $val)	$htmltext .= $key.'<br>';
+$htmltext .= '</i>';
 
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
 print '<input type="hidden" name="token" value="'.newToken().'" />';
 print '<input type="hidden" name="action" value="set_INVOICE_FREE_TEXT" />';
 print '<tr class="oddeven"><td colspan="2">';
 print $form->textwithpicto($langs->trans("FreeLegalTextOnInvoices"), $langs->trans("AddCRIfTooLong").'<br><br>'.$htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'<br>';
-$variablename='INVOICE_FREE_TEXT';
+$variablename = 'INVOICE_FREE_TEXT';
 if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))
 {
     print '<textarea name="'.$variablename.'" class="flat" cols="120">'.$conf->global->$variablename.'</textarea>';
@@ -777,7 +780,7 @@ if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))
 else
 {
     include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
-    $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes');
+    $doleditor = new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes');
     print $doleditor->Create();
 }
 print '</td><td class="right">';

+ 4 - 1
htdocs/admin/fichinter.php

@@ -409,7 +409,8 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/fichinter/doc/");
+	$realpath = $reldir."core/modules/fichinter/doc";
+	$dir = dol_buildpath($realpath);
 
 	if (is_dir($dir))
 	{
@@ -480,6 +481,8 @@ foreach ($dirmodels as $reldir)
 		    				$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
 		    				$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
 		    				$htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+		    				$htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
 		    				$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 		    				$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
 		    				$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);

+ 5 - 2
htdocs/admin/holiday.php

@@ -355,7 +355,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/holiday".$valdir);
+    	$realpath = $reldir."core/modules/holiday".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -429,7 +430,9 @@ foreach ($dirmodels as $reldir)
 			                    {
 			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 					    		$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
 					    		$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
 					    		$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);

+ 4 - 2
htdocs/admin/ihm.php

@@ -83,7 +83,7 @@ if ($action == 'update')
 {
 	dolibarr_set_const($db, "MAIN_LANG_DEFAULT", $_POST["MAIN_LANG_DEFAULT"], 'chaine', 0, '', $conf->entity);
 	dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int) $conf->global->MAIN_IHM_PARAMS_REV+1, 'chaine', 0, '', $conf->entity);
-	dolibarr_set_const($db, "MAIN_MULTILANGS", $_POST["MAIN_MULTILANGS"], 'chaine', 0, '', $conf->entity);
+	//dolibarr_set_const($db, "MAIN_MULTILANGS", $_POST["MAIN_MULTILANGS"], 'chaine', 0, '', $conf->entity);
 
 	dolibarr_set_const($db, "MAIN_THEME", $_POST["main_theme"], 'chaine', 0, '', $conf->entity);
 
@@ -241,13 +241,15 @@ print '</tr>';
 // Default language
 print '<tr class="oddeven"><td class="titlefield">'.$langs->trans("DefaultLanguage").'</td><td>';
 print $formadmin->select_language($conf->global->MAIN_LANG_DEFAULT, 'MAIN_LANG_DEFAULT', 1, 0, 0, 0, 0, 'minwidth300', 2);
+print '<input class="button" type="submit" name="submit" value="'.$langs->trans("Save").'">';
 print '</td>';
 print '<td width="20">&nbsp;</td>';
 print '</tr>';
 
 // Multilingual GUI
 print '<tr class="oddeven"><td class="titlefield">'.$langs->trans("EnableMultilangInterface").'</td><td>';
-print $form->selectyesno('MAIN_MULTILANGS', $conf->global->MAIN_MULTILANGS, 1);
+//print $form->selectyesno('MAIN_MULTILANGS', $conf->global->MAIN_MULTILANGS, 1);
+print ajax_constantonoff('MAIN_MULTILANGS');
 print '</td>';
 print '<td width="20">&nbsp;</td>';
 print '</tr>';

+ 74 - 41
htdocs/admin/limits.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2007-2012	Laurent Destailleur	<eldy@users.sourceforge.net>
- * Copyright (C) 2009-2012	Regis Houssin		<regis.houssin@inodbox.com>
+ * Copyright (C) 2009-2018	Regis Houssin		<regis.houssin@inodbox.com>
  * Copyright (C) 2010		Juanjo Menent		<jmenent@2byte.es>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -32,31 +32,37 @@ $langs->loadLangs(array('companies', 'products', 'admin'));
 if (! $user->admin) accessforbidden();
 
 $action = GETPOST('action', 'alpha');
+$currencycode = GETPOST('currencycode', 'alpha');
+
+$mainmaxdecimalsunit = 'MAIN_MAX_DECIMALS_UNIT'.(! empty($currencycode)?'_'.$currencycode:'');
+$mainmaxdecimalstot = 'MAIN_MAX_DECIMALS_TOT'.(! empty($currencycode)?'_'.$currencycode:'');
+$mainmaxdecimalsshown = 'MAIN_MAX_DECIMALS_SHOWN'.(! empty($currencycode)?'_'.$currencycode:'');
+$mainroundingruletot = 'MAIN_ROUNDING_RULE_TOT'.(! empty($currencycode)?'_'.$currencycode:'');
 
 if ($action == 'update')
 {
-    $error=0;
-    $MAXDEC=8;
-    if ($_POST["MAIN_MAX_DECIMALS_UNIT"] > $MAXDEC
-    || $_POST["MAIN_MAX_DECIMALS_TOT"] > $MAXDEC
-    || $_POST["MAIN_MAX_DECIMALS_SHOWN"] > $MAXDEC)
+	$error=0;
+	$MAXDEC=8;
+	if ($_POST[$mainmaxdecimalsunit] > $MAXDEC
+	|| $_POST[$mainmaxdecimalstot] > $MAXDEC
+	|| $_POST[$mainmaxdecimalsshown] > $MAXDEC)
     {
         $error++;
 	    setEventMessages($langs->trans("ErrorDecimalLargerThanAreForbidden", $MAXDEC), null, 'errors');
     }
 
-    if ($_POST["MAIN_MAX_DECIMALS_UNIT"]  < 0
-    || $_POST["MAIN_MAX_DECIMALS_TOT"]   < 0
-    || $_POST["MAIN_MAX_DECIMALS_SHOWN"] < 0)
+    if ($_POST[$mainmaxdecimalsunit].(! empty($currencycode)?'_'.$currencycode:'')  < 0
+    || $_POST[$mainmaxdecimalstot] < 0
+    || $_POST[$mainmaxdecimalsshown] < 0)
     {
         $langs->load("errors");
         $error++;
 	    setEventMessages($langs->trans("ErrorNegativeValueNotAllowed"), null, 'errors');
     }
 
-    if ($_POST["MAIN_ROUNDING_RULE_TOT"])
+    if ($_POST[$mainroundingruletot])
     {
-        if ($_POST["MAIN_ROUNDING_RULE_TOT"] * pow(10, $_POST["MAIN_MAX_DECIMALS_TOT"]) < 1)
+        if ($_POST[$mainroundingruletot] * pow(10, $_POST[$mainmaxdecimalstot]) < 1)
         {
             $langs->load("errors");
             $error++;
@@ -66,22 +72,21 @@ if ($action == 'update')
 
     if (! $error)
     {
-        dolibarr_set_const($db, "MAIN_MAX_DECIMALS_UNIT", $_POST["MAIN_MAX_DECIMALS_UNIT"], 'chaine', 0, '', $conf->entity);
-        dolibarr_set_const($db, "MAIN_MAX_DECIMALS_TOT", $_POST["MAIN_MAX_DECIMALS_TOT"], 'chaine', 0, '', $conf->entity);
-        dolibarr_set_const($db, "MAIN_MAX_DECIMALS_SHOWN", $_POST["MAIN_MAX_DECIMALS_SHOWN"], 'chaine', 0, '', $conf->entity);
+    	dolibarr_set_const($db, $mainmaxdecimalsunit, $_POST[$mainmaxdecimalsunit], 'chaine', 0, '', $conf->entity);
+    	dolibarr_set_const($db, $mainmaxdecimalstot, $_POST[$mainmaxdecimalstot], 'chaine', 0, '', $conf->entity);
+    	dolibarr_set_const($db, $mainmaxdecimalsshown, $_POST[$mainmaxdecimalsshown], 'chaine', 0, '', $conf->entity);
 
-        dolibarr_set_const($db, "MAIN_ROUNDING_RULE_TOT", $_POST["MAIN_ROUNDING_RULE_TOT"], 'chaine', 0, '', $conf->entity);
+    	dolibarr_set_const($db, $mainroundingruletot, $_POST[$mainroundingruletot], 'chaine', 0, '', $conf->entity);
 
-        header("Location: ".$_SERVER["PHP_SELF"]."?mainmenu=home&leftmenu=setup");
+        header("Location: ".$_SERVER["PHP_SELF"]."?mainmenu=home&leftmenu=setup".(! empty($currencycode)?'&currencycode='.$currencycode:''));
         exit;
     }
 }
 
 
-
 /*
  * View
-*/
+ */
 
 $form=new Form($db);
 
@@ -89,6 +94,31 @@ llxHeader();
 
 print load_fiche_titre($langs->trans("LimitsSetup"), '', 'title_setup');
 
+$currencycode = (! empty($currencycode)?$currencycode:$conf->currency);
+$aCurrencies = array($conf->currency);	// Default currency always first position
+
+if (! empty($conf->multicurrency->enabled) && ! empty($conf->global->MULTICURRENCY_USE_LIMIT_BY_CURRENCY))
+{
+	require_once DOL_DOCUMENT_ROOT.'/core/lib/multicurrency.lib.php';
+
+	$sql = 'SELECT rowid, code FROM '.MAIN_DB_PREFIX.'multicurrency';
+	$sql.= ' WHERE entity = '.$conf->entity;
+	$sql.= ' AND code != "'.$conf->currency.'"';	// Default currency always first position
+	$resql = $db->query($sql);
+	if ($resql)
+	{
+		while ($obj = $db->fetch_object($resql))
+		{
+			$aCurrencies[] = $obj->code;
+		}
+	}
+
+	if (! empty($aCurrencies) && count($aCurrencies) > 1)
+	{
+		$head = multicurrencyLimitPrepareHead($aCurrencies);
+		dol_fiche_head($head, $currencycode, '', -1, "multicurrency");
+	}
+}
 
 print '<span class="opacitymedium">'.$langs->trans("LimitsDesc")."</span><br>\n";
 print "<br>\n";
@@ -98,29 +128,29 @@ if ($action == 'edit')
     print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
     print '<input type="hidden" name="token" value="'.newToken().'">';
     print '<input type="hidden" name="action" value="update">';
+    if (! empty($conf->multicurrency->enabled) && ! empty($conf->global->MULTICURRENCY_USE_LIMIT_BY_CURRENCY)) {
+    	print '<input type="hidden" name="currencycode" value="'.$currencycode.'">';
+    }
 
     clearstatcache();
 
     print '<table class="noborder centpercent">';
     print '<tr class="liste_titre"><td>'.$langs->trans("Parameters").'</td><td>'.$langs->trans("Value").'</td></tr>';
 
-
     print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_MAX_DECIMALS_UNIT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td><input class="flat" name="MAIN_MAX_DECIMALS_UNIT" size="3" value="' . $conf->global->MAIN_MAX_DECIMALS_UNIT . '"></td></tr>';
+    print '</td><td><input class="flat" name="'.$mainmaxdecimalsunit.'" size="3" value="'.(isset($conf->global->$mainmaxdecimalsunit)?$conf->global->$mainmaxdecimalsunit:$conf->global->MAIN_MAX_DECIMALS_UNIT).'"></td></tr>';
 
-
-    print '<tr><td>';
+    print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_MAX_DECIMALS_TOT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td><input class="flat" name="MAIN_MAX_DECIMALS_TOT" size="3" value="' . $conf->global->MAIN_MAX_DECIMALS_TOT . '"></td></tr>';
-
-
-    print '<tr><td>'.$langs->trans("MAIN_MAX_DECIMALS_SHOWN").'</td><td><input class="flat" name="MAIN_MAX_DECIMALS_SHOWN" size="3" value="' . $conf->global->MAIN_MAX_DECIMALS_SHOWN . '"></td></tr>';
+    print '</td><td><input class="flat" name="'.$mainmaxdecimalstot.'" size="3" value="'.(isset($conf->global->$mainmaxdecimalstot)?$conf->global->$mainmaxdecimalstot:$conf->global->MAIN_MAX_DECIMALS_TOT).'"></td></tr>';
 
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAX_DECIMALS_SHOWN").'</td>';
+    print '<td><input class="flat" name="'.$mainmaxdecimalsshown.'" size="3" value="'.(isset($conf->global->$mainmaxdecimalsshown)?$conf->global->$mainmaxdecimalsshown:$conf->global->MAIN_MAX_DECIMALS_SHOWN).'"></td></tr>';
 
-    print '<tr><td>';
+    print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_ROUNDING_RULE_TOT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td><input class="flat" name="MAIN_ROUNDING_RULE_TOT" size="3" value="' . $conf->global->MAIN_ROUNDING_RULE_TOT . '"></td></tr>';
+    print '</td><td><input class="flat" name="'.$mainroundingruletot.'" size="3" value="'.(isset($conf->global->$mainroundingruletot)?$conf->global->$mainroundingruletot:$conf->global->MAIN_ROUNDING_RULE_TOT).'"></td></tr>';
 
     print '</table>';
 
@@ -138,31 +168,35 @@ else
     print '<table class="noborder centpercent">';
     print '<tr class="liste_titre"><td>'.$langs->trans("Parameter").'</td><td>'.$langs->trans("Value").'</td></tr>';
 
-
     print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_MAX_DECIMALS_UNIT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td class="right">'.$conf->global->MAIN_MAX_DECIMALS_UNIT.'</td></tr>';
+    print '</td><td align="right">'.(isset($conf->global->$mainmaxdecimalsunit)?$conf->global->$mainmaxdecimalsunit:$conf->global->MAIN_MAX_DECIMALS_UNIT).'</td></tr>';
 
-
-    print '<tr><td>';
+    print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_MAX_DECIMALS_TOT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td class="right">'.$conf->global->MAIN_MAX_DECIMALS_TOT.'</td></tr>';
+    print '</td><td align="right">'.(isset($conf->global->$mainmaxdecimalstot)?$conf->global->$mainmaxdecimalstot:$conf->global->MAIN_MAX_DECIMALS_TOT).'</td></tr>';
 
+    print '<tr class="oddeven"><td>'.$langs->trans("MAIN_MAX_DECIMALS_SHOWN").'</td>';
+    print '<td align="right">'.(isset($conf->global->$mainmaxdecimalsshown)?$conf->global->$mainmaxdecimalsshown:$conf->global->MAIN_MAX_DECIMALS_SHOWN).'</td></tr>';
 
-    print '<tr><td>'.$langs->trans("MAIN_MAX_DECIMALS_SHOWN").'</td><td class="right">'.$conf->global->MAIN_MAX_DECIMALS_SHOWN.'</td></tr>';
-
-
-    print '<tr><td>';
+    print '<tr class="oddeven"><td>';
     print $form->textwithpicto($langs->trans("MAIN_ROUNDING_RULE_TOT"), $langs->trans("ParameterActiveForNextInputOnly"));
-    print '</td><td class="right">'.$conf->global->MAIN_ROUNDING_RULE_TOT.'</td></tr>';
+    print '</td><td align="right">'.(isset($conf->global->$mainroundingruletot)?$conf->global->$mainroundingruletot:$conf->global->MAIN_ROUNDING_RULE_TOT).'</td></tr>';
 
     print '</table>';
 
-    print '<div class="tabsAction tabsActionNoBottom">';
-    print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit">'.$langs->trans("Modify").'</a>';
+    print '<div class="tabsAction">';
+    print '<a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit'.(! empty($currencycode)?'&currencycode='.$currencycode:'').'">'.$langs->trans("Modify").'</a>';
     print '</div>';
 }
 
+if (! empty($conf->multicurrency->enabled) && ! empty($conf->global->MULTICURRENCY_USE_LIMIT_BY_CURRENCY))
+{
+	if (! empty($aCurrencies) && count($aCurrencies) > 1)
+	{
+		dol_fiche_end();
+	}
+}
 
 if (empty($mysoc->country_code))
 {
@@ -197,7 +231,6 @@ else
 	print " - ".$langs->trans("VAT").": ".$vat.'%';
 	print " &nbsp; -> &nbsp; ".$langs->trans("TotalPriceAfterRounding").": ".$tmparray[0].' / '.$tmparray[1].' / '.$tmparray[2]."<br>\n";
 
-
 	// Add vat rates examples specific to country
 	$vat_rates=array();
 

+ 1 - 1
htdocs/admin/mails.php

@@ -638,7 +638,7 @@ else
 	$liste['user'] = $langs->trans('UserEmail');
 	$liste['company'] = $langs->trans('CompanyEmail').' ('.(empty($conf->global->MAIN_INFO_SOCIETE_MAIL) ? $langs->trans("NotDefined") : $conf->global->MAIN_INFO_SOCIETE_MAIL).')';
 	$sql = 'SELECT rowid, label, email FROM '.MAIN_DB_PREFIX.'c_email_senderprofile';
-	$sql.= ' WHERE active = 1 AND (private = 0 OR private = '.$user->id.')';
+	$sql .= ' WHERE active = 1 AND (private = 0 OR private = '.$user->id.')';
 	$resql = $db->query($sql);
 	if ($resql)
 	{

+ 7 - 7
htdocs/admin/mails_senderprofile_list.php

@@ -108,9 +108,9 @@ if (is_array($extrafields->attributes[$object->table_element]['label']) && count
 		if (!empty($extrafields->attributes[$object->table_element]['list'][$key])) {
 			$arrayfields["ef.".$key] = array(
 				'label'=>$extrafields->attributes[$object->table_element]['label'][$key],
-				'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key]<0)?0:1),
+				'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1),
 				'position'=>$extrafields->attributes[$object->table_element]['pos'][$key],
-				'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key])!=3 && $extrafields->attributes[$object->table_element]['perms'][$key])
+				'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key])
 			);
 		}
 	}
@@ -451,7 +451,7 @@ foreach ($object->fields as $key => $val)
 		elseif (strpos($val['type'], 'integer:') === 0) {
 			print $object->showInputField($val, $key, $search[$key], '', '', 'search_', 'maxwidth150', 1);
 		}
-		elseif (! preg_match('/^(date|timestamp)/', $val['type'])) print '<input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'">';
+		elseif (!preg_match('/^(date|timestamp)/', $val['type'])) print '<input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'">';
 		print '</td>';
 	}
 }
@@ -555,10 +555,10 @@ while ($i < ($limit ? min($num, $limit) : $num))
 	// Action column
 	print '<td class="nowrap center">';
 	$url = $_SERVER["PHP_SELF"].'?action=list&id='.$obj->rowid;
-	if ($limit) $url.='&limit='.urlencode($limit);
-	if ($page) $url.='&page='.urlencode($page);
-	if ($sortfield) $url.='&sortfield='.urlencode($sortfield);
-	if ($sortorder) $url.='&page='.urlencode($sortorder);
+	if ($limit) $url .= '&limit='.urlencode($limit);
+	if ($page) $url .= '&page='.urlencode($page);
+	if ($sortfield) $url .= '&sortfield='.urlencode($sortfield);
+	if ($sortorder) $url .= '&page='.urlencode($sortorder);
 	//print '<a class="reposition" href="'.$url.'&action=edit">'.img_edit().'</a>';
 	//print ' &nbsp; ';
 	print '<a href="'.$url.'&action=delete">'.img_delete().'</a>  &nbsp; ';

+ 66 - 64
htdocs/admin/mrp.php

@@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/mrp/lib/mrp.lib.php';
 // Load translation files required by the page
 $langs->loadLangs(array('admin', 'errors', 'mrp', 'other'));
 
-if (! $user->admin) accessforbidden();
+if (!$user->admin) accessforbidden();
 
 $action = GETPOST('action', 'alpha');
 $value = GETPOST('value', 'alpha');
@@ -48,14 +48,14 @@ include DOL_DOCUMENT_ROOT.'/core/actions_setmoduleoptions.inc.php';
 
 if ($action == 'updateMask')
 {
-	$maskconstmrp=GETPOST('maskconstMo', 'alpha');
-	$maskmrp=GETPOST('maskMo', 'alpha');
+	$maskconstmrp = GETPOST('maskconstMo', 'alpha');
+	$maskmrp = GETPOST('maskMo', 'alpha');
 
 	if ($maskconstmrp) $res = dolibarr_set_const($db, $maskconstmrp, $maskmrp, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -67,20 +67,20 @@ if ($action == 'updateMask')
 
 elseif ($action == 'specimen')
 {
-	$modele=GETPOST('module', 'alpha');
+	$modele = GETPOST('module', 'alpha');
 
 	$mo = new MO($db);
 	$mrp->initAsSpecimen();
 
 	// Search template files
-	$file=''; $classname=''; $filefound=0;
-	$dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
-	foreach($dirmodels as $reldir)
+	$file = ''; $classname = ''; $filefound = 0;
+	$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
+	foreach ($dirmodels as $reldir)
 	{
-	    $file=dol_buildpath($reldir."core/modules/mrp/doc/pdf_".$modele.".modules.php", 0);
+	    $file = dol_buildpath($reldir."core/modules/mrp/doc/pdf_".$modele.".modules.php", 0);
 		if (file_exists($file))
 		{
-			$filefound=1;
+			$filefound = 1;
 			$classname = "pdf_".$modele;
 			break;
 		}
@@ -156,9 +156,9 @@ elseif ($action == 'set_MRP_MO_DRAFT_WATERMARK')
 	$draft = GETPOST("MRP_MO_DRAFT_WATERMARK");
 	$res = dolibarr_set_const($db, "MRP_MO_DRAFT_WATERMARK", trim($draft), 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -170,13 +170,13 @@ elseif ($action == 'set_MRP_MO_DRAFT_WATERMARK')
 
 elseif ($action == 'set_MRP_MO_FREE_TEXT')
 {
-	$freetext = GETPOST("MRP_MO_FREE_TEXT", 'none');	// No alpha here, we want exact string
+	$freetext = GETPOST("MRP_MO_FREE_TEXT", 'none'); // No alpha here, we want exact string
 
 	$res = dolibarr_set_const($db, "MRP_MO_FREE_TEXT", $freetext, 'chaine', 0, '', $conf->entity);
 
-	if (! $res > 0) $error++;
+	if (!$res > 0) $error++;
 
- 	if (! $error)
+ 	if (!$error)
     {
         setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
     }
@@ -191,13 +191,13 @@ elseif ($action == 'set_MRP_MO_FREE_TEXT')
  * View
  */
 
-$form=new Form($db);
+$form = new Form($db);
 
-$dirmodels=array_merge(array('/'), (array) $conf->modules_parts['models']);
+$dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
 
 llxHeader("", $langs->trans("MrpSetupPage"));
 
-$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
+$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
 print load_fiche_titre($langs->trans("MrpSetupPage"), $linkback, 'title_setup');
 
 $head = mrpAdminPrepareHead();
@@ -230,18 +230,18 @@ foreach ($dirmodels as $reldir)
 		$handle = opendir($dir);
 		if (is_resource($handle))
 		{
-			while (($file = readdir($handle))!==false)
+			while (($file = readdir($handle)) !== false)
 			{
-			    if (substr($file, 0, 7) == 'mod_mo_' && substr($file, dol_strlen($file)-3, 3) == 'php')
+			    if (substr($file, 0, 7) == 'mod_mo_' && substr($file, dol_strlen($file) - 3, 3) == 'php')
 				{
-					$file = substr($file, 0, dol_strlen($file)-4);
+					$file = substr($file, 0, dol_strlen($file) - 4);
 
 					require_once $dir.$file.'.php';
 
 					$module = new $file($db);
 
 					// Show modules according to features level
-					if ($module->version == 'development'  && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
+					if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) continue;
 					if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) continue;
 
 					if ($module->isEnabled())
@@ -252,9 +252,9 @@ foreach ($dirmodels as $reldir)
 
                         // Show example of numbering model
                         print '<td class="nowrap">';
-                        $tmp=$module->getExample();
+                        $tmp = $module->getExample();
                         if (preg_match('/^Error/', $tmp)) print '<div class="error">'.$langs->trans($tmp).'</div>';
-                        elseif ($tmp=='NotConfigured') print $langs->trans($tmp);
+                        elseif ($tmp == 'NotConfigured') print $langs->trans($tmp);
                         else print $tmp;
                         print '</td>'."\n";
 
@@ -271,22 +271,22 @@ foreach ($dirmodels as $reldir)
 						}
 						print '</td>';
 
-						$mrp=new MO($db);
+						$mrp = new MO($db);
 						$mrp->initAsSpecimen();
 
 						// Info
-						$htmltooltip='';
-						$htmltooltip.=''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
-						$mrp->type=0;
-						$nextval=$module->getNextValue($mysoc, $mrp);
+						$htmltooltip = '';
+						$htmltooltip .= ''.$langs->trans("Version").': <b>'.$module->getVersion().'</b><br>';
+						$mrp->type = 0;
+						$nextval = $module->getNextValue($mysoc, $mrp);
                         if ("$nextval" != $langs->trans("NotAvailable")) {  // Keep " on nextval
-                            $htmltooltip.=''.$langs->trans("NextValue").': ';
+                            $htmltooltip .= ''.$langs->trans("NextValue").': ';
                             if ($nextval) {
-                                if (preg_match('/^Error/', $nextval) || $nextval=='NotConfigured')
+                                if (preg_match('/^Error/', $nextval) || $nextval == 'NotConfigured')
                                     $nextval = $langs->trans($nextval);
-                                $htmltooltip.=$nextval.'<br>';
+                                $htmltooltip .= $nextval.'<br>';
                             } else {
-                                $htmltooltip.=$langs->trans($module->error).'<br>';
+                                $htmltooltip .= $langs->trans($module->error).'<br>';
                             }
                         }
 
@@ -314,14 +314,14 @@ print load_fiche_titre($langs->trans("MOsModelModule"), '', '');
 // Load array def with activated templates
 $def = array();
 $sql = "SELECT nom";
-$sql.= " FROM ".MAIN_DB_PREFIX."document_model";
-$sql.= " WHERE type = '".$type."'";
-$sql.= " AND entity = ".$conf->entity;
-$resql=$db->query($sql);
+$sql .= " FROM ".MAIN_DB_PREFIX."document_model";
+$sql .= " WHERE type = '".$type."'";
+$sql .= " AND entity = ".$conf->entity;
+$resql = $db->query($sql);
 if ($resql)
 {
 	$i = 0;
-	$num_rows=$db->num_rows($resql);
+	$num_rows = $db->num_rows($resql);
 	while ($i < $num_rows)
 	{
 		$array = $db->fetch_array($resql);
@@ -349,43 +349,43 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-    foreach (array('','/doc') as $valdir)
+    foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/mrp".$valdir);
+    	$realpath = $reldir."core/modules/mrp".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
-            $handle=opendir($dir);
+            $handle = opendir($dir);
             if (is_resource($handle))
             {
-                while (($file = readdir($handle))!==false)
+                while (($file = readdir($handle)) !== false)
                 {
-                    $filelist[]=$file;
+                    $filelist[] = $file;
                 }
                 closedir($handle);
                 arsort($filelist);
 
-                foreach($filelist as $file)
+                foreach ($filelist as $file)
                 {
                     if (preg_match('/\.modules\.php$/i', $file) && preg_match('/^(pdf_|doc_)/', $file))
                     {
                     	if (file_exists($dir.'/'.$file))
                     	{
-                    		$name = substr($file, 4, dol_strlen($file) -16);
-	                        $classname = substr($file, 0, dol_strlen($file) -12);
+                    		$name = substr($file, 4, dol_strlen($file) - 16);
+	                        $classname = substr($file, 0, dol_strlen($file) - 12);
 
 	                        require_once $dir.'/'.$file;
 	                        $module = new $classname($db);
 
-	                        $modulequalified=1;
-	                        if ($module->version == 'development'  && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified=0;
-	                        if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified=0;
+	                        $modulequalified = 1;
+	                        if ($module->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2) $modulequalified = 0;
+	                        if ($module->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1) $modulequalified = 0;
 
 	                        if ($modulequalified)
 	                        {
-	                            $var = !$var;
 	                            print '<tr class="oddeven"><td width="100">';
-	                            print (empty($module->name)?$name:$module->name);
+	                            print (empty($module->name) ? $name : $module->name);
 	                            print "</td><td>\n";
 	                            if (method_exists($module, 'info')) print $module->info($langs);
 	                            else print $module->description;
@@ -420,15 +420,17 @@ foreach ($dirmodels as $reldir)
 	                            print '</td>';
 
 	                            // Info
-		    					$htmltooltip =    ''.$langs->trans("Name").': '.$module->name;
-					    		$htmltooltip.='<br>'.$langs->trans("Type").': '.($module->type?$module->type:$langs->trans("Unknown"));
+		    					$htmltooltip = ''.$langs->trans("Name").': '.$module->name;
+					    		$htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
 			                    if ($module->type == 'pdf')
 			                    {
-			                        $htmltooltip.='<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip.='<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
-					    		$htmltooltip.='<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
-					    		$htmltooltip.='<br>'.$langs->trans("WatermarkOnDraftMOs").': '.yn($module->option_draft_watermark, 1, 1);
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+					    		$htmltooltip .= '<br>'.$langs->trans("MultiLanguage").': '.yn($module->option_multilang, 1, 1);
+					    		$htmltooltip .= '<br>'.$langs->trans("WatermarkOnDraftMOs").': '.yn($module->option_draft_watermark, 1, 1);
 
 
 	                            print '<td class="center">';
@@ -472,18 +474,18 @@ print '<td class="center" width="60">'.$langs->trans("Value").'</td>';
 print "<td>&nbsp;</td>\n";
 print "</tr>\n";
 
-$substitutionarray=pdf_getSubstitutionArray($langs, null, null, 2);
-$substitutionarray['__(AnyTranslationKey)__']=$langs->trans("Translation");
+$substitutionarray = pdf_getSubstitutionArray($langs, null, null, 2);
+$substitutionarray['__(AnyTranslationKey)__'] = $langs->trans("Translation");
 $htmltext = '<i>'.$langs->trans("AvailableVariables").':<br>';
-foreach($substitutionarray as $key => $val)	$htmltext.=$key.'<br>';
-$htmltext.='</i>';
+foreach ($substitutionarray as $key => $val)	$htmltext .= $key.'<br>';
+$htmltext .= '</i>';
 
 print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
 print '<input type="hidden" name="token" value="'.newToken().'">';
 print '<input type="hidden" name="action" value="set_MRP_MO_FREE_TEXT">';
 print '<tr class="oddeven"><td colspan="2">';
 print $form->textwithpicto($langs->trans("FreeLegalTextOnMOs"), $langs->trans("AddCRIfTooLong").'<br><br>'.$htmltext, 1, 'help', '', 0, 2, 'freetexttooltip').'<br>';
-$variablename='MRP_MO_FREE_TEXT';
+$variablename = 'MRP_MO_FREE_TEXT';
 if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))
 {
     print '<textarea name="'.$variablename.'" class="flat" cols="120">'.$conf->global->$variablename.'</textarea>';
@@ -491,7 +493,7 @@ if (empty($conf->global->PDF_ALLOW_HTML_FOR_FREE_TEXT))
 else
 {
     include_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
-    $doleditor=new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes');
+    $doleditor = new DolEditor($variablename, $conf->global->$variablename, '', 80, 'dolibarr_notes');
     print $doleditor->Create();
 }
 print '</td><td class="right">';

+ 1 - 0
htdocs/admin/notification.php

@@ -53,6 +53,7 @@ if ($action == 'setvalue' && $user->admin)
     if (!$error && is_array($_POST))
     {
     	//var_dump($_POST);
+    	$reg = array();
 	    foreach ($_POST as $key => $val)
 	    {
 	    	if (!preg_match('/^NOTIF_(.*)_key$/', $key, $reg)) continue;

+ 9 - 9
htdocs/admin/order_extrafields.php

@@ -41,13 +41,13 @@ $extrafields = new ExtraFields($db);
 $form = new Form($db);
 
 // List of supported format
-$tmptype2label=ExtraFields::$type2label;
-$type2label=array('');
-foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->transnoentitiesnoconv($val);
+$tmptype2label = ExtraFields::$type2label;
+$type2label = array('');
+foreach ($tmptype2label as $key => $val) $type2label[$key] = $langs->transnoentitiesnoconv($val);
 
-$action=GETPOST('action', 'alpha');
-$attrname=GETPOST('attrname', 'alpha');
-$elementtype='commande'; //Must be the $table_element of the class that manage extrafield
+$action = GETPOST('action', 'alpha');
+$attrname = GETPOST('attrname', 'alpha');
+$elementtype = 'commande'; //Must be the $table_element of the class that manage extrafield
 
 if (!$user->admin) accessforbidden();
 
@@ -64,11 +64,11 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
-$textobject=$langs->transnoentitiesnoconv("Orders");
+$textobject = $langs->transnoentitiesnoconv("Orders");
 
 llxHeader('', $langs->trans("OrdersSetup"));
 
-$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
+$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
 print load_fiche_titre($langs->trans("OrdersSetup"), $linkback, 'title_setup');
 
 $head = order_admin_prepare_head();
@@ -108,7 +108,7 @@ if ($action == 'create')
 /* Edition of an optional field                                               */
 /*                                                                            */
 /* ************************************************************************** */
-if ($action == 'edit' && ! empty($attrname))
+if ($action == 'edit' && !empty($attrname))
 {
     print "<br>";
     print load_fiche_titre($langs->trans("FieldEdition", $attrname));

+ 9 - 9
htdocs/admin/orderdet_extrafields.php

@@ -42,13 +42,13 @@ $extrafields = new ExtraFields($db);
 $form = new Form($db);
 
 // List of supported format
-$tmptype2label=ExtraFields::$type2label;
-$type2label=array('');
-foreach ($tmptype2label as $key => $val) $type2label[$key]=$langs->transnoentitiesnoconv($val);
+$tmptype2label = ExtraFields::$type2label;
+$type2label = array('');
+foreach ($tmptype2label as $key => $val) $type2label[$key] = $langs->transnoentitiesnoconv($val);
 
-$action=GETPOST('action', 'alpha');
-$attrname=GETPOST('attrname', 'alpha');
-$elementtype='commandedet'; //Must be the $table_element of the class that manage extrafield
+$action = GETPOST('action', 'alpha');
+$attrname = GETPOST('attrname', 'alpha');
+$elementtype = 'commandedet'; //Must be the $table_element of the class that manage extrafield
 
 if (!$user->admin) accessforbidden();
 
@@ -65,11 +65,11 @@ require DOL_DOCUMENT_ROOT.'/core/actions_extrafields.inc.php';
  * View
  */
 
-$textobject=$langs->transnoentitiesnoconv("Orders");
+$textobject = $langs->transnoentitiesnoconv("Orders");
 
 llxHeader('', $langs->trans("OrdersSetup"));
 
-$linkback='<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
+$linkback = '<a href="'.DOL_URL_ROOT.'/admin/modules.php?restore_lastsearch_values=1">'.$langs->trans("BackToModuleList").'</a>';
 print load_fiche_titre($langs->trans("OrdersSetup"), $linkback, 'title_setup');
 
 $head = order_admin_prepare_head();
@@ -109,7 +109,7 @@ if ($action == 'create')
 /* Edition of an optional field                                               */
 /*                                                                            */
 /* ************************************************************************** */
-if ($action == 'edit' && ! empty($attrname))
+if ($action == 'edit' && !empty($attrname))
 {
     print "<br>";
     print load_fiche_titre($langs->trans("FieldEdition", $attrname));

+ 76 - 37
htdocs/admin/perms.php

@@ -35,6 +35,8 @@ $action = GETPOST('action', 'aZ09');
 
 if (!$user->admin) accessforbidden();
 
+$entity=$conf->entity;
+
 
 /*
  * Actions
@@ -70,14 +72,12 @@ print '<span class="opacitymedium">'.$langs->trans("DefaultRightsDesc")." ".$lan
 
 $db->begin();
 
-// Charge les modules soumis a permissions
+// Search all modules with permission and reload permissions def.
 $modules = array();
 $modulesdir = dolGetModulesDirs();
 
 foreach ($modulesdir as $dir)
 {
-	// Load modules attributes in arrays (name, numero, orders) from dir directory
-	//print $dir."\n<br>";
 	$handle = @opendir(dol_osencode($dir));
 	if (is_resource($handle))
 	{
@@ -102,7 +102,7 @@ foreach ($modulesdir as $dir)
 					// Load all permissions
 					if ($objMod->rights_class)
 					{
-						$ret = $objMod->insert_permissions(0);
+						$ret = $objMod->insert_permissions(0, $entity);
 						$modules[$objMod->rights_class] = $objMod;
 						//print "modules[".$objMod->rights_class."]=$objMod;";
 					}
@@ -122,35 +122,58 @@ dol_fiche_head($head, 'default', $langs->trans("Security"), -1);
 // Show warning about external users
 print info_admin(showModulesExludedForExternal($modules)).'<br>'."\n";
 
+print "\n";
 print '<div class="div-table-responsive-no-min">';
 print '<table class="noborder centpercent">';
 
-// Show permissions lines
-$sql = "SELECT r.id, r.libelle, r.module, r.perms, r.subperms, r.bydefault";
+print '<tr class="liste_titre">';
+print '<td>'.$langs->trans("Module").'</td>';
+print '<td class="center">&nbsp;</td>';
+print '<td class="center">'.$langs->trans("Default").'</td>';
+print '<td>'.$langs->trans("Permissions").'</td>';
+print '</tr>'."\n";
+
+//print "xx".$conf->global->MAIN_USE_ADVANCED_PERMS;
+$sql = "SELECT r.id, r.libelle as label, r.module, r.module_position, r.perms, r.subperms, r.bydefault";
 $sql .= " FROM ".MAIN_DB_PREFIX."rights_def as r";
 $sql .= " WHERE r.libelle NOT LIKE 'tou%'"; // On ignore droits "tous"
-$sql .= " AND entity = ".$conf->entity;
+$sql .= " AND r.entity = ".$entity;
 if (empty($conf->global->MAIN_USE_ADVANCED_PERMS)) $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
-$sql .= " ORDER BY r.module, r.id";
+$sql .= " ORDER BY r.family_position, r.module_position, r.module, r.id";
 
 $result = $db->query($sql);
 if ($result)
 {
     $num = $db->num_rows($result);
     $i = 0;
-    $oldmod = "";
+    $oldmod = '';
 
     while ($i < $num)
     {
         $obj = $db->fetch_object($result);
 
-        // Si la ligne correspond a un module qui n'existe plus (absent de includes/module), on l'ignore
-        if (!$modules[$obj->module])
+        // If line is for a module that doe snot existe anymore (absent of includes/module), we ignore it
+        if (empty($modules[$obj->module]))
         {
             $i++;
             continue;
         }
 
+        // Save field module_position in database if value is still zero
+        if (empty($obj->module_position))
+        {
+        	if (is_object($modules[$obj->module]) && ($modules[$obj->module]->module_position > 0))
+        	{
+        		// TODO Define familyposition
+        		$family = $modules[$obj->module]->family_position;
+        		$familyposition = 0;
+        		$sqlupdate = 'UPDATE '.MAIN_DB_PREFIX."rights_def SET module_position = ".$modules[$obj->module]->module_position.",";
+        		$sqlupdate.= " family_position = ".$familyposition;
+        		$sqlupdate.= " WHERE module_position = 0 AND module = '".$db->escape($obj->module)."'";
+        		$db->query($sqlupdate);
+        	}
+        }
+
         // Check if permission we found is inside a module definition. If not, we discard it.
         $found = false;
         foreach ($modules[$obj->module]->rights as $key => $val)
@@ -169,49 +192,65 @@ if ($result)
 		}
 
         // Break found, it's a new module to catch
-        if ($oldmod <> $obj->module)
+		if (isset($obj->module) && ($oldmod <> $obj->module))
         {
         	$oldmod = $obj->module;
+
+        	// Break detected, we get objMod
             $objMod = $modules[$obj->module];
             $picto = ($objMod->picto ? $objMod->picto : 'generic');
 
-            print '<tr class="liste_titre">';
-            print '<td>'.$langs->trans("Module").'</td>';
-            print '<td>'.$langs->trans("Permission").'</td>';
-            print '<td class="center">'.$langs->trans("Default").'</td>';
-            print '<td align="center">&nbsp;</td>';
-            print "</tr>\n";
+            // Show break line
+            print '<tr class="oddeven trforbreak">';
+            print '<td class="maxwidthonsmartphone tdoverflowonsmartphone">';
+            print img_object('', $picto, 'class="pictoobjectwidth"').' '.$objMod->getName();
+            print '<a name="'.$objMod->getName().'"></a>';
+            print '</td>';
+           	print '<td>&nbsp;</td>';
+            print '<td>&nbsp;</td>';
+            print '<td>&nbsp;</td>';
+            print '</tr>'."\n";
         }
 
+        $perm_libelle = ($conf->global->MAIN_USE_ADVANCED_PERMS && ($langs->trans("PermissionAdvanced".$obj->id) != ("PermissionAdvanced".$obj->id)) ? $langs->trans("PermissionAdvanced".$obj->id) : (($langs->trans("Permission".$obj->id) != ("Permission".$obj->id)) ? $langs->trans("Permission".$obj->id) : $obj->label));
 
         print '<tr class="oddeven">';
-        print '<td>';
-        print img_object('', $picto, 'class="pictoobjectwidth"').' '.$objMod->getName();
-        print '<a name="'.$objMod->getName().'">&nbsp;</a>';
+
+        // Picto and label of module
+        print '<td class="maxwidthonsmartphone tdoverflowonsmartphone">';
+		//print img_object('', $picto, 'class="pictoobjectwidth"').' '.$objMod->getName();
+        //print '<a name="'.$objMod->getName().'">&nbsp;</a>';
 		print '</td>';
 
-        $perm_libelle = ($conf->global->MAIN_USE_ADVANCED_PERMS && ($langs->trans("PermissionAdvanced".$obj->id) != ("PermissionAdvanced".$obj->id)) ? $langs->trans("PermissionAdvanced".$obj->id) : (($langs->trans("Permission".$obj->id) != ("Permission".$obj->id)) ? $langs->trans("Permission".$obj->id) : $obj->libelle));
+		// Tick
+		if ($obj->bydefault == 1)
+		{
+			print '<td>';
+			print '<a class="reposition" href="perms.php?pid='.$obj->id.'&amp;action=remove">'.img_edit_remove().'</a>';
+			print '</td>';
+			print '<td class="center">';
+			print img_picto($langs->trans("Active"), 'tick');
+			print '</td>';
+		}
+		else
+		{
+			print '<td>';
+			print '<a class="reposition" href="perms.php?pid='.$obj->id.'&amp;action=add">'.img_edit_add().'</a>';
+			print '</td>';
+			print '<td class="center">';
+			print '&nbsp;';
+			print '</td>';
+		}
+
+		// Permission and tick
         print '<td>'.$perm_libelle.'</td>';
 
-        print '<td class="center">';
-        if ($obj->bydefault == 1)
-        {
-            print img_picto($langs->trans("Active"), 'tick');
-            print '</td><td>';
-            print '<a class="reposition" href="perms.php?pid='.$obj->id.'&amp;action=remove">'.img_edit_remove().'</a>';
-        }
-        else
-        {
-            print '&nbsp;';
-            print '</td><td>';
-            print '<a class="reposition" href="perms.php?pid='.$obj->id.'&amp;action=add">'.img_edit_add().'</a>';
-        }
+        print '</tr>'."\n";
 
-        print '</td></tr>';
         $i++;
     }
 }
-
+else dol_print_error($db);
 print '</table>';
 print '</div>';
 

+ 7 - 4
htdocs/admin/propal.php

@@ -271,7 +271,7 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/propale/");
+	$dir = dol_buildpath($reldir."core/modules/propale");
 
 	if (is_dir($dir))
 	{
@@ -284,7 +284,7 @@ foreach ($dirmodels as $reldir)
 				{
 					$file = substr($file, 0, dol_strlen($file) - 4);
 
-					require_once $dir.$file.'.php';
+					require_once $dir.'/'.$file.'.php';
 
 					$module = new $file;
 
@@ -399,7 +399,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/propale".$valdir);
+    	$realpath = $reldir."core/modules/propale".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -474,7 +475,9 @@ foreach ($dirmodels as $reldir)
 	                            {
 	                                $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 	                            }
-								$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+	                            $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+	                            $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 								$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
 								$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
 								$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);

+ 7 - 4
htdocs/admin/reception_setup.php

@@ -221,7 +221,7 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/reception/");
+	$dir = dol_buildpath($reldir."core/modules/reception");
 
 	if (is_dir($dir))
 	{
@@ -234,7 +234,7 @@ foreach ($dirmodels as $reldir)
 				{
 					$file = substr($file, 0, dol_strlen($file) - 4);
 
-					require_once $dir.$file.'.php';
+					require_once $dir.'/'.$file.'.php';
 
 					$module = new $file;
 
@@ -353,7 +353,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/reception".$valdir);
+    	$realpath = $reldir."core/modules/reception".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -427,7 +428,9 @@ foreach ($dirmodels as $reldir)
 			                    {
 			                        $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 			                    }
-					    		$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+			                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+			                    $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 					    		$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
 					    		$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
 					    		$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);

+ 7 - 4
htdocs/admin/stock.php

@@ -461,6 +461,7 @@ print "</tr>\n";
 
 print '</table>';
 
+/*
 print '<br>';
 if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
 {
@@ -471,7 +472,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
 	print '</tr>'."\n";
 
 	// Example with a yes / no select
-	/*print '<tr class="oddeven">';
+	print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("INVENTORY_DISABLE_VIRTUAL").'</td>';
 	print '<td class="center">';
 	if ($conf->use_javascript_ajax) {
@@ -481,10 +482,10 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
 		print $form->selectarray("INVENTORY_DISABLE_VIRTUAL", $arrval, $conf->global->INVENTORY_DISABLE_VIRTUAL);
 	}
 	print '</td></tr>';
-	*/
+
 
 	// Example with a yes / no select
-    /*print '<tr class="oddeven">';
+    print '<tr class="oddeven">';
 	print '<td>'.$langs->trans("INVENTORY_USE_MIN_PA_IF_NO_LAST_PA").'</td>';
 	print '<td class="center">';
   	if ($conf->use_javascript_ajax) {
@@ -494,7 +495,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
   		print $form->selectarray("INVENTORY_USE_MIN_PA_IF_NO_LAST_PA", $arrval, $conf->global->INVENTORY_USE_MIN_PA_IF_NO_LAST_PA);
   	}
   	print '</td></tr>';
-  	*/
+
 
   	// Example with a yes / no select
 	print '<tr class="oddeven">';
@@ -507,8 +508,10 @@ if ($conf->global->MAIN_FEATURES_LEVEL >= 2)
     	print $form->selectarray("INVENTORY_USE_INVENTORY_DATE_FOR_DATE_OF_MVT", $arrval, $conf->global->INVENTORY_USE_INVENTORY_DATE_FOR_DATE_OF_MVT);
 	}
 	print '</td></tr>';
+
 	print '</table>';
 }
+*/
 
 /* I keep the option/feature, but hidden to end users for the moment. If feature is used by module, no need to have users see it.
 If not used by a module, I still need to understand in which case user may need this now we can set rule on product page.

+ 8 - 5
htdocs/admin/supplier_invoice.php

@@ -90,7 +90,7 @@ if ($action == 'specimen')  // For invoices
     $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
     foreach ($dirmodels as $reldir)
     {
-    	$file = dol_buildpath($reldir."core/modules/supplier_invoice/pdf/pdf_".$modele.".modules.php", 0);
+    	$file = dol_buildpath($reldir."core/modules/supplier_invoice/doc/pdf_".$modele.".modules.php", 0);
     	if (file_exists($file))
     	{
     		$filefound = 1;
@@ -230,7 +230,7 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_invoice/");
+	$dir = dol_buildpath($reldir."core/modules/supplier_invoice");
 
     if (is_dir($dir))
     {
@@ -243,7 +243,7 @@ foreach ($dirmodels as $reldir)
                 {
                     $file = substr($file, 0, dol_strlen($file) - 4);
 
-                    require_once $dir.$file.'.php';
+                    require_once $dir.'/'.$file.'.php';
 
                     $module = new $file;
 
@@ -360,7 +360,8 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_invoice/pdf/");
+	$realpath = $reldir."core/modules/supplier_invoice/doc";
+	$dir = dol_buildpath($realpath);
 
     if (is_dir($dir))
     {
@@ -385,7 +386,7 @@ foreach ($dirmodels as $reldir)
 	                print (empty($module->name) ? $name : $module->name);
 	                print "</td>\n";
                     print "<td>\n";
-                    require_once $dir.$file;
+                    require_once $dir.'/'.$file;
                     $module = new $classname($db, $specimenthirdparty);
                     if (method_exists($module, 'info')) print $module->info($langs);
 	                else print $module->description;
@@ -434,6 +435,8 @@ foreach ($dirmodels as $reldir)
                     $htmltooltip = ''.$langs->trans("Name").': '.$module->name;
                     $htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
                     $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
                     $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
                     $htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
                     $htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);

+ 6 - 3
htdocs/admin/supplier_order.php

@@ -86,7 +86,7 @@ elseif ($action == 'specimen')  // For orders
     $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
     foreach ($dirmodels as $reldir)
     {
-    	$file = dol_buildpath($reldir."core/modules/supplier_order/pdf/pdf_".$modele.".modules.php", 0);
+    	$file = dol_buildpath($reldir."core/modules/supplier_order/doc/pdf_".$modele.".modules.php", 0);
     	if (file_exists($file))
     	{
     		$filefound = 1;
@@ -388,7 +388,8 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_order/pdf/");
+	$realpath = $reldir."core/modules/supplier_order/doc";
+	$dir = dol_buildpath($realpath);
 
     if (is_dir($dir))
     {
@@ -411,7 +412,7 @@ foreach ($dirmodels as $reldir)
 	                print (empty($module->name) ? $name : $module->name);
 	                print "</td>\n";
                     print "<td>\n";
-                    require_once $dir.$file;
+                    require_once $dir.'/'.$file;
                     $module = new $classname($db, $specimenthirdparty);
                     if (method_exists($module, 'info')) print $module->info($langs);
                     else print $module->description;
@@ -456,6 +457,8 @@ foreach ($dirmodels as $reldir)
                     $htmltooltip = ''.$langs->trans("Name").': '.$module->name;
                     $htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
                     $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
                     $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
                     $htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
                     $htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);

+ 5 - 2
htdocs/admin/supplier_payment.php

@@ -332,7 +332,8 @@ clearstatcache();
 
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_payment/doc/");
+	$realpath = $reldir."core/modules/supplier_payment/doc";
+	$dir = dol_buildpath($realpath);
 
     if (is_dir($dir))
     {
@@ -356,7 +357,7 @@ foreach ($dirmodels as $reldir)
 	                print (empty($module->name) ? $name : $module->name);
 	                print "</td>\n";
                     print "<td>\n";
-                    require_once $dir.$file;
+                    require_once $dir.'/'.$file;
                     $module = new $classname($db, $specimenthirdparty);
                     if (method_exists($module, 'info')) print $module->info($langs);
 	                else print $module->description;
@@ -405,6 +406,8 @@ foreach ($dirmodels as $reldir)
                     $htmltooltip = ''.$langs->trans("Name").': '.$module->name;
                     $htmltooltip .= '<br>'.$langs->trans("Type").': '.($module->type ? $module->type : $langs->trans("Unknown"));
                     $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
+                    $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
                     $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
                     $htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
                     print '<td class="center">';

+ 7 - 4
htdocs/admin/supplier_proposal.php

@@ -239,7 +239,7 @@ print '</tr>'."\n";
 clearstatcache();
 foreach ($dirmodels as $reldir)
 {
-	$dir = dol_buildpath($reldir."core/modules/supplier_proposal/");
+	$dir = dol_buildpath($reldir."core/modules/supplier_proposal");
 
 	if (is_dir($dir))
 	{
@@ -252,7 +252,7 @@ foreach ($dirmodels as $reldir)
 				{
 					$file = substr($file, 0, dol_strlen($file) - 4);
 
-					require_once $dir.$file.'.php';
+					require_once $dir.'/'.$file.'.php';
 
 					$module = new $file;
 
@@ -366,7 +366,8 @@ foreach ($dirmodels as $reldir)
 {
     foreach (array('', '/doc') as $valdir)
     {
-    	$dir = dol_buildpath($reldir."core/modules/supplier_proposal".$valdir);
+    	$realpath = $reldir."core/modules/supplier_proposal".$valdir;
+    	$dir = dol_buildpath($realpath);
 
         if (is_dir($dir))
         {
@@ -440,7 +441,9 @@ foreach ($dirmodels as $reldir)
 	                            {
 	                                $htmltooltip .= '<br>'.$langs->trans("Width").'/'.$langs->trans("Height").': '.$module->page_largeur.'/'.$module->page_hauteur;
 	                            }
-								$htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
+	                            $htmltooltip .= '<br>'.$langs->trans("Path").': '.preg_replace('/^\//', '', $realpath).'/'.$file;
+
+	                            $htmltooltip .= '<br><br><u>'.$langs->trans("FeaturesSupported").':</u>';
 								$htmltooltip .= '<br>'.$langs->trans("Logo").': '.yn($module->option_logo, 1, 1);
 								$htmltooltip .= '<br>'.$langs->trans("PaymentMode").': '.yn($module->option_modereg, 1, 1);
 								$htmltooltip .= '<br>'.$langs->trans("PaymentConditions").': '.yn($module->option_condreg, 1, 1);

+ 110 - 6
htdocs/admin/system/phpinfo.php

@@ -28,6 +28,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 
 $langs->load("admin");
+$langs->load("install");
+$langs->load("errors");
 
 if (! $user->admin)
 	accessforbidden();
@@ -66,20 +68,122 @@ if ($maxphp > 0 && $maxphp2 > 0 && $maxphp > $maxphp2)
 	print '<br>';
 }
 
-
 print '<table class="noborder centpercent">';
 print '<tr class="liste_titre"><td>'.$langs->trans("Parameter").'</td><td>'.$langs->trans("Value").'</td></tr>';
 print "\n";
 
+$ErrorPicturePath = "../../theme/eldy/img/error.png";
+$WarningPicturePath = "../../theme/eldy/img/warning.png";
+$OkayPicturePath = "../../theme/eldy/img/tick.png";
 
-// Get PHP version
-$phpversion=version_php();
-print '<tr class="oddeven"><td  width="220px">'.$langs->trans("Version")."</td><td>".$phpversion."</td></tr>\n";
+print '<tr><td width="220">'.$langs->trans("Version").'</td><td>';
 
-print '</table>';
-print '<br>';
+$arrayphpminversionerror = array(5,5,0);
+$arrayphpminversionwarning = array(5,5,0);
+if (versioncompare(versionphparray(), $arrayphpminversionerror) < 0)
+{
+    print '<img src="'.$ErrorPicturePath.'" alt="Error"> '.$langs->trans("ErrorPHPVersionTooLow", versiontostring($arrayphpminversionerror));
+}
+elseif (versioncompare(versionphparray(), $arrayphpminversionwarning) < 0)
+{
+    print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPVersionTooLow", versiontostring($arrayphpminversionwarning));
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.versiontostring(versionphparray());
+}
+
+print '</td></tr>';
+print '<tr><td>GET and POST support</td><td>';
+
+if (! isset($_GET["testget"]) && ! isset($_POST["testpost"]) && ! isset($_GET["mainmenu"]))
+{
+    print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("PHPSupportPOSTGETKo");
+    print ' (<a href="'.$_SERVER["PHP_SELF"].'?testget=ok">'.$langs->trans("Recheck").'</a>)';
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportPOSTGETOk");
+}
+
+print '</td></tr>';
+print '<tr><td>Sessions support</td><td>';
+
+if (! function_exists("session_id"))
+{
+    print '<img src="'.$ErrorPicturePath.'" alt="Error"> '.$langs->trans("ErrorPHPDoesNotSupportSessions");
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportSessions");
+}
 
+print '</td></tr>';
+print '<tr><td>GD support</td><td>';
 
+if (! function_exists("imagecreate"))
+{
+    print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPDoesNotSupportGD");
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportGD");
+}
+
+print '</td></tr>';
+print '<tr><td>Curl support</td><td>';
+
+if (! function_exists("curl_init"))
+{
+    print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPDoesNotSupportCurl");
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportCurl");
+}
+
+print '</td></tr>';
+print '<tr><td>UTF-8 support</td><td>';
+
+if (! function_exists("utf8_encode"))
+{
+    print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPDoesNotSupportUTF8");
+}
+else
+{
+    print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportUTF8");
+}
+
+print '</td></tr>';
+print '<tr><td>Intl support</td><td>';
+
+if (empty($_SERVER["SERVER_ADMIN"]) || $_SERVER["SERVER_ADMIN"] != 'doliwamp@localhost')
+{
+	if (! function_exists("locale_get_primary_language") || ! function_exists("locale_get_region"))
+	{
+        print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPDoesNotSupportIntl");
+	}
+	else
+	{
+        print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupportIntl");
+	}
+}
+
+print '<tr><td>Zip support</td><td>';
+
+if (!class_exists('ZipArchive'))
+{
+	print '<img src="'.$WarningPicturePath.'" alt="Warning"> '.$langs->trans("ErrorPHPDoesNotSupport", "Zip");
+}
+else
+{
+	print '<img src="'.$OkayPicturePath.'" alt="Ok"> '.$langs->trans("PHPSupport", "Zip");
+}
+
+print '</td></tr>';
+print '</table>';
+
+print '<br>';
 
 // Get php_info array
 $phparray=phpinfo_array();

+ 2 - 2
htdocs/admin/ticket.php

@@ -209,7 +209,7 @@ print "</tr>\n";
 clearstatcache();
 
 foreach ($dirmodels as $reldir) {
-    $dir = dol_buildpath($reldir."core/modules/ticket/");
+    $dir = dol_buildpath($reldir."core/modules/ticket");
 
     if (is_dir($dir)) {
         $handle = opendir($dir);
@@ -219,7 +219,7 @@ foreach ($dirmodels as $reldir) {
                     $file = $reg[1];
                     $classname = substr($file, 4);
 
-                    include_once $dir.$file.'.php';
+                    include_once $dir.'/'.$file.'.php';
 
                     $module = new $file;
 

+ 42 - 42
htdocs/admin/tools/dolibarr_export.php

@@ -29,18 +29,18 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
 
 $langs->load("admin");
 
-$action=GETPOST('action', 'alpha');
+$action = GETPOST('action', 'alpha');
 
 $sortfield = GETPOST('sortfield', 'alpha');
 $sortorder = GETPOST('sortorder', 'alpha');
 $page = GETPOST('page', 'int');
-if (! $sortorder) $sortorder="DESC";
-if (! $sortfield) $sortfield="date";
+if (!$sortorder) $sortorder = "DESC";
+if (!$sortfield) $sortfield = "date";
 if (empty($page) || $page == -1) { $page = 0; }
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $offset = $limit * $page;
 
-if (! $user->admin)
+if (!$user->admin)
 	accessforbidden();
 
 
@@ -52,33 +52,33 @@ if ($action == 'delete')
 {
 	if (preg_match('/^backup\//', GETPOST('urlfile', 'alpha')))
 	{
-		$file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha'));
-		$ret=dol_delete_file($file, 1);
+		$file = $conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha'));
+		$ret = dol_delete_file($file, 1);
 		if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
 		else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
 	}
 	else
 	{
-		$file=$conf->admin->dir_output.'/documents/'.basename(GETPOST('urlfile', 'alpha'));
-		$ret=dol_delete_file($file, 1);
+		$file = $conf->admin->dir_output.'/documents/'.basename(GETPOST('urlfile', 'alpha'));
+		$ret = dol_delete_file($file, 1);
 		if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
 		else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
 	}
-	$action='';
+	$action = '';
 }
 
 /*
  * View
  */
 
-$form=new Form($db);
+$form = new Form($db);
 $formfile = new FormFile($db);
 
-$label=$db::LABEL;
-$type=$db->type;
+$label = $db::LABEL;
+$type = $db->type;
 //var_dump($db);
 
-$help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad';
+$help_url = 'EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad';
 llxHeader('', '', $help_url);
 
 print '<script type="text/javascript">
@@ -141,9 +141,9 @@ print '<br>';
 
 print '<div id="backupdatabaseleft" class="fichehalfleft" >';
 
-print load_fiche_titre($title?$title:$langs->trans("BackupDumpWizard"));
+print load_fiche_titre($title ? $title : $langs->trans("BackupDumpWizard"));
 
-print '<table width="100%" class="'.($useinecm?'nobordernopadding':'liste').' nohover">';
+print '<table width="100%" class="'.($useinecm ? 'nobordernopadding' : 'liste').' nohover">';
 print '<tr class="liste_titre">';
 print '<td class="liste_titre">';
 print $langs->trans("DatabaseName").' : <b>'.$dolibarr_main_db_name.'</b><br>';
@@ -186,11 +186,11 @@ if (in_array($type, array('mysql', 'mysqli'))) {
     print '<div class="formelementrow">'.$langs->trans("FullPathToMysqldumpCommand");
     if (empty($conf->global->SYSTEMTOOLS_MYSQLDUMP))
     {
-        $fullpathofmysqldump=$db->getPathOfDump();
+        $fullpathofmysqldump = $db->getPathOfDump();
     }
     else
     {
-        $fullpathofmysqldump=$conf->global->SYSTEMTOOLS_MYSQLDUMP;
+        $fullpathofmysqldump = $conf->global->SYSTEMTOOLS_MYSQLDUMP;
     }
     print '<br>';
     print '<input type="text" name="mysqldump" style="width: 80%" value="'.$fullpathofmysqldump.'" /></div>';
@@ -203,7 +203,7 @@ if (in_array($type, array('mysql', 'mysqli'))) {
 
     print '</div>';
 
-    if (! empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) {
+    if (!empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) {
         print '<div class="formelementrow">';
         print '<input type="checkbox" name="disable_fk" value="yes" id="checkbox_disable_fk" checked />';
         print '<label for="checkbox_disable_fk">'.$langs->trans("CommandsToDisableForeignKeysForImport").' '.img_info($langs->trans('CommandsToDisableForeignKeysForImportWarning')).'</label>';
@@ -242,7 +242,7 @@ if (in_array($type, array('mysql', 'mysqli'))) {
     print '<input type="checkbox" name="sql_structure" value="structure" id="checkbox_sql_structure" checked />';
     print '<label for="checkbox_sql_structure">'.$langs->trans('ExportStructure').'</label>';
     print '</legend>';
-    print '<input type="checkbox" name="drop"'.(((! isset($_GET["drop"]) && ! isset($_POST["drop"])) || GETPOST('drop'))?' checked':'').' id="checkbox_dump_drop" />';
+    print '<input type="checkbox" name="drop"'.(((!isset($_GET["drop"]) && !isset($_POST["drop"])) || GETPOST('drop')) ? ' checked' : '').' id="checkbox_dump_drop" />';
     print '<label for="checkbox_dump_drop">'.$langs->trans("AddDropTable").'</label>';
     print '<br>';
     print '</fieldset>';
@@ -293,7 +293,7 @@ if (in_array($type, array('mysql', 'mysqli'))) {
     print '<label for="checkbox_use_transaction">'.$langs->trans("UseTransactionnalMode").'</label>';
 
     print '</div>';
-    if (! empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) {
+    if (!empty($conf->global->MYSQL_OLD_OPTION_DISABLE_FK)) {
         print '<div class="formelementrow">';
         print '<input type="checkbox" name="nobin_disable_fk" value="yes" id="checkbox_disable_fk" checked />';
         print '<label for="checkbox_disable_fk">'.$langs->trans("CommandsToDisableForeignKeysForImport").' '.img_info($langs->trans('CommandsToDisableForeignKeysForImportWarning')).'</label>';
@@ -303,7 +303,7 @@ if (in_array($type, array('mysql', 'mysqli'))) {
 
     print '<br>';
     print '<fieldset><legend>'.$langs->trans('ExportStructure').'</legend>';
-    print '<input type="checkbox" name="nobin_drop"'.((! isset($_GET["nobin_drop"]) && ! isset($_POST["nobin_drop"])) || GETPOST('nobin_drop'))?' checked':''.' id="checkbox_dump_drop" />';
+    print '<input type="checkbox" name="nobin_drop"'.((!isset($_GET["nobin_drop"]) && !isset($_POST["nobin_drop"])) || GETPOST('nobin_drop')) ? ' checked' : ''.' id="checkbox_dump_drop" />';
     print '<label for="checkbox_dump_drop">'.$langs->trans("AddDropTable").'</label>';
     print '<br>';
     print '</fieldset>';
@@ -338,11 +338,11 @@ if (in_array($type, array('pgsql'))) {
 
     print '<div class="formelementrow">'.$langs->trans("FullPathToPostgreSQLdumpCommand");
     if (empty($conf->global->SYSTEMTOOLS_POSTGRESQLDUMP)) {
-        $fullpathofpgdump=$db->getPathOfDump();
+        $fullpathofpgdump = $db->getPathOfDump();
     }
     else
     {
-        $fullpathofpgdump=$conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
+        $fullpathofpgdump = $conf->global->SYSTEMTOOLS_POSTGRESQLDUMP;
     }
     print '<br>';
     print '<input type="text" name="postgresqldump" style="width: 80%" value="'.$fullpathofpgdump.'" /></div>';
@@ -391,27 +391,27 @@ print '<legend>'.$langs->trans("Destination").'</legend> -->';
 print '<br>';
 print '<label for="filename_template">'.$langs->trans("FileNameToGenerate").'</label>';
 print '<br>';
-$prefix='dump';
-$ext='.sql';
+$prefix = 'dump';
+$ext = '.sql';
 if (in_array($type, array('mysql', 'mysqli'))) {
-	$prefix='mysqldump';
-	$ext='sql';
+	$prefix = 'mysqldump';
+	$ext = 'sql';
 }
 //if ($label == 'PostgreSQL') {
 //	$prefix='pg_dump';
 //	$ext='dump';
 //}
 if (in_array($type, array('pgsql'))) {
-	$prefix='pg_dump';
-	$ext='sql';
+	$prefix = 'pg_dump';
+	$ext = 'sql';
 }
-$file=$prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
+$file = $prefix.'_'.$dolibarr_main_db_name.'_'.dol_sanitizeFileName(DOL_VERSION).'_'.strftime("%Y%m%d%H%M").'.'.$ext;
 print '<input type="text" name="filename_template" style="width: 90%" id="filename_template" value="'.$file.'" />';
 print '<br>';
 print '<br>';
 
 // Define compressions array
-$compression=array();
+$compression = array();
 if (in_array($type, array('mysql', 'mysqli'))) {
 	$compression['gz'] = array(
 		'function' => 'gzopen',
@@ -488,7 +488,7 @@ print '<input type="hidden" name="page_y" value="'.GETPOST('page_y', 'int').'">'
 print '<br>';
 print '<br>';
 
-if (! empty($_SESSION["commandbackuplastdone"]))
+if (!empty($_SESSION["commandbackuplastdone"]))
 {
     print '<br><b>'.$langs->trans("RunCommandSummary").':</b><br>'."\n";
     print '<textarea rows="'.ROWS_2.'" class="centpercent">'.$_SESSION["commandbackuplastdone"].'</textarea><br>'."\n";
@@ -500,11 +500,11 @@ if (! empty($_SESSION["commandbackuplastdone"]))
     print '<b>'.$langs->trans("BackupResult").':</b> ';
 	print $_SESSION["commandbackupresult"];
 
-	$_SESSION["commandbackuplastdone"]='';
-	$_SESSION["commandbackuptorun"]='';
-	$_SESSION["commandbackupresult"]='';
+	$_SESSION["commandbackuplastdone"] = '';
+	$_SESSION["commandbackuptorun"] = '';
+	$_SESSION["commandbackupresult"] = '';
 }
-if (! empty($_SESSION["commandbackuptorun"]))
+if (!empty($_SESSION["commandbackuptorun"]))
 {
 	print '<br><font class="warning">'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser", $dolibarr_main_db_user, $dolibarr_main_db_user).':</font><br>'."\n";
 	print '<textarea id="commandbackuptoruntext" rows="'.ROWS_2.'" class="centpercent">'.$_SESSION["commandbackuptorun"].'</textarea><br>'."\n";
@@ -513,9 +513,9 @@ if (! empty($_SESSION["commandbackuptorun"]))
 
 	//print $paramclear;
 
-	$_SESSION["commandbackuplastdone"]='';
-	$_SESSION["commandbackuptorun"]='';
-	$_SESSION["commandbackupresult"]='';
+	$_SESSION["commandbackuplastdone"] = '';
+	$_SESSION["commandbackuptorun"] = '';
+	$_SESSION["commandbackupresult"] = '';
 }
 
 print "</div> <!-- end div center button -->\n";
@@ -529,8 +529,8 @@ print "</div> 	<!-- end div fichehalfleft -->\n";
 print '<div id="backupdatabaseright" class="fichehalfright" style="height:480px; overflow: auto;">';
 print '<div class="ficheaddleft">';
 
-$filearray=dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1);
-$result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles"));
+$filearray = dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', $sortfield, (strtolower($sortorder) == 'asc' ?SORT_ASC:SORT_DESC), 1);
+$result = $formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles"));
 print '<br>';
 
 print '</div>';

+ 85 - 85
htdocs/admin/tools/listevents.php

@@ -28,11 +28,11 @@ require '../../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/events.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
 
-if (! $user->admin)
+if (!$user->admin)
 	accessforbidden();
 
-$action=GETPOST('action', 'alpha');
-$confirm=GETPOST('confirm', 'alpha');
+$action = GETPOST('action', 'alpha');
+$confirm = GETPOST('confirm', 'alpha');
 
 // Security check
 if ($user->socid > 0)
@@ -42,10 +42,10 @@ if ($user->socid > 0)
 }
 
 // Load translation files required by the page
-$langs->loadLangs(array("companies","admin","users","other"));
+$langs->loadLangs(array("companies", "admin", "users", "other"));
 
 // Load variable for pagination
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'alpha');
 $sortorder = GETPOST('sortorder', 'alpha');
 $page = GETPOST('page', 'int');
@@ -53,8 +53,8 @@ if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined,
 $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortfield) $sortfield="dateevent";
-if (! $sortorder) $sortorder="DESC";
+if (!$sortfield) $sortfield = "dateevent";
+if (!$sortorder) $sortorder = "DESC";
 
 $search_code = GETPOST("search_code", "alpha");
 $search_ip   = GETPOST("search_ip", "alpha");
@@ -63,24 +63,24 @@ $search_desc = GETPOST("search_desc", "alpha");
 $search_ua   = GETPOST("search_ua", "none");
 $search_prefix_session = GETPOST("search_prefix_session", "none");
 
-if (GETPOST("date_startmonth") == '' || GETPOST("date_startmonth") > 0) $date_start=dol_mktime(0, 0, 0, GETPOST("date_startmonth"), GETPOST("date_startday"), GETPOST("date_startyear"));
-else $date_start=-1;
-if (GETPOST("date_endmonth") == '' || GETPOST("date_endmonth") > 0) $date_end=dol_mktime(23, 59, 59, GETPOST("date_endmonth"), GETPOST("date_endday"), GETPOST("date_endyear"));
-else $date_end=-1;
+if (GETPOST("date_startmonth") == '' || GETPOST("date_startmonth") > 0) $date_start = dol_mktime(0, 0, 0, GETPOST("date_startmonth"), GETPOST("date_startday"), GETPOST("date_startyear"));
+else $date_start = -1;
+if (GETPOST("date_endmonth") == '' || GETPOST("date_endmonth") > 0) $date_end = dol_mktime(23, 59, 59, GETPOST("date_endmonth"), GETPOST("date_endday"), GETPOST("date_endyear"));
+else $date_end = -1;
 
 // checks:if date_start>date_end  then date_end=date_start + 24 hours
-if ($date_start > 0 && $date_end > 0 && $date_start > $date_end) $date_end=$date_start+86400;
+if ($date_start > 0 && $date_end > 0 && $date_start > $date_end) $date_end = $date_start + 86400;
 
 $now = dol_now();
 $nowarray = dol_getdate($now);
 
 if (empty($date_start)) // We define date_start and date_end
 {
-    $date_start=dol_get_first_day($nowarray['year'], $nowarray['mon'], false);
+    $date_start = dol_get_first_day($nowarray['year'], $nowarray['mon'], false);
 }
 if (empty($date_end))
 {
-    $date_end=dol_mktime(23, 59, 59, $nowarray['mon'], $nowarray['mday'], $nowarray['year']);
+    $date_end = dol_mktime(23, 59, 59, $nowarray['mon'], $nowarray['mday'], $nowarray['year']);
 }
 // Set $date_startmonth...
 $tmp = dol_getdate($date_start);
@@ -92,56 +92,56 @@ $date_endday = $tmp['mday'];
 $date_endmonth = $tmp['mon'];
 $date_endyear = $tmp['year'];
 
-$arrayfields=array();
+$arrayfields = array();
 
 
 /*
  * Actions
  */
 
-$now=dol_now();
+$now = dol_now();
 
 // Purge search criteria
 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All tests are required to be compatible with all browsers
 {
-    $date_start=-1;
-    $date_end=-1;
-    $search_code='';
-    $search_ip='';
-    $search_user='';
-    $search_desc='';
-    $search_ua='';
-    $search_prefix_session='';
+    $date_start = -1;
+    $date_end = -1;
+    $search_code = '';
+    $search_ip = '';
+    $search_user = '';
+    $search_desc = '';
+    $search_ua = '';
+    $search_prefix_session = '';
 }
 
 // Purge audit events
 if ($action == 'confirm_purge' && $confirm == 'yes' && $user->admin)
 {
-	$error=0;
+	$error = 0;
 
 	$db->begin();
-	$securityevents=new Events($db);
+	$securityevents = new Events($db);
 
 	// Delete events
 	$sql = "DELETE FROM ".MAIN_DB_PREFIX."events";
-	$sql.= " WHERE entity = ".$conf->entity;
+	$sql .= " WHERE entity = ".$conf->entity;
 
 	dol_syslog("listevents purge", LOG_DEBUG);
 	$resql = $db->query($sql);
-	if (! $resql)
+	if (!$resql)
 	{
 		$error++;
 		setEventMessages($db->lasterror(), null, 'errors');
 	}
 
 	// Add event purge
-	$text=$langs->trans("SecurityEventsPurged");
-	$securityevent=new Events($db);
-	$securityevent->type='SECURITY_EVENTS_PURGE';
-	$securityevent->dateevent=$now;
-	$securityevent->description=$text;
+	$text = $langs->trans("SecurityEventsPurged");
+	$securityevent = new Events($db);
+	$securityevent->type = 'SECURITY_EVENTS_PURGE';
+	$securityevent->dateevent = $now;
+	$securityevent->description = $text;
 
-	$result=$securityevent->create($user);
+	$result = $securityevent->create($user);
 	if ($result > 0)
 	{
 	    $db->commit();
@@ -162,26 +162,26 @@ if ($action == 'confirm_purge' && $confirm == 'yes' && $user->admin)
 
 llxHeader('', $langs->trans("Audit"));
 
-$form=new Form($db);
+$form = new Form($db);
 
-$userstatic=new User($db);
-$usefilter=0;
+$userstatic = new User($db);
+$usefilter = 0;
 
 $sql = "SELECT e.rowid, e.type, e.ip, e.user_agent, e.dateevent,";
-$sql.= " e.fk_user, e.description, e.prefix_session,";
-$sql.= " u.login";
-$sql.= " FROM ".MAIN_DB_PREFIX."events as e";
-$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = e.fk_user";
-$sql.= " WHERE e.entity IN (".getEntity('event').")";
-if ($date_start > 0) $sql.= " AND e.dateevent >= '".$db->idate($date_start)."'";
-if ($date_end > 0)   $sql.= " AND e.dateevent <= '".$db->idate($date_end)."'";
-if ($search_code) { $usefilter++; $sql.=natural_search("e.type", $search_code, 0); }
-if ($search_ip)   { $usefilter++; $sql.=natural_search("e.ip", $search_ip, 0); }
-if ($search_user) { $usefilter++; $sql.=natural_search("u.login", $search_user, 0); }
-if ($search_desc) { $usefilter++; $sql.=natural_search("e.description", $search_desc, 0); }
-if ($search_ua)   { $usefilter++; $sql.=natural_search("e.user_agent", $search_ua, 0); }
-if ($search_prefix_session)   { $usefilter++; $sql.=natural_search("e.prefix_session", $search_prefix_session, 0); }
-$sql.= $db->order($sortfield, $sortorder);
+$sql .= " e.fk_user, e.description, e.prefix_session,";
+$sql .= " u.login";
+$sql .= " FROM ".MAIN_DB_PREFIX."events as e";
+$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = e.fk_user";
+$sql .= " WHERE e.entity IN (".getEntity('event').")";
+if ($date_start > 0) $sql .= " AND e.dateevent >= '".$db->idate($date_start)."'";
+if ($date_end > 0)   $sql .= " AND e.dateevent <= '".$db->idate($date_end)."'";
+if ($search_code) { $usefilter++; $sql .= natural_search("e.type", $search_code, 0); }
+if ($search_ip) { $usefilter++; $sql .= natural_search("e.ip", $search_ip, 0); }
+if ($search_user) { $usefilter++; $sql .= natural_search("u.login", $search_user, 0); }
+if ($search_desc) { $usefilter++; $sql .= natural_search("e.description", $search_desc, 0); }
+if ($search_ua) { $usefilter++; $sql .= natural_search("e.user_agent", $search_ua, 0); }
+if ($search_prefix_session) { $usefilter++; $sql .= natural_search("e.prefix_session", $search_prefix_session, 0); }
+$sql .= $db->order($sortfield, $sortorder);
 
 // Count total nb of records
 $nbtotalofrecords = '';
@@ -196,7 +196,7 @@ $nbtotalofrecords = '';
     }
 }*/
 
-$sql.= $db->plimit($conf->liste_limit+1, $offset);
+$sql .= $db->plimit($conf->liste_limit + 1, $offset);
 //print $sql;
 $result = $db->query($sql);
 if ($result)
@@ -204,27 +204,27 @@ if ($result)
 	$num = $db->num_rows($result);
 	$i = 0;
 
-	$param='';
-	if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
-	if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
-	if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
-	if ($search_code) $param.='&search_code='.urlencode($search_code);
-	if ($search_ip)   $param.='&search_ip='.urlencode($search_ip);
-	if ($search_user) $param.='&search_user='.urlencode($search_user);
-	if ($search_desc) $param.='&search_desc='.urlencode($search_desc);
-	if ($search_ua)   $param.='&search_ua='.urlencode($search_ua);
-	if ($search_prefix_sessiona)   $param.='&search_prefix_session='.urlencode($search_prefix_session);
-	if ($date_startmonth) $param.= "&date_startmonth=".urlencode($date_startmonth);
-	if ($date_startday)   $param.= "&date_startday=".urlencode($date_startday);
-	if ($date_startyear)  $param.= "&date_startyear=".urlencode($date_startyear);
-	if ($date_endmonth)   $param.= "&date_endmonth=".urlencode($date_endmonth);
-	if ($date_endday)     $param.= "&date_endday=".urlencode($date_endday);
-	if ($date_endyear)    $param.= "&date_endyear=".urlencode($date_endyear);
+	$param = '';
+	if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
+	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
+	if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss);
+	if ($search_code) $param .= '&search_code='.urlencode($search_code);
+	if ($search_ip)   $param .= '&search_ip='.urlencode($search_ip);
+	if ($search_user) $param .= '&search_user='.urlencode($search_user);
+	if ($search_desc) $param .= '&search_desc='.urlencode($search_desc);
+	if ($search_ua)   $param .= '&search_ua='.urlencode($search_ua);
+	if ($search_prefix_sessiona)   $param .= '&search_prefix_session='.urlencode($search_prefix_session);
+	if ($date_startmonth) $param .= "&date_startmonth=".urlencode($date_startmonth);
+	if ($date_startday)   $param .= "&date_startday=".urlencode($date_startday);
+	if ($date_startyear)  $param .= "&date_startyear=".urlencode($date_startyear);
+	if ($date_endmonth)   $param .= "&date_endmonth=".urlencode($date_endmonth);
+	if ($date_endday)     $param .= "&date_endday=".urlencode($date_endday);
+	if ($date_endyear)    $param .= "&date_endyear=".urlencode($date_endyear);
 
     $langs->load('withdrawals');
     if ($num)
     {
-        $center='<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=purge">'.$langs->trans("Purge").'</a>';
+        $center = '<a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=purge">'.$langs->trans("Purge").'</a>';
     }
 
 	print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'">';
@@ -233,7 +233,7 @@ if ($result)
 
 	if ($action == 'purge')
 	{
-		$formquestion=array();
+		$formquestion = array();
 		print $form->formconfirm($_SERVER["PHP_SELF"].'?noparam=noparam', $langs->trans('PurgeAuditEvents'), $langs->trans('ConfirmPurgeAuditEvents'), 'confirm_purge', $formquestion, 'no', 1);
 	}
 
@@ -262,14 +262,14 @@ if ($result)
 	//print '<input class="flat maxwidth100" type="text" size="10" name="search_desc" value="'.$search_desc.'">';
 	print '</td>';
 
-	if (! empty($arrayfields['e.user_agent']['checked']))
+	if (!empty($arrayfields['e.user_agent']['checked']))
 	{
 		print '<td class="liste_titre left">';
 		print '<input class="flat maxwidth100" type="text" name="search_ua" value="'.$search_ua.'">';
 		print '</td>';
 	}
 
-	if (! empty($arrayfields['e.prefix_session']['checked']))
+	if (!empty($arrayfields['e.prefix_session']['checked']))
 	{
 		print '<td class="liste_titre left">';
 		print '<input class="flat maxwidth100" type="text" name="search_prefix_session" value="'.$search_prefix_session.'">';
@@ -277,7 +277,7 @@ if ($result)
 	}
 
 	print '<td class="liste_titre maxwidthsearch">';
-	$searchpicto=$form->showFilterAndCheckAddButtons(0);
+	$searchpicto = $form->showFilterAndCheckAddButtons(0);
 	print $searchpicto;
 	print '</td>';
 
@@ -290,11 +290,11 @@ if ($result)
 	print_liste_field_titre("IP", $_SERVER["PHP_SELF"], "e.ip", "", $param, '', $sortfield, $sortorder);
 	print_liste_field_titre("User", $_SERVER["PHP_SELF"], "u.login", "", $param, '', $sortfield, $sortorder);
 	print_liste_field_titre("Description", $_SERVER["PHP_SELF"], "e.description", "", $param, '', $sortfield, $sortorder);
-	if (! empty($arrayfields['e.user_agent']['checked']))
+	if (!empty($arrayfields['e.user_agent']['checked']))
 	{
 		print_liste_field_titre("UserAgent", $_SERVER["PHP_SELF"], "e.user_agent", "", $param, '', $sortfield, $sortorder);
 	}
-	if (! empty($arrayfields['e.prefix_session']['checked']))
+	if (!empty($arrayfields['e.prefix_session']['checked']))
 	{
 		print_liste_field_titre("PrefixSession", $_SERVER["PHP_SELF"], "e.prefix_session", "", $param, '', $sortfield, $sortorder);
 	}
@@ -322,8 +322,8 @@ if ($result)
 		print '<td class="nowrap">';
 		if ($obj->fk_user)
 		{
-			$userstatic->id=$obj->fk_user;
-			$userstatic->login=$obj->login;
+			$userstatic->id = $obj->fk_user;
+			$userstatic->login = $obj->login;
 			print $userstatic->getLoginUrl(1);
 		}
 		else print '&nbsp;';
@@ -331,18 +331,18 @@ if ($result)
 
 		// Description
 		print '<td>';
-		$text=$langs->trans($obj->description);
+		$text = $langs->trans($obj->description);
 		$reg = array();
 		if (preg_match('/\((.*)\)(.*)/i', $obj->description, $reg))
 		{
-			$val=explode(',', $reg[1]);
-			$text=$langs->trans($val[0], isset($val[1])?$val[1]:'', isset($val[2])?$val[2]:'', isset($val[3])?$val[3]:'', isset($val[4])?$val[4]:'');
-			if (! empty($reg[2])) $text.=$reg[2];
+			$val = explode(',', $reg[1]);
+			$text = $langs->trans($val[0], isset($val[1]) ? $val[1] : '', isset($val[2]) ? $val[2] : '', isset($val[3]) ? $val[3] : '', isset($val[4]) ? $val[4] : '');
+			if (!empty($reg[2])) $text .= $reg[2];
 		}
 		print dol_escape_htmltag($text);
 		print '</td>';
 
-		if (! empty($arrayfields['e.user_agent']['checked']))
+		if (!empty($arrayfields['e.user_agent']['checked']))
 		{
 			// User agent
 			print '<td>';
@@ -350,7 +350,7 @@ if ($result)
 			print '</td>';
 		}
 
-		if (! empty($arrayfields['e.prefix_session']['checked']))
+		if (!empty($arrayfields['e.prefix_session']['checked']))
 		{
 			// User agent
 			print '<td>';
@@ -360,8 +360,8 @@ if ($result)
 
 		// More informations
 		print '<td class="right">';
-		$htmltext='<b>'.$langs->trans("UserAgent").'</b>: '.($obj->user_agent ? dol_string_nohtmltag($obj->user_agent) : $langs->trans("Unknown"));
-		$htmltext.='<br><b>'.$langs->trans("PrefixSession").'</b>: '.($obj->prefix_session ? dol_string_nohtmltag($obj->prefix_session) : $langs->trans("Unknown"));
+		$htmltext = '<b>'.$langs->trans("UserAgent").'</b>: '.($obj->user_agent ? dol_string_nohtmltag($obj->user_agent) : $langs->trans("Unknown"));
+		$htmltext .= '<br><b>'.$langs->trans("PrefixSession").'</b>: '.($obj->prefix_session ? dol_string_nohtmltag($obj->prefix_session) : $langs->trans("Unknown"));
 		print $form->textwithpicto('', $htmltext);
 		print '</td>';
 

+ 1 - 1
htdocs/asset/class/asset.class.php

@@ -82,7 +82,7 @@ class Asset extends CommonObject
 		'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'visible'=>1, 'enabled'=>1, 'position'=>30, 'notnull'=>-1, 'searchall'=>1, 'help'=>"Help text",),
 		'amount_ht' => array('type'=>'double(24,8)', 'label'=>'AmountHTShort', 'visible'=>1, 'enabled'=>1, 'position'=>40, 'notnull'=>-1, 'isameasure'=>'1', 'help'=>"Help text",),
 		'amount_vat' => array('type'=>'double(24,8)', 'label'=>'AmountVAT', 'visible'=>1, 'enabled'=>1, 'position'=>40, 'notnull'=>-1, 'isameasure'=>'1', 'help'=>"Help text",),
-		'fk_asset_type' => array('type'=>'integer:AssetType:asset/class/asset.class.php', 'label'=>'AssetsType', 'visible'=>1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"LinkToThirparty",),
+		'fk_asset_type' => array('type'=>'integer:AssetType:asset/class/asset_type.class.php', 'label'=>'AssetsType', 'visible'=>1, 'enabled'=>1, 'position'=>50, 'notnull'=>-1, 'index'=>1, 'searchall'=>1, 'help'=>"LinkToThirparty",),
 		'description' => array('type'=>'text', 'label'=>'Description', 'visible'=>-1, 'enabled'=>1, 'position'=>90, 'notnull'=>-1,),
 		'note_public' => array('type'=>'html', 'label'=>'NotePublic', 'visible'=>-1, 'enabled'=>1, 'position'=>91, 'notnull'=>-1,),
 		'note_private' => array('type'=>'html', 'label'=>'NotePrivate', 'visible'=>-1, 'enabled'=>1, 'position'=>92, 'notnull'=>-1,),

+ 11 - 0
htdocs/asset/class/asset_type.class.php

@@ -70,6 +70,17 @@ class AssetType extends CommonObject
 	/** @var array Array of asset */
 	public $asset=array();
 
+	public $fields=array(
+		'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
+		'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>15, 'index'=>1),
+		'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>20),
+		'label' =>array('type'=>'varchar(50)', 'label'=>'Label', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25, 'showoncombobox'=>1),
+		'accountancy_code_asset' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code asset', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
+		'accountancy_code_depreciation_asset' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code depreciation asset', 'enabled'=>1, 'visible'=>-1, 'position'=>35),
+		'accountancy_code_depreciation_expense' =>array('type'=>'varchar(32)', 'label'=>'Accountancy code depreciation expense', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
+		'note' =>array('type'=>'mediumtext', 'label'=>'Note', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
+	);
+
 
 	/**
 	 *	Constructor

+ 124 - 118
htdocs/asset/list.php

@@ -33,7 +33,7 @@ require_once DOL_DOCUMENT_ROOT.'/asset/class/asset.class.php';
 // Load translation files required by the page
 $langs->loadLangs(array("assets"));
 
-$action     = GETPOST('action', 'alpha') ?GETPOST('action', 'alpha') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ...
+$action     = GETPOST('action', 'aZ09') ?GETPOST('action', 'aZ09') : 'view'; // The action 'add', 'create', 'edit', 'update', 'view', ...
 $massaction = GETPOST('massaction', 'alpha'); // The bulk action (combo box choice into lists)
 $show_files = GETPOST('show_files', 'int'); // Show files area generated by bulk actions ?
 $confirm    = GETPOST('confirm', 'alpha'); // Result of a confirmation
@@ -50,7 +50,7 @@ $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST('sortfield', 'alpha');
 $sortorder = GETPOST('sortorder', 'alpha');
 $page = GETPOST('page', 'int');
-if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined, or '' or -1
+if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST('button_removefilter', 'alpha') || (empty($toselect) && $massaction === '0')) { $page = 0; }     // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action
 $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
@@ -63,6 +63,7 @@ $hookmanager->initHooks(array('assetlist')); // Note that conf->hooks_modules co
 
 // Fetch optionals attributes and labels
 $extrafields->fetch_name_optionals_label($object->table_element);
+//$extrafields->fetch_name_optionals_label($object->table_element_line);
 
 $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
 
@@ -70,9 +71,9 @@ $search_array_options = $extrafields->getOptionalsFromPost($object->table_elemen
 if (!$sortfield) $sortfield = "t.".key($object->fields); // Set here default search field. By default 1st field in definition.
 if (!$sortorder) $sortorder = "ASC";
 
-// Protection if external user
+// Security check
 $socid = 0;
-if ($user->socid > 0)
+if ($user->socid > 0)	// Protection if external user
 {
 	//$socid = $user->socid;
 	accessforbidden();
@@ -84,7 +85,7 @@ $search_all = trim(GETPOST("search_all", 'alpha'));
 $search = array();
 foreach ($object->fields as $key => $val)
 {
-	if (GETPOST('search_'.$key, 'alpha')) $search[$key] = GETPOST('search_'.$key, 'alpha');
+	if (GETPOST('search_'.$key, 'alpha') !== '') $search[$key] = GETPOST('search_'.$key, 'alpha');
 }
 
 // List of fields to search into when doing a "search in all"
@@ -99,26 +100,33 @@ $arrayfields = array();
 foreach ($object->fields as $key => $val)
 {
 	// If $val['visible']==0, then we never show the field
-	if (!empty($val['visible'])) $arrayfields['t.'.$key] = array('label'=>$val['label'], 'checked'=>(($val['visible'] < 0) ? 0 : 1), 'enabled'=>$val['enabled'], 'position'=>$val['position']);
+	if (!empty($val['visible'])) $arrayfields['t.'.$key] = array('label'=>$val['label'], 'checked'=>(($val['visible'] < 0) ? 0 : 1), 'enabled'=>($val['enabled'] && ($val['visible'] != 3)), 'position'=>$val['position']);
 }
 // Extra fields
 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0)
 {
 	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val)
 	{
-		if (!empty($extrafields->attributes[$object->table_element]['list'][$key]))
-			$arrayfields["ef.".$key] = array('label'=>$extrafields->attributes[$object->table_element]['label'][$key], 'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1), 'position'=>$extrafields->attributes[$object->table_element]['pos'][$key], 'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key]));
+		if (!empty($extrafields->attributes[$object->table_element]['list'][$key])) {
+			$arrayfields["ef.".$key] = array(
+				'label'=>$extrafields->attributes[$object->table_element]['label'][$key],
+				'checked'=>(($extrafields->attributes[$object->table_element]['list'][$key] < 0) ? 0 : 1),
+				'position'=>$extrafields->attributes[$object->table_element]['pos'][$key],
+				'enabled'=>(abs($extrafields->attributes[$object->table_element]['list'][$key]) != 3 && $extrafields->attributes[$object->table_element]['perms'][$key])
+			);
+		}
 	}
 }
 $object->fields = dol_sort_array($object->fields, 'position');
 $arrayfields = dol_sort_array($arrayfields, 'position');
 
+$permissiontoread = $user->rights->asset->read;
+$permissiontoadd = $user->rights->asset->write;
+$permissiontodelete = $user->rights->asset->delete;
 
 
 /*
  * Actions
- *
- * Put here all code to do according to value of "$action" parameter
  */
 
 if (GETPOST('cancel', 'alpha')) { $action = 'list'; $massaction = ''; }
@@ -152,8 +160,6 @@ if (empty($reshook))
 	// Mass actions
 	$objectclass = 'Asset';
 	$objectlabel = 'Asset';
-	$permissiontoread = $user->rights->asset->read;
-	$permissiontodelete = $user->rights->asset->delete;
 	$uploaddir = $conf->asset->dir_output;
 	include DOL_DOCUMENT_ROOT.'/core/actions_massactions.inc.php';
 }
@@ -162,8 +168,6 @@ if (empty($reshook))
 
 /*
  * View
- *
- * Put here all code to render page
  */
 
 $form = new Form($db);
@@ -183,23 +187,30 @@ foreach ($object->fields as $key => $val)
 	$sql .= 't.'.$key.', ';
 }
 // Add fields from extrafields
-if (!empty($extrafields->attributes[$object->table_element]['label']))
+if (!empty($extrafields->attributes[$object->table_element]['label'])) {
 	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.' as options_'.$key.', ' : '');
+}
 // Add fields from hooks
 $parameters = array();
 $reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters, $object); // Note that $action and $object may have been modified by hook
-$sql .= $hookmanager->resPrint;
+$sql .= preg_replace('/^,/', '', $hookmanager->resPrint);
 $sql = preg_replace('/,\s*$/', '', $sql);
 $sql .= " FROM ".MAIN_DB_PREFIX.$object->table_element." as t";
 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (t.rowid = ef.fk_object)";
-if ($object->ismultientitymanaged == 1) $sql .= " WHERE t.entity IN (".getEntity('assets').")";
+if ($object->ismultientitymanaged == 1) $sql .= " WHERE t.entity IN (".getEntity($object->element).")";
 else $sql .= " WHERE 1 = 1";
 foreach ($search as $key => $val)
 {
+	if ($key == 'status' && $search[$key] == -1) continue;
 	$mode_search = (($object->isInt($object->fields[$key]) || $object->isFloat($object->fields[$key])) ? 1 : 0);
+	if (strpos($object->fields[$key]['type'], 'integer:') === 0) {
+		if ($search[$key] == '-1') $search[$key] = '';
+		$mode_search = 2;
+	}
 	if ($search[$key] != '') $sql .= natural_search($key, $search[$key], (($key == 'status') ? 2 : $mode_search));
 }
 if ($search_all) $sql .= natural_search(array_keys($fieldstosearchall), $search_all);
+//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear);
 // Add where from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
 // Add where from hooks
@@ -216,10 +227,12 @@ foreach($object->fields as $key => $val)
 // Add fields from extrafields
 if (! empty($extrafields->attributes[$object->table_element]['label'])) {
 	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? "ef.".$key.', ' : '');
+}
 // Add where from hooks
 $parameters=array();
 $reshook=$hookmanager->executeHooks('printFieldListGroupBy',$parameters);    // Note that $action and $object may have been modified by hook
 $sql.=$hookmanager->resPrint;
+$sql=preg_replace('/,\s*$/','', $sql);
 */
 
 $sql .= $db->order($sortfield, $sortorder);
@@ -228,28 +241,35 @@ $sql .= $db->order($sortfield, $sortorder);
 $nbtotalofrecords = '';
 if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 {
-	$result = $db->query($sql);
-	$nbtotalofrecords = $db->num_rows($result);
-	if (($page * $limit) > $nbtotalofrecords)	// if total resultset is smaller then paging size (filtering), goto and load page 0
+	$resql = $db->query($sql);
+	$nbtotalofrecords = $db->num_rows($resql);
+	if (($page * $limit) > $nbtotalofrecords)	// if total of record found is smaller than page * limit, goto and load page 0
 	{
 		$page = 0;
 		$offset = 0;
 	}
 }
-
-$sql .= $db->plimit($limit + 1, $offset);
-
-$resql = $db->query($sql);
-if (!$resql)
+// if total of record found is smaller than limit, no need to do paging and to restart another select with limits set.
+if (is_numeric($nbtotalofrecords) && ($limit > $nbtotalofrecords || empty($limit)))
 {
-	dol_print_error($db);
-	exit;
+	$num = $nbtotalofrecords;
 }
+else
+{
+	if ($limit) $sql .= $db->plimit($limit + 1, $offset);
+
+	$resql = $db->query($sql);
+	if (!$resql)
+	{
+		dol_print_error($db);
+		exit;
+	}
 
-$num = $db->num_rows($resql);
+	$num = $db->num_rows($resql);
+}
 
 // Direct jump if only one record found
-if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all)
+if ($num == 1 && !empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $search_all && !$page)
 {
 	$obj = $db->fetch_object($resql);
 	$id = $obj->rowid;
@@ -285,7 +305,8 @@ if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&co
 if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
 foreach ($search as $key => $val)
 {
-	$param .= '&search_'.$key.'='.urlencode($search[$key]);
+	if (is_array($search[$key]) && count($search[$key])) foreach ($search[$key] as $skey) $param .= '&search_'.$key.'[]='.urlencode($skey);
+	else $param .= '&search_'.$key.'='.urlencode($search[$key]);
 }
 if ($optioncss != '')     $param .= '&optioncss='.urlencode($optioncss);
 // Add $param from extra fields
@@ -296,19 +317,11 @@ $arrayofmassactions = array(
 	//'presend'=>$langs->trans("SendByMail"),
 	//'builddoc'=>$langs->trans("PDFMerge"),
 );
-if ($user->rights->asset->delete) $arrayofmassactions['predelete'] = '<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
-if (in_array($massaction, array('presend', 'predelete'))) $arrayofmassactions = array();
+if ($permissiontodelete) $arrayofmassactions['predelete'] = '<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
+if (GETPOST('nomassaction', 'int') || in_array($massaction, array('presend', 'predelete'))) $arrayofmassactions = array();
 $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
 
-$newcardbutton = '';
-if ($user->rights->asset->write)
-{
-    $newcardbutton = '<a class="butActionNew" href="'.DOL_URL_ROOT.'/asset/card.php?action=create"><span class="valignmiddle text-plus-circle">'.$langs->trans('NewAsset').'</span>';
-    $newcardbutton .= '<span class="fa fa-plus-circle valignmiddle"></span>';
-    $newcardbutton .= '</a>';
-}
-
-print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
+print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">'."\n";
 if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
 print '<input type="hidden" name="token" value="'.newToken().'">';
 print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">';
@@ -318,6 +331,8 @@ print '<input type="hidden" name="sortorder" value="'.$sortorder.'">';
 print '<input type="hidden" name="page" value="'.$page.'">';
 print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
 
+$newcardbutton = dolGetButtonTitle($langs->trans('NewAsset'), '', 'fa fa-plus-circle', dol_buildpath('/asset/card.php', 1).'?action=create&backtopage='.urlencode($_SERVER['PHP_SELF']), '', $permissiontoadd);
+
 print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'accountancy', 0, $newcardbutton, '', $limit);
 
 // Add code for pre mass action (confirmation or email presend form)
@@ -363,11 +378,21 @@ print '<table class="tagtable liste'.($moreforfilter ? " listwithfilterbefore" :
 print '<tr class="liste_titre">';
 foreach ($object->fields as $key => $val)
 {
-	$align = '';
-	if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) $align .= ($align ? ' ' : '').'center';
-	if (in_array($val['type'], array('timestamp'))) $align .= ($align ? ' ' : '').'nowrap';
-	if ($key == 'status') $align .= ($align ? ' ' : '').'center';
-	if (!empty($arrayfields['t.'.$key]['checked'])) print '<td class="liste_titre'.($align ? ' '.$align : '').'"><input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'"></td>';
+	$cssforfield = (empty($val['css']) ? '' : $val['css']);
+	if ($key == 'status') $cssforfield .= ($cssforfield ? ' ' : '').'center';
+	elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'center';
+	elseif (in_array($val['type'], array('timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'nowrap';
+	elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID') $cssforfield .= ($cssforfield ? ' ' : '').'right';
+	if (!empty($arrayfields['t.'.$key]['checked']))
+	{
+		print '<td class="liste_titre'.($cssforfield ? ' '.$cssforfield : '').'">';
+		if (is_array($val['arrayofkeyval'])) print $form->selectarray('search_'.$key, $val['arrayofkeyval'], $search[$key], $val['notnull'], 0, 0, '', 1, 0, 0, '', 'maxwidth75');
+		elseif (strpos($val['type'], 'integer:') === 0) {
+			print $object->showInputField($val, $key, $search[$key], '', '', 'search_', 'maxwidth150', 1);
+		}
+		elseif (!preg_match('/^(date|timestamp)/', $val['type'])) print '<input type="text" class="flat maxwidth75" name="search_'.$key.'" value="'.dol_escape_htmltag($search[$key]).'">';
+		print '</td>';
+	}
 }
 // Extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
@@ -389,11 +414,15 @@ print '</tr>'."\n";
 print '<tr class="liste_titre">';
 foreach($object->fields as $key => $val)
 {
-	$align='';
-	if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center';
-	if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap';
-	if ($key == 'status') $align.=($align?' ':'').'center';
-	if (! empty($arrayfields['t.'.$key]['checked'])) print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($align?'class="'.$align.'"':''), $sortfield, $sortorder, $align.' ')."\n";
+	$cssforfield = (empty($val['css']) ? '' : $val['css']);
+	if ($key == 'status') $cssforfield .= ($cssforfield ? ' ' : '').'center';
+	elseif (in_array($val['type'], array('date', 'datetime', 'timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'center';
+	elseif (in_array($val['type'], array('timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'nowrap';
+	elseif (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $val['label'] != 'TechnicalID') $cssforfield .= ($cssforfield ? ' ' : '').'right';
+	if (!empty($arrayfields['t.'.$key]['checked']))
+	{
+		print getTitleFieldOfList($arrayfields['t.'.$key]['label'], 0, $_SERVER['PHP_SELF'], 't.'.$key, '', $param, ($cssforfield ? 'class="'.$cssforfield.'"' : ''), $sortfield, $sortorder, ($cssforfield ? $cssforfield.' ' : ''))."\n";
+	}
 }
 // Extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
@@ -401,19 +430,19 @@ include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
 $parameters=array('arrayfields'=>$arrayfields,'param'=>$param,'sortfield'=>$sortfield,'sortorder'=>$sortorder);
 $reshook=$hookmanager->executeHooks('printFieldListTitle', $parameters, $object);    // Note that $action and $object may have been modified by hook
 print $hookmanager->resPrint;
+// Action column
 print getTitleFieldOfList($selectedfields, 0, $_SERVER["PHP_SELF"], '', '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ')."\n";
 print '</tr>'."\n";
 
 
 // Detect if we need a fetch on each output line
 $needToFetchEachLine=0;
-if (is_array($extrafields->attributes[$object->table_element]['computed'])) {
-    foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val) {
-        if (preg_match('/\$object/', $val)) {
-            // There is at least one compute field that use $object
-            $needToFetchEachLine++;
-        }
-    }
+if (is_array($extrafields->attributes[$object->table_element]['computed']) && count($extrafields->attributes[$object->table_element]['computed']) > 0)
+{
+	foreach ($extrafields->attributes[$object->table_element]['computed'] as $key => $val)
+	{
+		if (preg_match('/\$object/', $val)) $needToFetchEachLine++; // There is at least one compute field that use $object
+	}
 }
 
 
@@ -421,84 +450,65 @@ if (is_array($extrafields->attributes[$object->table_element]['computed'])) {
 // --------------------------------------------------------------------
 $i=0;
 $totalarray=array();
-while ($i < min($num, $limit))
+while ($i < ($limit ? min($num, $limit) : $num))
 {
 	$obj = $db->fetch_object($resql);
 	if (empty($obj)) break;		// Should not happen
 
 	// Store properties in $object
-	$object->id = $obj->rowid;
-	foreach($object->fields as $key => $val)
-	{
-		if (property_exists($obj, $key)) $object->$key = $obj->$key;
-	}
+	$object->setVarsFromFetchObj($obj);
 
 	// Show here line of result
 	print '<tr class="oddeven">';
 	foreach($object->fields as $key => $val)
 	{
-		$align='';
-		if (in_array($val['type'], array('date','datetime','timestamp'))) $align.=($align?' ':'').'center';
-		if (in_array($val['type'], array('timestamp'))) $align.=($align?' ':'').'nowrap';
-		if ($key == 'status') $align.=($align?' ':'').'center';
-		if (! empty($arrayfields['t.'.$key]['checked']))
+		$cssforfield = (empty($val['css']) ? '' : $val['css']);
+		if (in_array($val['type'], array('date', 'datetime', 'timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'center';
+		elseif ($key == 'status') $cssforfield .= ($cssforfield ? ' ' : '').'center';
+
+		if (in_array($val['type'], array('timestamp'))) $cssforfield .= ($cssforfield ? ' ' : '').'nowrap';
+		elseif ($key == 'ref') $cssforfield .= ($cssforfield ? ' ' : '').'nowrap';
+
+		if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $key != 'status') $cssforfield .= ($cssforfield ? ' ' : '').'right';
+
+		if (!empty($arrayfields['t.'.$key]['checked']))
 		{
-			print '<td';
-			if ($align) print ' class="'.$align.'"';
-			print '>';
-			print $object->showOutputField($val, $key, $obj->$key, '');
+			print '<td'.($cssforfield ? ' class="'.$cssforfield.'"' : '').'>';
+			if ($key == 'status') print $object->getLibStatut(5);
+			else print $object->showOutputField($val, $key, $object->$key, '');
 			print '</td>';
-			if (! $i) $totalarray['nbfield']++;
-			if (! empty($val['isameasure']))
+			if (!$i) $totalarray['nbfield']++;
+			if (!empty($val['isameasure']))
 			{
-				if (! $i) $totalarray['pos'][$totalarray['nbfield']]='t.'.$key;
-				$totalarray['val']['t.'.$key] += $obj->$key;
+				if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 't.'.$key;
+				$totalarray['val']['t.'.$key] += $object->$key;
 			}
 		}
 	}
 	// Extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
 	// Fields from hook
-	$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj);
+	$parameters = array('arrayfields'=>$arrayfields, 'object'=>$object, 'obj'=>$obj, 'i'=>$i, 'totalarray'=>&$totalarray);
 	$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters, $object); // Note that $action and $object may have been modified by hook
 	print $hookmanager->resPrint;
 	// Action column
-	print '<td class="nowrap" align="center">';
+	print '<td class="nowrap 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"' : '').'>';
+		if (in_array($object->id, $arrayofselected)) $selected = 1;
+		print '<input id="cb'.$object->id.'" class="flat checkforselect" type="checkbox" name="toselect[]" value="'.$object->id.'"'.($selected ? ' checked="checked"' : '').'>';
 	}
 	print '</td>';
 	if (!$i) $totalarray['nbfield']++;
 
-	print '</tr>';
+	print '</tr>'."\n";
 
 	$i++;
 }
 
 // Show total line
-if (isset($totalarray['pos']))
-{
-	print '<tr class="liste_total">';
-	$i = 0;
-	while ($i < $totalarray['nbfield'])
-	{
-		$i++;
-		if (!empty($totalarray['pos'][$i]))  print '<td class="right">'.price($totalarray['val'][$totalarray['pos'][$i]]).'</td>';
-		else
-		{
-			if ($i == 1)
-			{
-				if ($num < $limit) print '<td class="left">'.$langs->trans("Total").'</td>';
-				else print '<td class="left">'.$langs->trans("Totalforthispage").'</td>';
-			}
-			else print '<td></td>';
-		}
-	}
-	print '</tr>';
-}
+include DOL_DOCUMENT_ROOT.'/core/tpl/list_print_total.tpl.php';
 
 // If no record found
 if ($num == 0)
@@ -522,25 +532,21 @@ print '</form>'."\n";
 
 if (in_array('builddoc', $arrayofmassactions) && ($nbtotalofrecords === '' || $nbtotalofrecords))
 {
-	if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files)
-	{
-		require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
-		$formfile = new FormFile($db);
+	$hidegeneratedfilelistifempty = 1;
+	if ($massaction == 'builddoc' || $action == 'remove_file' || $show_files) $hidegeneratedfilelistifempty = 0;
 
-		// Show list of available documents
-		$urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
-		$urlsource .= str_replace('&amp;', '&', $param);
+	require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
+	$formfile = new FormFile($db);
 
-		$filedir = $diroutputmassaction;
-		$genallowed = $user->rights->asset->read;
-		$delallowed = $user->rights->asset->create;
+	// Show list of available documents
+	$urlsource = $_SERVER['PHP_SELF'].'?sortfield='.$sortfield.'&sortorder='.$sortorder;
+	$urlsource .= str_replace('&amp;', '&', $param);
 
-		print $formfile->showdocuments('massfilesarea_asset', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '');
-	}
-	else
-	{
-		print '<br><a name="show_files"></a><a href="'.$_SERVER["PHP_SELF"].'?show_files=1'.$param.'#show_files">'.$langs->trans("ShowTempMassFilesArea").'</a>';
-	}
+	$filedir = $diroutputmassaction;
+	$genallowed = $permissiontoread;
+	$delallowed = $permissiontoadd;
+
+	print $formfile->showdocuments('massfilesarea_asset', '', $filedir, $urlsource, 0, $delallowed, '', 1, 1, 0, 48, 1, $param, $title, '');
 }
 
 // End of page

+ 1 - 1
htdocs/bom/class/bom.class.php

@@ -747,7 +747,7 @@ class BOM extends CommonObject
         $label .= '<br>';
         $label .= '<b>'.$langs->trans('Ref').':</b> '.$this->ref;
         if (isset($this->status)) {
-        	$label.= '<br><b>' . $langs->trans("Status").":</b> ".$this->getLibStatut(5);
+        	$label .= '<br><b>'.$langs->trans("Status").":</b> ".$this->getLibStatut(5);
         }
 
         $url = dol_buildpath('/bom/bom_card.php', 1).'?id='.$this->id;

+ 5 - 0
htdocs/categories/class/api_categories.class.php

@@ -48,6 +48,11 @@ class Categories extends DolibarrApi
         3 => 'member',
         4 => 'contact',
         5 => 'account',
+        //6 => 'project',
+        //7 => 'user',
+        //8 => 'bank_line',
+        //9 => 'warehouse',
+        //10 => 'actioncomm',
     );
 
     /**

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

@@ -54,6 +54,7 @@ class Categorie extends CommonObject
 	const TYPE_ACCOUNT   = 'bank_account';
     const TYPE_BANK_LINE = 'bank_line';
     const TYPE_WAREHOUSE = 'warehouse';
+    const TYPE_ACTIONCOMM = 'actioncomm';
 
 	/**
 	 * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png
@@ -77,6 +78,7 @@ class Categorie extends CommonObject
 		'user'         => 7,
 		'bank_line'    => 8,
 		'warehouse'    => 9,
+        'actioncomm' => 10,
 	);
 
     /**
@@ -93,6 +95,7 @@ class Categorie extends CommonObject
 		7 => 'user',
 		8 => 'bank_line',
 		9 => 'warehouse',
+        10 => 'actioncomm',
 	);
 
 	/**
@@ -111,6 +114,7 @@ class Categorie extends CommonObject
         'bank_account' => 'account',
         'project'  => 'project',
         'warehouse'=> 'warehouse',
+        'actioncomm' => 'actioncomm',
     );
 
     /**
@@ -129,6 +133,7 @@ class Categorie extends CommonObject
         'bank_account'=> 'account',
         'project'  => 'project',
         'warehouse'=> 'warehouse',
+        'actioncomm' => 'actioncomm',
 	);
 
     /**
@@ -147,6 +152,7 @@ class Categorie extends CommonObject
 		'bank_account'  => 'Account',
         'project'  => 'Project',
         'warehouse'=> 'Entrepot',
+        'actioncomm' => 'ActionComm',
 	);
 
     /**
@@ -164,6 +170,7 @@ class Categorie extends CommonObject
         'account'  => 'bank_account',
         'project'  => 'projet',
         'warehouse'=> 'entrepot',
+        'actioncomm' => 'actioncomm',
 	);
 
 	/**
@@ -214,6 +221,7 @@ class Categorie extends CommonObject
 	 * @see Categorie::TYPE_PROJECT
 	 * @see Categorie::TYPE_BANK_LINE
      * @see Categorie::TYPE_WAREHOUSE
+     * @see Categorie::TYPE_ACTIONCOMM
 	 */
 	public $type;
 

+ 36 - 2
htdocs/categories/index.php

@@ -59,7 +59,13 @@ elseif ($type == Categorie::TYPE_ACCOUNT)   { $title=$langs->trans("AccountsCate
 elseif ($type == Categorie::TYPE_PROJECT)   { $title=$langs->trans("ProjectsCategoriesArea");  $typetext='project'; }
 elseif ($type == Categorie::TYPE_USER)      { $title=$langs->trans("UsersCategoriesArea");     $typetext='user'; }
 elseif ($type == Categorie::TYPE_WAREHOUSE) { $title=$langs->trans("StocksCategoriesArea");    $typetext='warehouse'; }
-else                                        { $title=$langs->trans("CategoriesArea");          $typetext='unknown'; }
+elseif ($type == Categorie::TYPE_ACTIONCOMM) {
+    $title = $langs->trans("ActionCommCategoriesArea");
+    $typetext = 'actioncomm';
+} else {
+    $title = $langs->trans("CategoriesArea");
+    $typetext = 'unknown';
+}
 
 $arrayofjs=array('/includes/jquery/plugins/jquerytreeview/jquery.treeview.js', '/includes/jquery/plugins/jquerytreeview/lib/jquery.cookie.js');
 $arrayofcss=array('/includes/jquery/plugins/jquerytreeview/jquery.treeview.css');
@@ -155,6 +161,15 @@ $cate_arbo = $categstatic->get_full_arbo($typetext);
 // Define fulltree array
 $fulltree = $cate_arbo;
 
+// Load possible missing includes
+if($conf->global->CATEGORY_SHOW_COUNTS)
+{
+	if ($type == Categorie::TYPE_MEMBER)	require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
+	if ($type == Categorie::TYPE_ACCOUNT)	require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
+	if ($type == Categorie::TYPE_PROJECT)	require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
+	if ($type == Categorie::TYPE_USER)		require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
+}
+
 // Define data (format for treeview)
 $data = array();
 $data[] = array('rowid'=>0, 'fk_menu'=>-1, 'title'=>"racine", 'mainmenu'=>'', 'leftmenu'=>'', 'fk_mainmenu'=>'', 'fk_leftmenu'=>'');
@@ -167,10 +182,29 @@ foreach ($fulltree as $key => $val)
 	$li = $categstatic->getNomUrl(1, '', 60);
 	$desc = dol_htmlcleanlastbr($val['description']);
 
+	if($conf->global->CATEGORY_SHOW_COUNTS)
+	{
+		// we need only a count of the elements, so it is enough to consume only the id's from the database
+		if ($type == Categorie::TYPE_PRODUCT)	$elements = $categstatic->getObjectsInCateg("product", 1);
+		if ($type == Categorie::TYPE_SUPPLIER)	$elements = $categstatic->getObjectsInCateg("supplier", 1);
+		if ($type == Categorie::TYPE_CUSTOMER)	$elements = $categstatic->getObjectsInCateg("customer", 1);
+		if ($type == Categorie::TYPE_MEMBER)	$elements = $categstatic->getObjectsInCateg("member", 1);
+		if ($type == Categorie::TYPE_CONTACT)	$elements = $categstatic->getObjectsInCateg("contact", 1);
+		if ($type == Categorie::TYPE_ACCOUNT)	$elements = $categstatic->getObjectsInCateg("account", 1);
+		if ($type == Categorie::TYPE_PROJECT)	$elements = $categstatic->getObjectsInCateg("project", 1);
+		if ($type == Categorie::TYPE_USER)		$elements = $categstatic->getObjectsInCateg("user", 1);
+
+		$counter = "<td class='left' width='40px;'>".count($elements)."</td>";
+	}
+	else
+	{
+		$counter = "";
+	}
+
 	$data[] = array(
 	'rowid'=>$val['rowid'],
 	'fk_menu'=>$val['fk_parent'],
-	'entry'=>'<table class="nobordernopadding centpercent"><tr><td><span class="noborderoncategories" '.($categstatic->color ? ' style="background: #'.$categstatic->color.';"' : ' style="background: #aaa"').'>'.$li.'</span></td>'.
+	'entry'=>'<table class="nobordernopadding centpercent"><tr><td><span class="noborderoncategories" '.($categstatic->color ? ' style="background: #'.$categstatic->color.';"' : ' style="background: #aaa"').'>'.$li.'</span></td>'.$counter.
 	//'<td width="50%">'.dolGetFirstLineOfText($desc).'</td>'.
 	'<td class="right" width="20px;"><a href="'.DOL_URL_ROOT.'/categories/viewcat.php?id='.$val['id'].'&type='.$type.'">'.img_view().'</a></td>'.
 	'</tr></table>'

+ 56 - 2
htdocs/categories/viewcat.php

@@ -144,6 +144,13 @@ if ($id > 0 && $removeelem > 0)
         $result = $tmpobject->fetch($removeelem);
         $elementtype = 'project';
     }
+	elseif ($type == Categorie::TYPE_USER && $user->rights->user->user->creer)
+	{
+		require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
+		$tmpobject = new User($db);
+		$result = $tmpobject->fetch($removeelem);
+		$elementtype = 'user';
+	}
 
 	$result = $object->del_type($tmpobject, $elementtype);
 	if ($result < 0) dol_print_error('', $object->error);
@@ -214,8 +221,8 @@ $head = categories_prepare_head($object, $type);
 
 
 dol_fiche_head($head, 'card', $title, -1, 'category');
-
-$linkback = '<a href="'.DOL_URL_ROOT.'/categories/index.php?leftmenu=cat&type='.$type.'">'.$langs->trans("BackToList").'</a>';
+$backtolist = (GETPOST('backtolist') ? GETPOST('backtolist') : DOL_URL_ROOT.'/categories/index.php?leftmenu=cat&type='.$type);
+$linkback = '<a href="'.$backtolist.'\">'.$langs->trans("BackToList").'</a>';
 $object->next_prev_filter=" type = ".$object->type;
 $object->ref = $object->label;
 $morehtmlref='<br><div class="refidno"><a href="'.DOL_URL_ROOT.'/categories/index.php?leftmenu=cat&type='.$type.'">'.$langs->trans("Root").'</a> >> ';
@@ -834,6 +841,53 @@ if ($type == Categorie::TYPE_PROJECT)
 	}
 }
 
+// List of users
+if ($type == Categorie::TYPE_USER)
+{
+	require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
+
+	$users = $object->getObjectsInCateg("user");
+	if ($users < 0)
+	{
+		dol_print_error($db, $object->error, $object->errors);
+	}
+	else
+	{
+		print "<br>";
+		print "<table class='noborder' width='100%'>\n";
+		print '<tr class="liste_titre"><td colspan="4">'.$langs->trans("Users").' <span class="badge">'.count($users).'</span></td></tr>'."\n";
+
+		if (count($users) > 0)
+		{
+			// Use "$userentry" here, because "$user" is the current user
+			foreach ($users as $key => $userentry)
+			{
+				print "\t".'<tr class="oddeven">'."\n";
+				print '<td class="nowrap" valign="top">';
+				print $userentry->getNomUrl(1);
+				print "</td>\n";
+				print '<td class="tdtop">'.$userentry->job."</td>\n";
+
+				// Link to delete from category
+				print '<td class="right">';
+				if ($user->rights->user->user->creer)
+				{
+					print "<a href= '".$_SERVER['PHP_SELF']."?".(empty($socid)?'id':'socid')."=".$object->id."&amp;type=".$type."&amp;removeelem=".$userentry->id."'>";
+					print $langs->trans("DeleteFromCat");
+					print img_picto($langs->trans("DeleteFromCat"), 'unlink');
+					print "</a>";
+				}
+				print "</tr>\n";
+			}
+		}
+		else
+		{
+			print '<tr class="oddeven"><td colspan="3" class="opacitymedium">'.$langs->trans("ThisCategoryHasNoUsers").'</td></tr>';
+		}
+		print "</table>\n";
+	}
+}
+
 // End of page
 llxFooter();
 $db->close();

+ 36 - 0
htdocs/comm/action/card.php

@@ -44,6 +44,7 @@ require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
+require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
 
 // Load translation files required by the page
 $langs->loadLangs(array("companies", "other", "commercial", "bills", "orders", "agenda"));
@@ -374,6 +375,10 @@ if (empty($reshook) && $action == 'add')
 		{
 			if (!$object->error)
 			{
+				// Category association
+				$categories = GETPOST('categories', 'array');
+				$object->setCategories($categories);
+
 				unset($_SESSION['assignedtouser']);
 
 				$moreparam = '';
@@ -595,6 +600,10 @@ if (empty($reshook) && $action == 'update')
 
 			if ($result > 0)
 			{
+				// Category association
+				$categories = GETPOST('categories', 'array');
+				$object->setCategories($categories);
+
 				unset($_SESSION['assignedtouser']);
 
 				$db->commit();
@@ -1000,6 +1009,14 @@ if ($action == 'create')
 		print '</td></tr>';
 	}
 
+	if ($conf->categorie->enabled) {
+		// Categories
+		print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
+		$cate_arbo = $form->select_all_categories(Categorie::TYPE_ACTIONCOMM, '', 'parent', 64, 0, 1);
+		print $form->multiselectarray('categories', $cate_arbo, GETPOST('categories', 'array'), '', 0, '', 0, '100%');
+		print "</td></tr>";
+	}
+
 	print '</table>';
 
 
@@ -1411,6 +1428,19 @@ if ($id > 0)
 			print $form->select_dolusers($object->userdoneid > 0 ? $object->userdoneid : -1, 'doneby', 1);
 			print '</td></tr>';
 		}
+		// Tags-Categories
+        if ($conf->categorie->enabled) {
+			print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
+			$cate_arbo = $form->select_all_categories(Categorie::TYPE_ACTIONCOMM, '', 'parent', 64, 0, 1);
+			$c = new Categorie($db);
+			$cats = $c->containing($object->id, Categorie::TYPE_ACTIONCOMM);
+			$arrayselected = array();
+			foreach ($cats as $cat) {
+				$arrayselected[] = $cat->id;
+			}
+			print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%');
+			print "</td></tr>";
+		}
 
 		print '</table>';
 
@@ -1717,6 +1747,12 @@ if ($id > 0)
 			}
 			print '</td></tr>';
 		}
+		// Categories
+		if ($conf->categorie->enabled) {
+			print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td colspan="3">';
+			print $form->showCategories($object->id, Categorie::TYPE_ACTIONCOMM, 1);
+			print "</td></tr>";
+		}
 
 		print '</table>';
 

+ 284 - 143
htdocs/comm/action/class/actioncomm.class.php

@@ -272,7 +272,7 @@ class ActionComm extends CommonObject
     /**
      * @var int Id of linked object
      */
-    public $fk_element;    // Id of record
+    public $fk_element; // Id of record
 
     /**
      * @var int Id of record alternative for API
@@ -302,7 +302,7 @@ class ActionComm extends CommonObject
     /**
      * @var array Actions
      */
-    public $actions=array();
+    public $actions = array();
 
     /**
      * @var string Email msgid
@@ -455,6 +455,7 @@ class ActionComm extends CommonObject
         $sql .= "durationp,"; // deprecated
         $sql .= "fk_action,";
         $sql .= "code,";
+	 	$sql .= "ref_ext,";
         $sql .= "fk_soc,";
         $sql .= "fk_project,";
         $sql .= "note,";
@@ -484,6 +485,7 @@ class ActionComm extends CommonObject
         $sql .= ((isset($this->durationp) && $this->durationp >= 0 && $this->durationp != '') ? "'".$this->db->escape($this->durationp)."'" : "null").", "; // deprecated
         $sql .= (isset($this->type_id) ? $this->type_id : "null").",";
         $sql .= ($code ? ("'".$code."'") : "null").", ";
+        $sql .= ($this->ref_ext ? ("'".$this->db->idate($this->ref_ext)."'") : "null").", ";
         $sql .= ((isset($this->socid) && $this->socid > 0) ? $this->socid : "null").", ";
         $sql .= ((isset($this->fk_project) && $this->fk_project > 0) ? $this->fk_project : "null").", ";
         $sql .= " '".$this->db->escape($this->note_private ? $this->note_private : $this->note)."', ";
@@ -839,11 +841,11 @@ class ActionComm extends CommonObject
     public function fetch_userassigned($override = true)
     {
         // phpcs:enable
-        $sql ="SELECT fk_actioncomm, element_type, fk_element, answer_status, mandatory, transparency";
-        $sql.=" FROM ".MAIN_DB_PREFIX."actioncomm_resources";
-        $sql.=" WHERE element_type = 'user' AND fk_actioncomm = ".$this->id;
+        $sql = "SELECT fk_actioncomm, element_type, fk_element, answer_status, mandatory, transparency";
+        $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm_resources";
+        $sql .= " WHERE element_type = 'user' AND fk_actioncomm = ".$this->id;
 
-        $resql2=$this->db->query($sql);
+        $resql2 = $this->db->query($sql);
         if ($resql2)
         {
             $this->userassigned = array();
@@ -894,35 +896,35 @@ class ActionComm extends CommonObject
     {
         global $user;
 
-        $error=0;
+        $error = 0;
 
         $this->db->begin();
 
         $sql = "DELETE FROM ".MAIN_DB_PREFIX."actioncomm";
-        $sql.= " WHERE id=".$this->id;
+        $sql .= " WHERE id=".$this->id;
 
         dol_syslog(get_class($this)."::delete", LOG_DEBUG);
-        $res=$this->db->query($sql);
+        $res = $this->db->query($sql);
         if ($res < 0) {
-        	$this->error=$this->db->lasterror();
+        	$this->error = $this->db->lasterror();
         	$error++;
         }
 
-        if (! $error) {
+        if (!$error) {
             $sql = "DELETE FROM ".MAIN_DB_PREFIX."actioncomm_resources";
-            $sql.= " WHERE fk_actioncomm=".$this->id;
+            $sql .= " WHERE fk_actioncomm=".$this->id;
 
             dol_syslog(get_class($this)."::delete", LOG_DEBUG);
-            $res=$this->db->query($sql);
+            $res = $this->db->query($sql);
             if ($res < 0) {
-                $this->error=$this->db->lasterror();
+                $this->error = $this->db->lasterror();
                 $error++;
             }
         }
 
         // Removed extrafields
-        if (! $error) {
-        	$result=$this->deleteExtraFields();
+        if (!$error) {
+        	$result = $this->deleteExtraFields();
           	if ($result < 0)
            	{
            		$error++;
@@ -1186,52 +1188,52 @@ class ActionComm extends CommonObject
         // phpcs:enable
         global $conf, $langs;
 
-    	if(empty($load_state_board)) $sql = "SELECT a.id, a.datep as dp";
+    	if (empty($load_state_board)) $sql = "SELECT a.id, a.datep as dp";
     	else {
-    		$this->nb=array();
+    		$this->nb = array();
     		$sql = "SELECT count(a.id) as nb";
     	}
-    	$sql.= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
-    	if (! $user->rights->societe->client->voir && ! $user->socid) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON a.fk_soc = sc.fk_soc";
-    	$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON a.fk_soc = s.rowid";
-    	$sql.= " WHERE 1 = 1";
-    	if(empty($load_state_board)) $sql.= " AND a.percent >= 0 AND a.percent < 100";
-    	$sql.= " AND a.entity IN (".getEntity('agenda').")";
-    	if (! $user->rights->societe->client->voir && ! $user->socid) $sql.= " AND (a.fk_soc IS NULL OR sc.fk_user = " .$user->id . ")";
-    	if ($user->socid) $sql.=" AND a.fk_soc = ".$user->socid;
-    	if (! $user->rights->agenda->allactions->read) $sql.= " AND (a.fk_user_author = ".$user->id . " OR a.fk_user_action = ".$user->id . " OR a.fk_user_done = ".$user->id . ")";
-
-    	$resql=$this->db->query($sql);
+    	$sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
+    	if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON a.fk_soc = sc.fk_soc";
+    	$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON a.fk_soc = s.rowid";
+    	$sql .= " WHERE 1 = 1";
+    	if (empty($load_state_board)) $sql .= " AND a.percent >= 0 AND a.percent < 100";
+    	$sql .= " AND a.entity IN (".getEntity('agenda').")";
+    	if (!$user->rights->societe->client->voir && !$user->socid) $sql .= " AND (a.fk_soc IS NULL OR sc.fk_user = ".$user->id.")";
+    	if ($user->socid) $sql .= " AND a.fk_soc = ".$user->socid;
+    	if (!$user->rights->agenda->allactions->read) $sql .= " AND (a.fk_user_author = ".$user->id." OR a.fk_user_action = ".$user->id." OR a.fk_user_done = ".$user->id.")";
+
+    	$resql = $this->db->query($sql);
     	if ($resql)
     	{
-    		if(empty($load_state_board)) {
+    		if (empty($load_state_board)) {
 	    		$agenda_static = new ActionComm($this->db);
 	    		$response = new WorkboardResponse();
-	    		$response->warning_delay = $conf->agenda->warning_delay/60/60/24;
+	    		$response->warning_delay = $conf->agenda->warning_delay / 60 / 60 / 24;
 	    		$response->label = $langs->trans("ActionsToDo");
 	    		$response->labelShort = $langs->trans("ActionsToDoShort");
 	    		$response->url = DOL_URL_ROOT.'/comm/action/list.php?actioncode=0&amp;status=todo&amp;mainmenu=agenda';
-	    		if ($user->rights->agenda->allactions->read) $response->url.='&amp;filtert=-1';
+	    		if ($user->rights->agenda->allactions->read) $response->url .= '&amp;filtert=-1';
 	    		$response->img = img_object('', "action", 'class="inline-block valigntextmiddle"');
     		}
     		// This assignment in condition is not a bug. It allows walking the results.
-    		while ($obj=$this->db->fetch_object($resql))
+    		while ($obj = $this->db->fetch_object($resql))
     		{
-    			if(empty($load_state_board)) {
+    			if (empty($load_state_board)) {
 	    			$response->nbtodo++;
 	    			$agenda_static->datep = $this->db->jdate($obj->dp);
 	    			if ($agenda_static->hasDelay()) $response->nbtodolate++;
-    			} else $this->nb["actionscomm"]=$obj->nb;
+    			} else $this->nb["actionscomm"] = $obj->nb;
     		}
 
     		$this->db->free($resql);
-    		if(empty($load_state_board)) return $response;
+    		if (empty($load_state_board)) return $response;
     		else return 1;
     	}
     	else
     	{
     		dol_print_error($this->db);
-    		$this->error=$this->db->error();
+    		$this->error = $this->db->error();
     		return -1;
     	}
     }
@@ -1378,13 +1380,13 @@ class ActionComm extends CommonObject
      *  Return URL of event
      *  Use $this->id, $this->type_code, $this->label and $this->type_label
      *
-     *  @param	int		$withpicto				0=No picto, 1=Include picto into link, 2=Only picto
+     *  @param	int		$withpicto				0 = No picto, 1 = Include picto into link, 2 = Only picto
      *  @param	int		$maxlength				Max number of charaters into label. If negative, use the ref as label.
      *  @param	string	$classname				Force style class on a link
-     *  @param	string	$option					''=Link to action, 'birthday'=Link to contact
-     *  @param	int		$overwritepicto			1=Overwrite picto
-     *  @param	int   	$notooltip		    	1=Disable tooltip
-     *  @param  int     $save_lastsearch_value  -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
+     *  @param	string	$option					'' = Link to action, 'birthday'= Link to contact, 'holiday' = Link to leave
+     *  @param	int		$overwritepicto			1 = Overwrite picto
+     *  @param	int   	$notooltip		    	1 = Disable tooltip
+     *  @param  int     $save_lastsearch_value  -1 = Auto, 0 = No save of lastsearch_values when clicking, 1 = Save lastsearch_values whenclicking
      *  @return	string							Chaine avec URL
      */
     public function getNomUrl($withpicto = 0, $maxlength = 0, $classname = '', $option = '', $overwritepicto = 0, $notooltip = 0, $save_lastsearch_value = -1)
@@ -1394,10 +1396,10 @@ class ActionComm extends CommonObject
         if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips
 
 		$canread = 0;
-		if ($user->rights->agenda->myactions->read && $this->authorid == $user->id) $canread = 1;	// Can read my event
-		if ($user->rights->agenda->myactions->read && array_key_exists($user->id, $this->userassigned)) $canread = 1;	// Can read my event i am assigned
-		if ($user->rights->agenda->allactions->read) $canread = 1;		// Can read all event of other
-		if (! $canread)
+		if ($user->rights->agenda->myactions->read && $this->authorid == $user->id) $canread = 1; // Can read my event
+		if ($user->rights->agenda->myactions->read && array_key_exists($user->id, $this->userassigned)) $canread = 1; // Can read my event i am assigned
+		if ($user->rights->agenda->allactions->read) $canread = 1; // Can read all event of other
+		if (!$canread)
 		{
             $option = 'nolink';
 		}
@@ -1455,6 +1457,8 @@ class ActionComm extends CommonObject
 		$url = '';
 		if ($option == 'birthday')
 			$url = DOL_URL_ROOT.'/contact/perso.php?id='.$this->id;
+		elseif ($option == 'holiday')
+            $url = DOL_URL_ROOT.'/holiday/card.php?id='.$this->id;
 		else
 			$url = DOL_URL_ROOT.'/comm/action/card.php?id='.$this->id;
 		if ($option !== 'nolink')
@@ -1514,21 +1518,66 @@ class ActionComm extends CommonObject
         return $result;
     }
 
+    /**
+     * Sets object to supplied categories.
+     *
+     * Deletes object from existing categories not supplied.
+     * Adds it to non existing supplied categories.
+     * Existing categories are left untouch.
+     *
+     * @param  int[]|int $categories Category or categories IDs
+     * @return void
+     */
+    public function setCategories($categories)
+    {
+        // Handle single category
+        if (!is_array($categories)) {
+            $categories = array($categories);
+        }
+
+        // Get current categories
+        include_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
+        $c = new Categorie($this->db);
+        $existing = $c->containing($this->id, Categorie::TYPE_ACTIONCOMM, 'id');
+
+        // Diff
+        if (is_array($existing)) {
+            $to_del = array_diff($existing, $categories);
+            $to_add = array_diff($categories, $existing);
+        } else {
+            $to_del = array(); // Nothing to delete
+            $to_add = $categories;
+        }
+
+        // Process
+        foreach ($to_del as $del) {
+            if ($c->fetch($del) > 0) {
+                $c->del_type($this, Categorie::TYPE_ACTIONCOMM);
+            }
+        }
+        foreach ($to_add as $add) {
+            if ($c->fetch($add) > 0) {
+                $c->add_type($this, Categorie::TYPE_ACTIONCOMM);
+            }
+        }
+        return;
+    }
 
     // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
     /**
-     *		Export events from database into a cal file.
+     * Export events from database into a cal file.
      *
-     *		@param	string		$format			'vcal', 'ical/ics', 'rss'
-     *		@param	string		$type			'event' or 'journal'
-     *		@param	int			$cachedelay		Do not rebuild file if date older than cachedelay seconds
-     *		@param	string		$filename		Force filename
-     *		@param	array		$filters		Array of filters. Exemple array('notolderthan'=>99, 'year'=>..., 'idfrom'=>..., 'notactiontype'=>'systemauto', 'project'=>123, ...)
-     *		@return int     					<0 if error, nb of events in new file if ok
-     */
-    public function build_exportfile($format, $type, $cachedelay, $filename, $filters)
+     * @param string    $format         The format of the export 'vcal', 'ical/ics' or 'rss'
+     * @param string    $type           The type of the export 'event' or 'journal'
+     * @param integer   $cachedelay     Do not rebuild file if date older than cachedelay seconds
+     * @param string    $filename       The name for the exported file.
+     * @param array     $filters        Array of filters. Example array('notolderthan'=>99, 'year'=>..., 'idfrom'=>..., 'notactiontype'=>'systemauto', 'project'=>123, ...)
+     * @param integer   $exportholiday  0 = don't integrate holidays into the export, 1 = integrate holidays into the export
+     * @return integer                  -1 = error on build export file, 0 = export okay
+     */
+    public function build_exportfile($format, $type, $cachedelay, $filename, $filters, $exportholiday = 0)
     {
-    	global $hookmanager;
+        global $hookmanager;
 
         // phpcs:enable
         global $conf, $langs, $dolibarr_main_url_root, $mysoc;
@@ -1575,105 +1624,105 @@ class ActionComm extends CommonObject
         if ($buildfile)
         {
             // Build event array
-            $eventarray=array();
+            $eventarray = array();
 
             $sql = "SELECT a.id,";
-            $sql.= " a.datep,";		// Start
-            $sql.= " a.datep2,";	// End
-            $sql.= " a.durationp,";			// deprecated
-            $sql.= " a.datec, a.tms as datem,";
-            $sql.= " a.label, a.code, a.note, a.fk_action as type_id,";
-            $sql.= " a.fk_soc,";
-            $sql.= " a.fk_user_author, a.fk_user_mod,";
-            $sql.= " a.fk_user_action,";
-            $sql.= " a.fk_contact, a.percent as percentage,";
-            $sql.= " a.fk_element, a.elementtype,";
-            $sql.= " a.priority, a.fulldayevent, a.location, a.punctual, a.transparency,";
-            $sql.= " u.firstname, u.lastname, u.email,";
-            $sql.= " s.nom as socname,";
-            $sql.= " c.id as type_id, c.code as type_code, c.libelle as type_label";
-            $sql.= " FROM (".MAIN_DB_PREFIX."c_actioncomm as c, ".MAIN_DB_PREFIX."actioncomm as a)";
-            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_author";	// Link to get author of event for export
-            $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on s.rowid = a.fk_soc";
-
-			$parameters=array('filters' => $filters);
-			$reshook=$hookmanager->executeHooks('printFieldListFrom', $parameters);    // Note that $action and $object may have been modified by hook
-			$sql.=$hookmanager->resPrint;
+            $sql .= " a.datep,"; // Start
+            $sql .= " a.datep2,"; // End
+            $sql .= " a.durationp,"; // deprecated
+            $sql .= " a.datec, a.tms as datem,";
+            $sql .= " a.label, a.code, a.note, a.fk_action as type_id,";
+            $sql .= " a.fk_soc,";
+            $sql .= " a.fk_user_author, a.fk_user_mod,";
+            $sql .= " a.fk_user_action,";
+            $sql .= " a.fk_contact, a.percent as percentage,";
+            $sql .= " a.fk_element, a.elementtype,";
+            $sql .= " a.priority, a.fulldayevent, a.location, a.punctual, a.transparency,";
+            $sql .= " u.firstname, u.lastname, u.email,";
+            $sql .= " s.nom as socname,";
+            $sql .= " c.id as type_id, c.code as type_code, c.libelle as type_label";
+            $sql .= " FROM (".MAIN_DB_PREFIX."c_actioncomm as c, ".MAIN_DB_PREFIX."actioncomm as a)";
+            $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_author"; // Link to get author of event for export
+            $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on s.rowid = a.fk_soc";
+
+			$parameters = array('filters' => $filters);
+			$reshook = $hookmanager->executeHooks('printFieldListFrom', $parameters); // Note that $action and $object may have been modified by hook
+			$sql .= $hookmanager->resPrint;
 
 			// We must filter on assignement table
-			if ($filters['logint']) $sql.=", ".MAIN_DB_PREFIX."actioncomm_resources as ar";
-			$sql.= " WHERE a.fk_action=c.id";
-            $sql.= " AND a.entity IN (".getEntity('agenda').")";
+			if ($filters['logint']) $sql .= ", ".MAIN_DB_PREFIX."actioncomm_resources as ar";
+			$sql .= " WHERE a.fk_action=c.id";
+            $sql .= " AND a.entity IN (".getEntity('agenda').")";
             foreach ($filters as $key => $value)
             {
-                if ($key == 'notolderthan' && $value != '') $sql.=" AND a.datep >= '".$this->db->idate($now-($value*24*60*60))."'";
-                if ($key == 'year')         $sql.=" AND a.datep BETWEEN '".$this->db->idate(dol_get_first_day($value, 1))."' AND '".$this->db->idate(dol_get_last_day($value, 12))."'";
-                if ($key == 'id')           $sql.=" AND a.id=".(is_numeric($value)?$value:0);
-                if ($key == 'idfrom')       $sql.=" AND a.id >= ".(is_numeric($value)?$value:0);
-                if ($key == 'idto')         $sql.=" AND a.id <= ".(is_numeric($value)?$value:0);
-                if ($key == 'project')      $sql.=" AND a.fk_project=".(is_numeric($value)?$value:0);
-                if ($key == 'actiontype')    $sql.=" AND c.type = '".$this->db->escape($value)."'";
-                if ($key == 'notactiontype') $sql.=" AND c.type <> '".$this->db->escape($value)."'";
+                if ($key == 'notolderthan' && $value != '') $sql .= " AND a.datep >= '".$this->db->idate($now - ($value * 24 * 60 * 60))."'";
+                if ($key == 'year')         $sql .= " AND a.datep BETWEEN '".$this->db->idate(dol_get_first_day($value, 1))."' AND '".$this->db->idate(dol_get_last_day($value, 12))."'";
+                if ($key == 'id')           $sql .= " AND a.id=".(is_numeric($value) ? $value : 0);
+                if ($key == 'idfrom')       $sql .= " AND a.id >= ".(is_numeric($value) ? $value : 0);
+                if ($key == 'idto')         $sql .= " AND a.id <= ".(is_numeric($value) ? $value : 0);
+                if ($key == 'project')      $sql .= " AND a.fk_project=".(is_numeric($value) ? $value : 0);
+                if ($key == 'actiontype')    $sql .= " AND c.type = '".$this->db->escape($value)."'";
+                if ($key == 'notactiontype') $sql .= " AND c.type <> '".$this->db->escape($value)."'";
                 // We must filter on assignement table
-				if ($key == 'logint')       $sql.= " AND ar.fk_actioncomm = a.id AND ar.element_type='user'";
+				if ($key == 'logint')       $sql .= " AND ar.fk_actioncomm = a.id AND ar.element_type='user'";
                 if ($key == 'logina')
                 {
-                    $logina=$value;
-                    $condition='=';
+                    $logina = $value;
+                    $condition = '=';
                     if (preg_match('/^!/', $logina))
                     {
-                        $logina=preg_replace('/^!/', '', $logina);
-                        $condition='<>';
+                        $logina = preg_replace('/^!/', '', $logina);
+                        $condition = '<>';
                     }
-                    $userforfilter=new User($this->db);
-                    $result=$userforfilter->fetch('', $logina);
-                    if ($result > 0) $sql.= " AND a.fk_user_author ".$condition." ".$userforfilter->id;
-                    elseif ($result < 0 || $condition == '=') $sql.= " AND a.fk_user_author = 0";
+                    $userforfilter = new User($this->db);
+                    $result = $userforfilter->fetch('', $logina);
+                    if ($result > 0) $sql .= " AND a.fk_user_author ".$condition." ".$userforfilter->id;
+                    elseif ($result < 0 || $condition == '=') $sql .= " AND a.fk_user_author = 0";
                 }
                 if ($key == 'logint')
                 {
-                    $logint=$value;
-                    $condition='=';
+                    $logint = $value;
+                    $condition = '=';
                     if (preg_match('/^!/', $logint))
                     {
-                        $logint=preg_replace('/^!/', '', $logint);
-                        $condition='<>';
+                        $logint = preg_replace('/^!/', '', $logint);
+                        $condition = '<>';
                     }
-                    $userforfilter=new User($this->db);
-                    $result=$userforfilter->fetch('', $logint);
-                    if ($result > 0) $sql.= " AND ar.fk_element = ".$userforfilter->id;
-                    elseif ($result < 0 || $condition == '=') $sql.= " AND ar.fk_element = 0";
+                    $userforfilter = new User($this->db);
+                    $result = $userforfilter->fetch('', $logint);
+                    if ($result > 0) $sql .= " AND ar.fk_element = ".$userforfilter->id;
+                    elseif ($result < 0 || $condition == '=') $sql .= " AND ar.fk_element = 0";
                 }
             }
 
-            $sql.= " AND a.datep IS NOT NULL";		// To exclude corrupted events and avoid errors in lightning/sunbird import
+            $sql .= " AND a.datep IS NOT NULL"; // To exclude corrupted events and avoid errors in lightning/sunbird import
 
-			$parameters=array('filters' => $filters);
-			$reshook=$hookmanager->executeHooks('printFieldListWhere', $parameters);    // Note that $action and $object may have been modified by hook
-			$sql.=$hookmanager->resPrint;
+			$parameters = array('filters' => $filters);
+			$reshook = $hookmanager->executeHooks('printFieldListWhere', $parameters); // Note that $action and $object may have been modified by hook
+			$sql .= $hookmanager->resPrint;
 
-            $sql.= " ORDER by datep";
+            $sql .= " ORDER by datep";
             //print $sql;exit;
 
             dol_syslog(get_class($this)."::build_exportfile select events", LOG_DEBUG);
-            $resql=$this->db->query($sql);
+            $resql = $this->db->query($sql);
             if ($resql)
             {
                 // Note: Output of sql request is encoded in $conf->file->character_set_client
                 // This assignment in condition is not a bug. It allows walking the results.
 				$diff = 0;
-                while ($obj=$this->db->fetch_object($resql))
+                while ($obj = $this->db->fetch_object($resql))
                 {
-                    $qualified=true;
+                    $qualified = true;
 
                     // 'eid','startdate','duration','enddate','title','summary','category','email','url','desc','author'
-                    $event=array();
-                    $event['uid']='dolibarragenda-'.$this->db->database_name.'-'.$obj->id."@".$_SERVER["SERVER_NAME"];
-                    $event['type']=$type;
-                    $datestart=$this->db->jdate($obj->datep)-(empty($conf->global->AGENDA_EXPORT_FIX_TZ)?0:($conf->global->AGENDA_EXPORT_FIX_TZ*3600));
+                    $event = array();
+                    $event['uid'] = 'dolibarragenda-'.$this->db->database_name.'-'.$obj->id."@".$_SERVER["SERVER_NAME"];
+                    $event['type'] = $type;
+                    $datestart = $this->db->jdate($obj->datep) - (empty($conf->global->AGENDA_EXPORT_FIX_TZ) ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
 
                     // fix for -> Warning: A non-numeric value encountered
-                    if(is_numeric($this->db->jdate($obj->datep2)))
+                    if (is_numeric($this->db->jdate($obj->datep2)))
                     {
                         $dateend = $this->db->jdate($obj->datep2)
                                  - (empty($conf->global->AGENDA_EXPORT_FIX_TZ) ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
@@ -1684,28 +1733,28 @@ class ActionComm extends CommonObject
                         $dateend = $datestart;
                     }
 
-                    $duration=($datestart && $dateend)?($dateend - $datestart):0;
-                    $event['summary']=$obj->label.($obj->socname?" (".$obj->socname.")":"");
-                    $event['desc']=$obj->note;
-                    $event['startdate']=$datestart;
-                    $event['enddate']=$dateend;		// Not required with type 'journal'
-                    $event['duration']=$duration;	// Not required with type 'journal'
-                    $event['author']=dolGetFirstLastname($obj->firstname, $obj->lastname);
-                    $event['priority']=$obj->priority;
-                    $event['fulldayevent']=$obj->fulldayevent;
-                    $event['location']=$obj->location;
-                    $event['transparency']=(($obj->transparency > 0)?'OPAQUE':'TRANSPARENT');		// OPAQUE (busy) or TRANSPARENT (not busy)
-                    $event['punctual']=$obj->punctual;
-                    $event['category']=$obj->type_label;
-                    $event['email']=$obj->email;
+                    $duration = ($datestart && $dateend) ? ($dateend - $datestart) : 0;
+                    $event['summary'] = $obj->label.($obj->socname ? " (".$obj->socname.")" : "");
+                    $event['desc'] = $obj->note;
+                    $event['startdate'] = $datestart;
+                    $event['enddate'] = $dateend; // Not required with type 'journal'
+                    $event['duration'] = $duration; // Not required with type 'journal'
+                    $event['author'] = dolGetFirstLastname($obj->firstname, $obj->lastname);
+                    $event['priority'] = $obj->priority;
+                    $event['fulldayevent'] = $obj->fulldayevent;
+                    $event['location'] = $obj->location;
+                    $event['transparency'] = (($obj->transparency > 0) ? 'OPAQUE' : 'TRANSPARENT'); // OPAQUE (busy) or TRANSPARENT (not busy)
+                    $event['punctual'] = $obj->punctual;
+                    $event['category'] = $obj->type_label;
+                    $event['email'] = $obj->email;
 					// Define $urlwithroot
-					$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
-					$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;			// This is to use external domain name found into config file
+					$urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
+					$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=$urlwithroot.'/comm/action/card.php?id='.$obj->id;
-                    $event['url']=$url;
-                    $event['created']=$this->db->jdate($obj->datec)-(empty($conf->global->AGENDA_EXPORT_FIX_TZ)?0:($conf->global->AGENDA_EXPORT_FIX_TZ*3600));
-                    $event['modified']=$this->db->jdate($obj->datem)-(empty($conf->global->AGENDA_EXPORT_FIX_TZ)?0:($conf->global->AGENDA_EXPORT_FIX_TZ*3600));
+                    $url = $urlwithroot.'/comm/action/card.php?id='.$obj->id;
+                    $event['url'] = $url;
+                    $event['created'] = $this->db->jdate($obj->datec) - (empty($conf->global->AGENDA_EXPORT_FIX_TZ) ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
+                    $event['modified'] = $this->db->jdate($obj->datem) - (empty($conf->global->AGENDA_EXPORT_FIX_TZ) ? 0 : ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600));
 
                     // TODO: find a way to call "$this->fetch_userassigned();" without override "$this" properties
                     $this->id = $obj->id;
@@ -1713,22 +1762,29 @@ class ActionComm extends CommonObject
 
                     $assignedUserArray = array();
 
-                    foreach($this->userassigned as $key => $value)
+                    foreach ($this->userassigned as $key => $value)
                     {
                         $assignedUser = new User($this->db);
                         $assignedUser->fetch($value['id']);
 
-                        $assignedUserArray[$key]=$assignedUser;
+                        $assignedUserArray[$key] = $assignedUser;
                     }
 
-                    $event['assignedUsers']=$assignedUserArray;
+                    $event['assignedUsers'] = $assignedUserArray;
 
                     if ($qualified && $datestart)
                     {
-                        $eventarray[]=$event;
+                        $eventarray[] = $event;
                     }
                     $diff++;
                 }
+
+				$parameters = array('filters' => $filters, 'eventarray' => &$eventarray);
+				$reshook = $hookmanager->executeHooks('addMoreEventsExport', $parameters); // Note that $action and $object may have been modified by hook
+				if ($reshook > 0)
+				{
+					$eventarray = $hookmanager->resArray;
+				}
             }
             else
             {
@@ -1736,6 +1792,91 @@ class ActionComm extends CommonObject
                 return -1;
             }
 
+			if($exportholiday == 1)
+            {
+                $langs->load("holidays");
+                $title = $langs->trans("Holidays");
+
+                $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.email, u.statut, x.rowid, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.statut as status";
+                $sql.= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u";
+                $sql.= " WHERE u.rowid = x.fk_user";
+                $sql.= " AND u.statut = '1'";                           // Show only active users  (0 = inactive user, 1 = active user)
+                $sql.= " AND (x.statut = '2' OR x.statut = '3')";       // Show only public leaves (2 = leave wait for approval, 3 = leave approved)
+
+                $resql=$this->db->query($sql);
+                if ($resql)
+                {
+                    $num = $this->db->num_rows($resql);
+                    $i   = 0;
+
+                    while ($i < $num)
+                    {
+                        $obj   = $this->db->fetch_object($resql);
+                        $event = array();
+
+                        if($obj->halfday == -1)
+                        {
+                            $event['fulldayevent'] = false;
+
+                            $timestampStart = dol_stringtotime($obj->date_start." 00:00:00", 0);
+                            $timestampEnd   = dol_stringtotime($obj->date_end." 12:00:00", 0);
+                        }
+                        elseif($obj->halfday == 1)
+                        {
+                            $event['fulldayevent'] = false;
+
+                            $timestampStart = dol_stringtotime($obj->date_start." 12:00:00", 0);
+                            $timestampEnd   = dol_stringtotime($obj->date_end." 23:59:59", 0);
+                        }
+                        else
+                        {
+                            $event['fulldayevent'] = true;
+
+                            $timestampStart = dol_stringtotime($obj->date_start." 00:00:00", 0);
+                            $timestampEnd   = dol_stringtotime($obj->date_end." 23:59:59", 0);
+                        }
+
+                        if(!empty($conf->global->AGENDA_EXPORT_FIX_TZ))
+                        {
+                            $timestampStart =- ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600);
+                            $timestampEnd   =- ($conf->global->AGENDA_EXPORT_FIX_TZ * 3600);
+                        }
+
+                        $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
+                        $urlwithroot       = $urlwithouturlroot.DOL_URL_ROOT;
+                        $url               = $urlwithroot.'/holiday/card.php?id='.$obj->rowid;
+
+                        $event['uid']          = 'dolibarrholiday-'.$this->db->database_name.'-'.$obj->rowid."@".$_SERVER["SERVER_NAME"];
+                        $event['author']       = dolGetFirstLastname($obj->firstname, $obj->lastname);
+                        $event['type']         = 'event';
+                        $event['category']     = "Holiday";
+                        $event['transparency'] = 'OPAQUE';
+                        $event['email']        = $obj->email;
+                        $event['created']      = $timestampStart;
+                        $event['modified']     = $timestampStart;
+                        $event['startdate']    = $timestampStart;
+                        $event['enddate']      = $timestampEnd;
+                        $event['duration']     = $timestampEnd - $timestampStart;
+                        $event['url']          = $url;
+
+                        if($obj->status == 2)
+                        {
+                            // 2 = leave wait for approval
+                            $event['summary'] = $title." - ".$obj->lastname." (wait for approval)";
+                        }
+                        else
+                        {
+                            // 3 = leave approved
+                            $event['summary'] = $title." - ".$obj->lastname;
+                        }
+
+                        $eventarray[] = $event;
+
+                        $i++;
+                    }
+                }
+            }
+
             $langs->load("agenda");
 
             // Define title and desc

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

@@ -757,6 +757,95 @@ if ($showbirthday)
     }
 }
 
+if ($conf->global->AGENDA_SHOW_HOLIDAYS)
+{
+    $sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.statut, x.rowid, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.statut as status";
+    $sql .= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u";
+    $sql .= " WHERE u.rowid = x.fk_user";
+    $sql .= " AND u.statut = '1'"; // Show only active users  (0 = inactive user, 1 = active user)
+    $sql .= " AND (x.statut = '2' OR x.statut = '3')"; // Show only public leaves (2 = leave wait for approval, 3 = leave approved)
+
+    if ($action == 'show_day')
+    {
+        // Request only leaves for the current selected day
+        $sql .= " AND '".$year."-".$month."-".$day."' BETWEEN x.date_debut AND x.date_fin";
+    }
+    elseif ($action == 'show_week')
+    {
+        // TODO: Add filter to reduce database request
+    }
+    elseif ($action == 'show_month')
+    {
+        // TODO: Add filter to reduce database request
+    }
+
+    $resql = $db->query($sql);
+    if ($resql)
+    {
+        $num = $db->num_rows($resql);
+        $i   = 0;
+
+        while ($i < $num)
+        {
+            $obj = $db->fetch_object($resql);
+
+            $dateStartArray = dol_getdate(dol_stringtotime($obj->date_start, 1), true);
+            $dateEndArray   = dol_getdate(dol_stringtotime($obj->date_end, 1), true);
+
+            $event = new ActionComm($db);
+
+            // Need the id of the leave object for link to it
+            $event->id                      = $obj->rowid;
+
+            $event->type_code               = 'HOLIDAY';
+            $event->datep                   = dol_mktime(0, 0, 0, $dateStartArray['mon'], $dateStartArray['mday'], $dateStartArray['year'], true);
+            $event->datef                   = dol_mktime(0, 0, 0, $dateEndArray['mon'], $dateEndArray['mday'], $dateEndArray['year'], true);
+            $event->date_start_in_calendar  = $event->datep;
+            $event->date_end_in_calendar    = $event->datef;
+
+            if ($obj->status == 3)
+            {
+                // Show no symbol for leave with state "leave approved"
+                $event->percentage = -1;
+            }
+            elseif ($obj->status == 2)
+            {
+                // Show TO-DO symbol for leave with state "leave wait for approval"
+                $event->percentage = 0;
+            }
+
+            if ($obj->halfday == 1)
+            {
+                $event->label = $obj->lastname.' ('.$langs->trans("Morning").')';
+            }
+            elseif ($obj->halfday == -1)
+            {
+                $event->label = $obj->lastname.' ('.$langs->trans("Afternoon").')';
+            }
+            else
+            {
+                $event->label = $obj->lastname;
+            }
+
+            $annee  = date('Y', $event->date_start_in_calendar);
+            $mois   = date('m', $event->date_start_in_calendar);
+            $jour   = date('d', $event->date_start_in_calendar);
+            $daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee);
+
+            do
+            {
+                $eventarray[$daykey][] = $event;
+
+                $daykey += 60 * 60 * 24;
+            }
+
+            while ($daykey <= $event->date_end_in_calendar);
+
+            $i++;
+        }
+    }
+}
+
 // Complete $eventarray with external import Ical
 if (count($listofextcals))
 {
@@ -1512,7 +1601,11 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                     {
                         print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'birthday', 'contact');
                     }
-                    if ($event->type_code != 'BIRTHDAY')
+					elseif ($event->type_code == 'HOLIDAY')
+                    {
+                        print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'holiday', 'user');
+                    }
+                    elseif ($event->type_code != 'BIRTHDAY' && $event->type_code != 'HOLIDAY')
                     {
                         // Picto
                         if (empty($event->fulldayevent))
@@ -1741,6 +1834,17 @@ function dol_color_minus($color, $minus, $minusunit = 16)
  */
 function sort_events_by_date($a, $b)
 {
+	// Sort holidays at first
+    if ($a->type_code === 'HOLIDAY')
+    {
+        return -1;
+    }
+
+    if ($b->type_code === 'HOLIDAY')
+    {
+        return 1;
+    }
+
     // datep => Event start time
     // datef => Event end time
 

+ 1 - 1
htdocs/comm/action/list.php

@@ -554,7 +554,7 @@ if ($resql)
 		$actionstatic->type_picto = $obj->type_picto;
 		$actionstatic->label = $obj->label;
 		$actionstatic->location = $obj->location;
-		$actionstatic->note = dol_htmlentitiesbr($obj->note);			// deprecated
+		$actionstatic->note = dol_htmlentitiesbr($obj->note); // deprecated
 		$actionstatic->note_public = dol_htmlentitiesbr($obj->note);
 
 		$actionstatic->fetchResources();

+ 5 - 5
htdocs/comm/card.php

@@ -491,7 +491,7 @@ if ($object->id > 0)
 		$langs->load("categories");
 		print '<tr><td>'.$langs->trans("CustomersCategoriesShort").'</td>';
 		print '<td>';
-		print $form->showCategories($object->id, 'customer', 1);
+		print $form->showCategories($object->id, Categorie::TYPE_CUSTOMER, 1);
 		print "</td></tr>";
 	}
 
@@ -1032,7 +1032,7 @@ if ($object->id > 0)
 	 */
 	if (!empty($conf->facture->enabled) && $user->rights->facture->lire)
 	{
-		$sql = 'SELECT f.rowid as id, f.titre as ref, f.amount';
+		$sql = 'SELECT f.rowid as id, f.titre as ref';
 		$sql .= ', f.total as total_ht';
 		$sql .= ', f.tva as total_tva';
 		$sql .= ', f.total_ttc';
@@ -1045,7 +1045,7 @@ if ($object->id > 0)
 		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture_rec as f";
 		$sql .= " WHERE f.fk_soc = s.rowid AND s.rowid = ".$object->id;
 		$sql .= " AND f.entity = ".$conf->entity;
-		$sql .= ' GROUP BY f.rowid, f.titre, f.amount, f.total, f.tva, f.total_ttc,';
+		$sql .= ' GROUP BY f.rowid, f.titre, f.total, f.tva, f.total_ttc,';
 		$sql .= ' f.date_last_gen, f.datec, f.frequency, f.unit_frequency,';
 		$sql .= ' f.suspended, f.date_when,';
 		$sql .= ' s.nom, s.rowid';
@@ -1140,7 +1140,7 @@ if ($object->id > 0)
 	 */
 	if (!empty($conf->facture->enabled) && $user->rights->facture->lire)
 	{
-        $sql = 'SELECT f.rowid as facid, f.ref, f.type, f.amount';
+        $sql = 'SELECT f.rowid as facid, f.ref, f.type';
         $sql .= ', f.total as total_ht';
         $sql .= ', f.tva as total_tva';
         $sql .= ', f.total_ttc';
@@ -1151,7 +1151,7 @@ if ($object->id > 0)
 		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'paiement_facture as pf ON f.rowid=pf.fk_facture';
 		$sql .= " WHERE f.fk_soc = s.rowid AND s.rowid = ".$object->id;
 		$sql .= " AND f.entity IN (".getEntity('invoice').")";
-		$sql .= ' GROUP BY f.rowid, f.ref, f.type, f.amount, f.total, f.tva, f.total_ttc,';
+		$sql .= ' GROUP BY f.rowid, f.ref, f.type, f.total, f.tva, f.total_ttc,';
 		$sql .= ' f.datef, f.datec, f.paye, f.fk_statut,';
 		$sql .= ' s.nom, s.rowid';
 		$sql .= " ORDER BY f.datef DESC, f.datec DESC";

+ 1 - 1
htdocs/comm/index.php

@@ -636,7 +636,7 @@ if (!empty($conf->contrat->enabled) && $user->rights->contrat->lire && 0) // TOD
 
 	$sql = "SELECT s.nom as name, s.rowid, s.canvas, ";
     $sql .= ", s.code_client";
-	$sql .= " c.statut, c.rowid as contratid, p.ref, c.mise_en_service as datemes, c.fin_validite as datefin, c.date_cloture as dateclo";
+	$sql .= " c.statut, c.rowid as contratid, p.ref, c.fin_validite as datefin, c.date_cloture as dateclo";
 	$sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
 	$sql .= ", ".MAIN_DB_PREFIX."contrat as c";
 	$sql .= ", ".MAIN_DB_PREFIX."product as p";

+ 42 - 18
htdocs/comm/propal/class/propal.class.php

@@ -810,7 +810,7 @@ class Propal extends CommonObject
 
 			if (is_array($array_options) && count($array_options) > 0) {
 				// We replace values in this->line->array_options only for entries defined into $array_options
-				foreach($array_options as $key => $value) {
+				foreach ($array_options as $key => $value) {
 					$this->line->array_options[$key] = $array_options[$key];
 				}
 			}
@@ -3549,10 +3549,10 @@ class Propal extends CommonObject
 	 *	@param      string	$get_params    	          Parametres added to url
 	 *  @param	    int   	$notooltip		          1=Disable tooltip
 	 *  @param      int     $save_lastsearch_value    -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
-	 *  @param		int		$addlinktonotes			  Add linkt to notes
+     *  @param      int     $addlinktonotes           -1=Disable, 0=Just add label show notes, 1=Add private note (only internal user), 2=Add public note (internal or external user), 3=Add private (internal user) and public note (internal and external user)
 	 *	@return     string          		          String with URL
 	 */
-    public function getNomUrl($withpicto = 0, $option = '', $get_params = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = 0)
+    public function getNomUrl($withpicto = 0, $option = '', $get_params = '', $notooltip = 0, $save_lastsearch_value = -1, $addlinktonotes = -1)
 	{
 		global $langs, $conf, $user;
 
@@ -3618,21 +3618,45 @@ class Propal extends CommonObject
 		if ($withpicto != 2) $result .= $this->ref;
 		$result .= $linkend;
 
-		if ($addlinktonotes)
-		{
-			$txttoshow = ($user->socid > 0 ? $this->note_public : $this->note_private);
-			if ($txttoshow)
-			{
-				$notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($txttoshow, 1);
-				$result .= ' <span class="note inline-block">';
-				$result .= '<a href="'.DOL_URL_ROOT.'/comm/propal/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
-				$result .= img_picto('', 'note');
-				$result .= '</a>';
-				//$result.=img_picto($langs->trans("ViewNote"),'object_generic');
-				//$result.='</a>';
-				$result .= '</span>';
-			}
-		}
+        if ($addlinktonotes >= 0) {
+            $txttoshow = '';
+
+            if ($addlinktonotes == 0) {
+                if (!empty($this->note_private) || !empty($this->note_public)) {
+                    $txttoshow = $langs->trans('ViewPrivateNote');
+                }
+            } elseif ($addlinktonotes == 1) {
+                if (!empty($this->note_private)) {
+                    $txttoshow .= ($user->socid > 0 ? '' : dol_string_nohtmltag($this->note_private, 1));
+                }
+            } elseif ($addlinktonotes == 2) {
+                if (!empty($this->note_public)) {
+                    $txttoshow .= dol_string_nohtmltag($this->note_public, 1);
+                }
+            } elseif ($addlinktonotes == 3) {
+                if ($user->socid > 0) {
+                    if (!empty($this->note_public)) {
+                        $txttoshow .= dol_string_nohtmltag($this->note_public, 1);
+                    }
+                } else {
+                    if (!empty($this->note_public)) {
+                        $txttoshow .= dol_string_nohtmltag($this->note_public, 1);
+                    }
+                    if (!empty($this->note_private)) {
+                        if (!empty($txttoshow)) $txttoshow .= '<br><br>';
+                        $txttoshow .= dol_string_nohtmltag($this->note_private, 1);
+                    }
+                }
+            }
+
+            if ($txttoshow) {
+                $result .= ' <span class="note inline-block">';
+                $result .= '<a href="'.DOL_URL_ROOT.'/comm/propal/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($txttoshow).'">';
+                $result .= img_picto('', 'note');
+                $result .= '</a>';
+                $result .= '</span>';
+            }
+        }
 
 		return $result;
 	}

+ 131 - 120
htdocs/comm/propal/list.php

@@ -1,18 +1,19 @@
 <?php
-/* Copyright (C) 2001-2007 Rodolphe Quiedeville  <rodolphe@quiedeville.org>
- * Copyright (C) 2004-2016 Laurent Destailleur   <eldy@users.sourceforge.net>
- * Copyright (C) 2004      Eric Seigne           <eric.seigne@ryxeo.com>
- * Copyright (C) 2005      Marc Barilley / Ocebo <marc@ocebo.com>
- * Copyright (C) 2005-2013 Regis Houssin         <regis.houssin@inodbox.com>
- * Copyright (C) 2006      Andre Cianfarani      <acianfa@free.fr>
- * Copyright (C) 2010-2011 Juanjo Menent         <jmenent@2byte.es>
- * Copyright (C) 2010-2011 Philippe Grand        <philippe.grand@atoo-net.com>
- * Copyright (C) 2012      Christophe Battarel   <christophe.battarel@altairis.fr>
- * Copyright (C) 2013      Cédric Salvador       <csalvador@gpcsolutions.fr>
- * Copyright (C) 2015      Jean-François Ferry     <jfefe@aternatik.fr>
- * Copyright (C) 2016-2018 Ferran Marcet	 <fmarcet@2byte.es>
- * Copyright (C) 2017-2018 Charlene Benke	 <charlie@patas-monkey.com>
- * Copyright (C) 2018	   Nicolas ZABOURI	 <info@inovea-conseil.com>
+/* Copyright (C) 2001-2007 Rodolphe Quiedeville		<rodolphe@quiedeville.org>
+ * Copyright (C) 2004-2016 Laurent Destailleur		<eldy@users.sourceforge.net>
+ * Copyright (C) 2004      Eric Seigne				<eric.seigne@ryxeo.com>
+ * Copyright (C) 2005      Marc Barilley / Ocebo	<marc@ocebo.com>
+ * Copyright (C) 2005-2013 Regis Houssin			<regis.houssin@inodbox.com>
+ * Copyright (C) 2006      Andre Cianfarani			<acianfa@free.fr>
+ * Copyright (C) 2010-2011 Juanjo Menent			<jmenent@2byte.es>
+ * Copyright (C) 2010-2011 Philippe Grand			<philippe.grand@atoo-net.com>
+ * Copyright (C) 2012      Christophe Battarel		<christophe.battarel@altairis.fr>
+ * Copyright (C) 2013      Cédric Salvador			<csalvador@gpcsolutions.fr>
+ * Copyright (C) 2015      Jean-François Ferry		<jfefe@aternatik.fr>
+ * Copyright (C) 2016-2018 Ferran Marcet			<fmarcet@2byte.es>
+ * Copyright (C) 2017-2018 Charlene Benke			<charlie@patas-monkey.com>
+ * Copyright (C) 2018	   Nicolas ZABOURI			<info@inovea-conseil.com>
+ * Copyright (C) 2019	   Alexandre Spangaro		<aspangaro@open-dsi.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -75,15 +76,12 @@ $search_zip = GETPOST('search_zip', 'alpha');
 $search_state = trim(GETPOST("search_state"));
 $search_country = GETPOST("search_country", 'int');
 $search_type_thirdparty = GETPOST("search_type_thirdparty", 'int');
-$search_day = GETPOST("search_day", "int");
-$search_month = GETPOST("search_month", "int");
-$search_year = GETPOST("search_year", "int");
-$search_dayfin = GETPOST("search_dayfin", "int");
-$search_month_end = GETPOST("search_month_end", "int");
-$search_yearfin = GETPOST("search_yearfin", "int");
-$search_daydelivery = GETPOST("search_daydelivery", "int");
-$search_monthdelivery = GETPOST("search_monthdelivery", "int");
-$search_yeardelivery = GETPOST("search_yeardelivery", "int");
+$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
+$search_date_end = dol_mktime(23, 59, 59, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
+$search_dateend_start = dol_mktime(0, 0, 0, GETPOST('search_dateend_startmonth', 'int'), GETPOST('search_dateend_startday', 'int'), GETPOST('search_dateend_startyear', 'int'));
+$search_dateend_end = dol_mktime(23, 59, 59, GETPOST('search_dateend_endmonth', 'int'), GETPOST('search_dateend_endday', 'int'), GETPOST('search_dateend_endyear', 'int'));
+$search_datedelivery_start = dol_mktime(0, 0, 0, GETPOST('search_datedelivery_startmonth', 'int'), GETPOST('search_datedelivery_startday', 'int'), GETPOST('search_datedelivery_startyear', 'int'));
+$search_datedelivery_end = dol_mktime(23, 59, 59, GETPOST('search_datedelivery_endmonth', 'int'), GETPOST('search_datedelivery_endday', 'int'), GETPOST('search_datedelivery_endyear', 'int'));
 $search_availability = GETPOST('search_availability', 'int');
 $search_categ_cus = trim(GETPOST("search_categ_cus", 'int'));
 $search_btn = GETPOST('button_search', 'alpha');
@@ -219,15 +217,12 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x'
 	$search_type = '';
 	$search_country = '';
 	$search_type_thirdparty = '';
-	$search_year = '';
-	$search_month = '';
-	$search_day = '';
-	$search_yearfin = '';
-	$search_month_end = '';
-	$search_dayfin = '';
-	$search_yeardelivery = '';
-	$search_monthdelivery = '';
-	$search_daydelivery = '';
+	$search_date_start = '';
+	$search_date_end = '';
+	$search_dateend_start = '';
+	$search_dateend_end = '';
+	$search_datedelivery_start = '';
+	$search_datedelivery_end = '';
 	$search_availability = '';
 	$viewstatut = '';
 	$object_statut = '';
@@ -314,38 +309,42 @@ if (!$user->rights->societe->client->voir && !$socid) //restriction
 {
 	$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
 }
-if ($search_town)  $sql .= natural_search('s.town', $search_town);
-if ($search_zip)   $sql .= natural_search("s.zip", $search_zip);
-if ($search_state) $sql .= natural_search("state.nom", $search_state);
-if ($search_country) $sql .= " AND s.fk_pays IN (".$db->escape($search_country).')';
-if ($search_type_thirdparty) $sql .= " AND s.fk_typent IN (".$db->escape($search_type_thirdparty).')';
-if ($search_ref)         $sql .= natural_search('p.ref', $search_ref);
-if ($search_refcustomer) $sql .= natural_search('p.ref_client', $search_refcustomer);
-if ($search_refproject)  $sql .= natural_search('pr.ref', $search_refproject);
-if ($search_project)     $sql .= natural_search('pr.title', $search_project);
-if ($search_availability) $sql .= " AND p.fk_availability IN (".$db->escape($search_availability).')';
-
-if ($search_societe)     $sql .= natural_search('s.nom', $search_societe);
-if ($search_login)       $sql .= natural_search("u.login", $search_login);
-if ($search_montant_ht != '')  $sql .= natural_search("p.total_ht", $search_montant_ht, 1);
-if ($search_montant_vat != '') $sql .= natural_search("p.tva", $search_montant_vat, 1);
-if ($search_montant_ttc != '') $sql .= natural_search("p.total", $search_montant_ttc, 1);
+
+if ($search_town)					$sql .= natural_search('s.town', $search_town);
+if ($search_zip)					$sql .= natural_search("s.zip", $search_zip);
+if ($search_state)					$sql .= natural_search("state.nom", $search_state);
+if ($search_country)				$sql .= " AND s.fk_pays IN (".$db->escape($search_country).')';
+if ($search_type_thirdparty)		$sql .= " AND s.fk_typent IN (".$db->escape($search_type_thirdparty).')';
+if ($search_ref)					$sql .= natural_search('p.ref', $search_ref);
+if ($search_refcustomer)			$sql .= natural_search('p.ref_client', $search_refcustomer);
+if ($search_refproject)				$sql .= natural_search('pr.ref', $search_refproject);
+if ($search_project)				$sql .= natural_search('pr.title', $search_project);
+if ($search_availability)			$sql .= " AND p.fk_availability IN (".$db->escape($search_availability).')';
+
+if ($search_societe)				$sql .= natural_search('s.nom', $search_societe);
+if ($search_login)					$sql .= natural_search("u.login", $search_login);
+if ($search_montant_ht != '')		$sql .= natural_search("p.total_ht", $search_montant_ht, 1);
+if ($search_montant_vat != '')		$sql .= natural_search("p.tva", $search_montant_vat, 1);
+if ($search_montant_ttc != '')		$sql .= natural_search("p.total", $search_montant_ttc, 1);
 if ($sall) {
 	$sql .= natural_search(array_keys($fieldstosearchall), $sall);
 }
-if ($search_categ_cus > 0) $sql .= " AND cc.fk_categorie = ".$db->escape($search_categ_cus);
-if ($search_categ_cus == -2)   $sql .= " AND cc.fk_categorie IS NULL";
+if ($search_categ_cus > 0)			$sql .= " AND cc.fk_categorie = ".$db->escape($search_categ_cus);
+if ($search_categ_cus == -2)		$sql .= " AND cc.fk_categorie IS NULL";
 
-if ($search_product_category > 0) $sql .= " AND cp.fk_categorie = ".$db->escape($search_product_category);
+if ($search_product_category > 0)	$sql .= " AND cp.fk_categorie = ".$db->escape($search_product_category);
 if ($socid > 0) $sql .= ' AND s.rowid = '.$socid;
 if ($viewstatut != '' && $viewstatut != '-1')
 {
 	$sql .= ' AND p.fk_statut IN ('.$db->escape($viewstatut).')';
 }
-$sql .= dolSqlDateFilter("p.datep", $search_day, $search_month, $search_year);
-$sql .= dolSqlDateFilter("p.fin_validite", $search_dayfin, $search_month_end, $search_yearfin);
-$sql .= dolSqlDateFilter("p.date_livraison", $search_daydelivery, $search_monthdelivery, $search_yeardelivery);
-if ($search_sale > 0) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$db->escape($search_sale);
+if ($search_date_start)             $sql .= " AND p.datep >= '".$db->idate($search_date_start)."'";
+if ($search_date_end)               $sql .= " AND p.datep <= '".$db->idate($search_date_end)."'";
+if ($search_dateend_start)      	$sql .= " AND p.fin_validite >= '".$db->idate($search_dateend_start)."'";
+if ($search_dateend_end)            $sql .= " AND p.fin_validite <= '".$db->idate($search_dateend_end)."'";
+if ($search_datedelivery_start)     $sql .= " AND p.date_livraison >= '".$db->idate($search_datedelivery_start)."'";
+if ($search_datedelivery_end)       $sql .= " AND p.date_livraison <= '".$db->idate($search_datedelivery_end)."'";
+if ($search_sale > 0)				$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$db->escape($search_sale);
 if ($search_user > 0)
 {
 	$sql .= " AND c.fk_c_type_contact = tc.rowid AND tc.element='propal' AND tc.source='internal' AND c.element_id = p.rowid AND c.fk_socpeople = ".$db->escape($search_user);
@@ -415,22 +414,25 @@ if ($resql)
 	$param = '&viewstatut='.urlencode($viewstatut);
 	if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
 	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
-	if ($sall)				 $param .= '&sall='.urlencode($sall);
-	if ($search_day)         $param .= '&search_day='.urlencode($search_day);
-	if ($search_month)       $param .= '&search_month='.urlencode($search_month);
-	if ($search_year)        $param .= '&search_year='.urlencode($search_year);
-	if ($search_ref)         $param .= '&search_ref='.urlencode($search_ref);
-	if ($search_refcustomer) $param .= '&search_refcustomer='.urlencode($search_refcustomer);
-	if ($search_refproject)  $param .= '&search_refproject='.urlencode($search_refproject);
-	if ($search_societe)     $param .= '&search_societe='.urlencode($search_societe);
-	if ($search_user > 0)    $param .= '&search_user='.urlencode($search_user);
-	if ($search_sale > 0)    $param .= '&search_sale='.urlencode($search_sale);
-	if ($search_montant_ht)  $param .= '&search_montant_ht='.urlencode($search_montant_ht);
-	if ($search_login)  	 $param .= '&search_login='.urlencode($search_login);
-	if ($search_town)		 $param .= '&search_town='.urlencode($search_town);
-	if ($search_zip)		 $param .= '&search_zip='.urlencode($search_zip);
-	if ($socid > 0)          $param .= '&socid='.urlencode($socid);
-	if ($optioncss != '')    $param .= '&optioncss='.urlencode($optioncss);
+	if ($sall)				 			$param .= '&sall='.urlencode($sall);
+	if ($search_date_start)				$param .= '&search_date_start='.urlencode($search_date_start);
+	if ($search_date_end)				$param .= '&search_date_end='.urlencode($search_date_end);
+	if ($search_dateend_start)			$param .= '&search_dateend_start='.urlencode($search_dateend_start);
+	if ($search_dateend_end)			$param .= '&search_dateend_end='.urlencode($search_dateend_end);
+	if ($search_datedelivery_start)		$param .= '&search_datedelivery_start='.urlencode($search_datedelivery_start);
+	if ($search_datedelivery_end)		$param .= '&search_datedelivery_end='.urlencode($search_datedelivery_end);
+	if ($search_ref)         			$param .= '&search_ref='.urlencode($search_ref);
+	if ($search_refcustomer) 			$param .= '&search_refcustomer='.urlencode($search_refcustomer);
+	if ($search_refproject)  			$param .= '&search_refproject='.urlencode($search_refproject);
+	if ($search_societe)     			$param .= '&search_societe='.urlencode($search_societe);
+	if ($search_user > 0)    			$param .= '&search_user='.urlencode($search_user);
+	if ($search_sale > 0)    			$param .= '&search_sale='.urlencode($search_sale);
+	if ($search_montant_ht)  			$param .= '&search_montant_ht='.urlencode($search_montant_ht);
+	if ($search_login)  	 			$param .= '&search_login='.urlencode($search_login);
+	if ($search_town)		 			$param .= '&search_town='.urlencode($search_town);
+	if ($search_zip)		 			$param .= '&search_zip='.urlencode($search_zip);
+	if ($socid > 0)          			$param .= '&socid='.urlencode($socid);
+	if ($optioncss != '')    			$param .= '&optioncss='.urlencode($optioncss);
 	if ($search_categ_cus > 0)          $param .= '&search_categ_cus='.urlencode($search_categ_cus);
 	if ($search_product_category != '') $param .= '&search_product_category='.$search_product_category;
 
@@ -595,34 +597,43 @@ if ($resql)
 	// Date
 	if (!empty($arrayfields['p.date']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		//print $langs->trans('Month').': ';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat width25" type="text" maxlength="2" name="search_day" value="'.dol_escape_htmltag($search_day).'">';
-		print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_month" value="'.dol_escape_htmltag($search_month).'">';
-		//print '&nbsp;'.$langs->trans('Year').': ';
-		$formother->select_year($search_year, 'search_year', 1, 20, 5);
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	// Date end
 	if (!empty($arrayfields['p.fin_validite']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		//print $langs->trans('Month').': ';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat width25" type="text" maxlength="2" name="search_dayfin" value="'.dol_escape_htmltag($search_dayfin).'">';
-		print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_month_end" value="'.dol_escape_htmltag($search_month_end).'">';
-		//print '&nbsp;'.$langs->trans('Year').': ';
-		$formother->select_year($search_yearfin, 'search_yearfin', 1, 20, 5);
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_dateend_start ? $search_dateend_start : -1, 'search_dateend_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_dateend_end ? $search_dateend_end : -1, 'search_dateend_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	// Date delivery
 	if (!empty($arrayfields['p.date_livraison']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		//print $langs->trans('Month').': ';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat width25" type="text" size="1" maxlength="2" name="search_daydelivery" value="'.dol_escape_htmltag($search_daydelivery).'">';
-		print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_monthdelivery" value="'.dol_escape_htmltag($search_monthdelivery).'">';
-		//print '&nbsp;'.$langs->trans('Year').': ';
-		$formother->select_year($search_yeardelivery, 'search_yeardelivery', 1, 20, 5);
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_datedelivery_start ? $search_datedelivery_start : -1, 'search_datedelivery_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_datedelivery_end ? $search_datedelivery_end : -1, 'search_datedelivery_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	// Availability
@@ -720,37 +731,37 @@ if ($resql)
 
 	// Fields title
 	print '<tr class="liste_titre">';
-	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['p.ref_client']['checked']))     print_liste_field_titre($arrayfields['p.ref_client']['label'], $_SERVER["PHP_SELF"], 'p.ref_client', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['pr.ref']['checked']))     	  print_liste_field_titre($arrayfields['pr.ref']['label'], $_SERVER["PHP_SELF"], 'pr.ref', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['pr.title']['checked']))         print_liste_field_titre($arrayfields['pr.title']['label'], $_SERVER["PHP_SELF"], 'pr.title', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['s.nom']['checked']))            print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], 's.nom', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['s.town']['checked']))           print_liste_field_titre($arrayfields['s.town']['label'], $_SERVER["PHP_SELF"], 's.town', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['s.zip']['checked']))            print_liste_field_titre($arrayfields['s.zip']['label'], $_SERVER["PHP_SELF"], 's.zip', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['state.nom']['checked']))        print_liste_field_titre($arrayfields['state.nom']['label'], $_SERVER["PHP_SELF"], "state.nom", "", $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['country.code_iso']['checked'])) print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['typent.code']['checked']))      print_liste_field_titre($arrayfields['typent.code']['label'], $_SERVER["PHP_SELF"], "typent.code", "", $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.date']['checked']))           print_liste_field_titre($arrayfields['p.date']['label'], $_SERVER["PHP_SELF"], 'p.datep', '', $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.fin_validite']['checked']))   print_liste_field_titre($arrayfields['p.fin_validite']['label'], $_SERVER["PHP_SELF"], 'dfv', '', $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.date_livraison']['checked'])) print_liste_field_titre($arrayfields['p.date_livraison']['label'], $_SERVER["PHP_SELF"], 'ddelivery', '', $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['ava.rowid']['checked']))        print_liste_field_titre($arrayfields['ava.rowid']['label'], $_SERVER["PHP_SELF"], 'availability', '', $param, '', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.total_ht']['checked']))       print_liste_field_titre($arrayfields['p.total_ht']['label'], $_SERVER["PHP_SELF"], 'p.total_ht', '', $param, 'class="right"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.total_vat']['checked']))      print_liste_field_titre($arrayfields['p.total_vat']['label'], $_SERVER["PHP_SELF"], 'p.tva', '', $param, 'class="right"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.total_ttc']['checked']))      print_liste_field_titre($arrayfields['p.total_ttc']['label'], $_SERVER["PHP_SELF"], 'p.total', '', $param, 'class="right"', $sortfield, $sortorder);
+	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['p.ref_client']['checked']))     	print_liste_field_titre($arrayfields['p.ref_client']['label'], $_SERVER["PHP_SELF"], 'p.ref_client', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['pr.ref']['checked']))				print_liste_field_titre($arrayfields['pr.ref']['label'], $_SERVER["PHP_SELF"], 'pr.ref', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['pr.title']['checked']))         	print_liste_field_titre($arrayfields['pr.title']['label'], $_SERVER["PHP_SELF"], 'pr.title', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['s.nom']['checked']))            	print_liste_field_titre($arrayfields['s.nom']['label'], $_SERVER["PHP_SELF"], 's.nom', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['s.town']['checked']))           	print_liste_field_titre($arrayfields['s.town']['label'], $_SERVER["PHP_SELF"], 's.town', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['s.zip']['checked']))            	print_liste_field_titre($arrayfields['s.zip']['label'], $_SERVER["PHP_SELF"], 's.zip', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['state.nom']['checked']))        	print_liste_field_titre($arrayfields['state.nom']['label'], $_SERVER["PHP_SELF"], "state.nom", "", $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['country.code_iso']['checked'])) 	print_liste_field_titre($arrayfields['country.code_iso']['label'], $_SERVER["PHP_SELF"], "country.code_iso", "", $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['typent.code']['checked']))      	print_liste_field_titre($arrayfields['typent.code']['label'], $_SERVER["PHP_SELF"], "typent.code", "", $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.date']['checked']))           	print_liste_field_titre($arrayfields['p.date']['label'], $_SERVER["PHP_SELF"], 'p.datep', '', $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.fin_validite']['checked']))		print_liste_field_titre($arrayfields['p.fin_validite']['label'], $_SERVER["PHP_SELF"], 'dfv', '', $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.date_livraison']['checked']))	print_liste_field_titre($arrayfields['p.date_livraison']['label'], $_SERVER["PHP_SELF"], 'ddelivery', '', $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['ava.rowid']['checked']))			print_liste_field_titre($arrayfields['ava.rowid']['label'], $_SERVER["PHP_SELF"], 'availability', '', $param, '', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.total_ht']['checked']))			print_liste_field_titre($arrayfields['p.total_ht']['label'], $_SERVER["PHP_SELF"], 'p.total_ht', '', $param, 'class="right"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.total_vat']['checked']))			print_liste_field_titre($arrayfields['p.total_vat']['label'], $_SERVER["PHP_SELF"], 'p.tva', '', $param, 'class="right"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.total_ttc']['checked']))			print_liste_field_titre($arrayfields['p.total_ttc']['label'], $_SERVER["PHP_SELF"], 'p.total', '', $param, 'class="right"', $sortfield, $sortorder);
 	if (!empty($arrayfields['p.total_ht_invoiced']['checked'])) print_liste_field_titre($arrayfields['p.total_ht_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, 'class="right"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.total_invoiced']['checked'])) print_liste_field_titre($arrayfields['p.total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, 'class="right"', $sortfield, $sortorder);
-	if (!empty($arrayfields['u.login']['checked']))       	  print_liste_field_titre($arrayfields['u.login']['label'], $_SERVER["PHP_SELF"], 'u.login', '', $param, 'align="center"', $sortfield, $sortorder);
-	if (!empty($arrayfields['sale_representative']['checked'])) print_liste_field_titre($arrayfields['sale_representative']['label'], $_SERVER["PHP_SELF"], "", "", "$param", '', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.total_invoiced']['checked']))	print_liste_field_titre($arrayfields['p.total_invoiced']['label'], $_SERVER["PHP_SELF"], '', '', $param, 'class="right"', $sortfield, $sortorder);
+	if (!empty($arrayfields['u.login']['checked']))				print_liste_field_titre($arrayfields['u.login']['label'], $_SERVER["PHP_SELF"], 'u.login', '', $param, 'align="center"', $sortfield, $sortorder);
+	if (!empty($arrayfields['sale_representative']['checked']))	print_liste_field_titre($arrayfields['sale_representative']['label'], $_SERVER["PHP_SELF"], "", "", "$param", '', $sortfield, $sortorder);
 	// Extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
 	// Hook fields
 	$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder);
 	$reshook = $hookmanager->executeHooks('printFieldListTitle', $parameters); // Note that $action and $object may have been modified by hook
 	print $hookmanager->resPrint;
-	if (!empty($arrayfields['p.datec']['checked']))     print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.tms']['checked']))       print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.date_cloture']['checked']))       print_liste_field_titre($arrayfields['p.date_cloture']['label'], $_SERVER["PHP_SELF"], "p.date_cloture", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
-	if (!empty($arrayfields['p.fk_statut']['checked'])) print_liste_field_titre($arrayfields['p.fk_statut']['label'], $_SERVER["PHP_SELF"], "p.fk_statut", "", $param, 'class="right"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.datec']['checked']))     		print_liste_field_titre($arrayfields['p.datec']['label'], $_SERVER["PHP_SELF"], "p.datec", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.tms']['checked']))       		print_liste_field_titre($arrayfields['p.tms']['label'], $_SERVER["PHP_SELF"], "p.tms", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.date_cloture']['checked']))		print_liste_field_titre($arrayfields['p.date_cloture']['label'], $_SERVER["PHP_SELF"], "p.date_cloture", "", $param, 'align="center" class="nowrap"', $sortfield, $sortorder);
+	if (!empty($arrayfields['p.fk_statut']['checked']))			print_liste_field_titre($arrayfields['p.fk_statut']['label'], $_SERVER["PHP_SELF"], "p.fk_statut", "", $param, 'class="right"', $sortfield, $sortorder);
 	print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', 'align="center"', $sortfield, $sortorder, 'maxwidthsearch ');
 	print '</tr>'."\n";
 
@@ -765,8 +776,8 @@ if ($resql)
 
 		$objectstatic->id = $obj->rowid;
 		$objectstatic->ref = $obj->ref;
-		$objectstatic->note_public = $obj->note_public;
 		$objectstatic->note_private = $obj->note_private;
+		$objectstatic->note_public = $obj->note_public;
 
 		$companystatic->id = $obj->socid;
 		$companystatic->name = $obj->name;
@@ -787,7 +798,7 @@ if ($resql)
 			print '<table class="nobordernopadding"><tr class="nocellnopadd">';
 			// Picto + Ref
 			print '<td class="nobordernopadding nowrap">';
-			print $objectstatic->getNomUrl(1, '', '', 0, 1, 1);
+			print $objectstatic->getNomUrl(1, '', '', 0, 1, (isset($conf->global->PROPAL_LIST_SHOW_NOTES) ? $conf->global->PROPAL_LIST_SHOW_NOTES : 1));
 			print '</td>';
 			// Warning
 			$warnornote = '';
@@ -941,7 +952,7 @@ if ($resql)
 		// Amount HT
 		if (!empty($arrayfields['p.total_ht']['checked']))
 		{
-			  print '<td class="right">'.price($obj->total_ht)."</td>\n";
+			  print '<td class="nowrap right">'.price($obj->total_ht)."</td>\n";
 			  if (!$i) $totalarray['nbfield']++;
 			  if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht';
 			  $totalarray['val']['p.total_ht'] += $obj->total_ht;
@@ -949,7 +960,7 @@ if ($resql)
 		// Amount VAT
 		if (!empty($arrayfields['p.total_vat']['checked']))
 		{
-			print '<td class="right">'.price($obj->total_vat)."</td>\n";
+			print '<td class="nowrap right">'.price($obj->total_vat)."</td>\n";
 			if (!$i) $totalarray['nbfield']++;
 			if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'p.total_vat';
 			$totalarray['val']['p.total_vat'] += $obj->total_vat;
@@ -957,7 +968,7 @@ if ($resql)
 		// Amount TTC
 		if (!empty($arrayfields['p.total_ttc']['checked']))
 		{
-			print '<td class="right">'.price($obj->total_ttc)."</td>\n";
+			print '<td class="nowrap right">'.price($obj->total_ttc)."</td>\n";
 			if (!$i) $totalarray['nbfield']++;
 			if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'p.total_ttc';
 			$totalarray['val']['p.total_ttc'] += $obj->total_ttc;
@@ -978,7 +989,7 @@ if ($resql)
                 }
             }
 
-            print '<td class="right">'.price($totalInvoiced)."</td>\n";
+            print '<td class="nowrap right">'.price($totalInvoiced)."</td>\n";
             if (!$i) $totalarray['nbfield']++;
             if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'p.total_ht_invoiced';
             $totalarray['val']['p.total_ht_invoiced'] += $obj->total_ht_invoiced;
@@ -999,7 +1010,7 @@ if ($resql)
                 }
             }
 
-            print '<td class="right">'.price($totalInvoiced)."</td>\n";
+            print '<td class="nowrap right">'.price($totalInvoiced)."</td>\n";
             if (!$i) $totalarray['nbfield']++;
             if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'p.total_invoiced';
             $totalarray['val']['p.total_invoiced'] += $obj->total_invoiced;

+ 285 - 285
htdocs/commande/class/commande.class.php

@@ -164,7 +164,7 @@ class Commande extends CommonOrder
 	 */
 	public $availability;
 
-	public $demand_reason_id;   // Source reason. Why we receive order (after a phone campaign, ...)
+	public $demand_reason_id; // Source reason. Why we receive order (after a phone campaign, ...)
 	public $demand_reason_code;
 	/**
      * @var int Date of order
@@ -343,11 +343,11 @@ class Commande extends CommonOrder
 	 */
 	public function valid($user, $idwarehouse = 0, $notrigger = 0)
 	{
-		global $conf,$langs;
+		global $conf, $langs;
 
 		require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 
-		$error=0;
+		$error = 0;
 
 		// Protection
 		if ($this->statut == self::STATUS_VALIDATED)
@@ -388,31 +388,31 @@ class Commande extends CommonOrder
 
 		// Validate
 		$sql = "UPDATE ".MAIN_DB_PREFIX."commande";
-		$sql.= " SET ref = '".$this->db->escape($num)."',";
-		$sql.= " fk_statut = ".self::STATUS_VALIDATED.",";
-		$sql.= " date_valid='".$this->db->idate($now)."',";
-		$sql.= " fk_user_valid = ".$user->id;
-		$sql.= " WHERE rowid = ".$this->id;
+		$sql .= " SET ref = '".$this->db->escape($num)."',";
+		$sql .= " fk_statut = ".self::STATUS_VALIDATED.",";
+		$sql .= " date_valid='".$this->db->idate($now)."',";
+		$sql .= " fk_user_valid = ".$user->id;
+		$sql .= " WHERE rowid = ".$this->id;
 
 		dol_syslog(get_class($this)."::valid()", LOG_DEBUG);
-		$resql=$this->db->query($sql);
-		if (! $resql)
+		$resql = $this->db->query($sql);
+		if (!$resql)
 		{
 			dol_print_error($this->db);
-			$this->error=$this->db->lasterror();
+			$this->error = $this->db->lasterror();
 			$error++;
 		}
 
-		if (! $error)
+		if (!$error)
 		{
 			// If stock is incremented on validate order, we must increment it
-			if ($result >= 0 && ! empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
+			if ($result >= 0 && !empty($conf->stock->enabled) && $conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER == 1)
 			{
 				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
 				$langs->load("agenda");
 
 				// Loop on each line
-				$cpt=count($this->lines);
+				$cpt = count($this->lines);
 				for ($i = 0; $i < $cpt; $i++)
 				{
 					if ($this->lines[$i]->fk_product > 0)
@@ -448,17 +448,17 @@ class Commande extends CommonOrder
 			if (preg_match('/^[\(]?PROV/i', $this->ref))
 			{
 				// Now we rename also files into index
-				$sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref)+1).")), filepath = 'commande/".$this->db->escape($this->newref)."'";
-				$sql.= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
+				$sql = 'UPDATE '.MAIN_DB_PREFIX."ecm_files set filename = CONCAT('".$this->db->escape($this->newref)."', SUBSTR(filename, ".(strlen($this->ref) + 1).")), filepath = 'commande/".$this->db->escape($this->newref)."'";
+				$sql .= " WHERE filename LIKE '".$this->db->escape($this->ref)."%' AND filepath = 'commande/".$this->db->escape($this->ref)."' and entity = ".$conf->entity;
 				$resql = $this->db->query($sql);
-				if (! $resql) { $error++; $this->error = $this->db->lasterror(); }
+				if (!$resql) { $error++; $this->error = $this->db->lasterror(); }
 
 				// We rename directory ($this->ref = old ref, $num = new ref) in order not to lose the attachments
 				$oldref = dol_sanitizeFileName($this->ref);
 				$newref = dol_sanitizeFileName($num);
 				$dirsource = $conf->commande->multidir_output[$this->entity].'/'.$oldref;
 				$dirdest = $conf->commande->multidir_output[$this->entity].'/'.$newref;
-				if (! $error && file_exists($dirsource))
+				if (!$error && file_exists($dirsource))
 				{
 					dol_syslog(get_class($this)."::valid() rename dir ".$dirsource." into ".$dirdest);
 
@@ -466,13 +466,13 @@ class Commande extends CommonOrder
 					{
 						dol_syslog("Rename ok");
 						// Rename docs starting with $oldref with $newref
-						$listoffiles=dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
-						foreach($listoffiles as $fileentry)
+						$listoffiles = dol_dir_list($conf->commande->multidir_output[$this->entity].'/'.$newref, 'files', 1, '^'.preg_quote($oldref, '/'));
+						foreach ($listoffiles as $fileentry)
 						{
-							$dirsource=$fileentry['name'];
-							$dirdest=preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
-							$dirsource=$fileentry['path'].'/'.$dirsource;
-							$dirdest=$fileentry['path'].'/'.$dirdest;
+							$dirsource = $fileentry['name'];
+							$dirdest = preg_replace('/^'.preg_quote($oldref, '/').'/', $newref, $dirsource);
+							$dirsource = $fileentry['path'].'/'.$dirsource;
+							$dirdest = $fileentry['path'].'/'.$dirdest;
 							@rename($dirsource, $dirdest);
 						}
 					}
@@ -661,34 +661,34 @@ class Commande extends CommonOrder
 	{
 		global $conf;
 
-		$error=0;
+		$error = 0;
 
-		if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->commande->creer))
-			|| (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->commande->order_advance->validate)))
+		if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->creer))
+			|| (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && !empty($user->rights->commande->order_advance->validate)))
 		{
 			$this->db->begin();
 
-			$now=dol_now();
+			$now = dol_now();
 
 			$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element;
-			$sql.= ' SET fk_statut = '.self::STATUS_CLOSED.',';
-			$sql.= ' fk_user_cloture = '.$user->id.',';
-			$sql.= " date_cloture = '".$this->db->idate($now)."'";
-			$sql.= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
+			$sql .= ' SET fk_statut = '.self::STATUS_CLOSED.',';
+			$sql .= ' fk_user_cloture = '.$user->id.',';
+			$sql .= " date_cloture = '".$this->db->idate($now)."'";
+			$sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
 
 			if ($this->db->query($sql))
 			{
-				if (! $notrigger)
+				if (!$notrigger)
 				{
 					// Call trigger
-					$result=$this->call_trigger('ORDER_CLOSE', $user);
+					$result = $this->call_trigger('ORDER_CLOSE', $user);
 					if ($result < 0) $error++;
 					// End call triggers
 				}
 
-				if (! $error)
+				if (!$error)
 				{
-					$this->statut=self::STATUS_CLOSED;
+					$this->statut = self::STATUS_CLOSED;
 
 					$this->db->commit();
 					return 1;
@@ -835,88 +835,88 @@ class Commande extends CommonOrder
 		}
 
 		$soc = new Societe($this->db);
-		$result=$soc->fetch($this->socid);
+		$result = $soc->fetch($this->socid);
 		if ($result < 0)
 		{
-			$this->error="Failed to fetch company";
+			$this->error = "Failed to fetch company";
 			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
 			return -2;
 		}
-		if (! empty($conf->global->COMMANDE_REQUIRE_SOURCE) && $this->source < 0)
+		if (!empty($conf->global->COMMANDE_REQUIRE_SOURCE) && $this->source < 0)
 		{
-			$this->error=$langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
+			$this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Source"));
 			dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
 			return -1;
 		}
 
-		$now=dol_now();
+		$now = dol_now();
 
 		$this->db->begin();
 
 		$sql = "INSERT INTO ".MAIN_DB_PREFIX."commande (";
-		$sql.= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client, ref_int";
-		$sql.= ", model_pdf, fk_cond_reglement, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
-		$sql.= ", fk_shipping_method";
-		$sql.= ", fk_warehouse";
-		$sql.= ", remise_absolue, remise_percent";
-		$sql.= ", fk_incoterms, location_incoterms";
-		$sql.= ", entity, module_source, pos_source";
-		$sql.= ", fk_multicurrency";
-		$sql.= ", multicurrency_code";
-		$sql.= ", multicurrency_tx";
-		$sql.= ")";
-		$sql.= " VALUES ('(PROV)', ".$this->socid.", '".$this->db->idate($now)."', ".$user->id;
-		$sql.= ", ".($this->fk_project>0?$this->fk_project:"null");
-		$sql.= ", '".$this->db->idate($date)."'";
-		$sql.= ", ".($this->source>=0 && $this->source != '' ?$this->db->escape($this->source):'null');
-		$sql.= ", '".$this->db->escape($this->note_private)."'";
-		$sql.= ", '".$this->db->escape($this->note_public)."'";
-		$sql.= ", ".($this->ref_ext?"'".$this->db->escape($this->ref_ext)."'":"null");
-		$sql.= ", ".($this->ref_client?"'".$this->db->escape($this->ref_client)."'":"null");
-		$sql.= ", ".($this->ref_int?"'".$this->db->escape($this->ref_int)."'":"null");
-		$sql.= ", '".$this->db->escape($this->modelpdf)."'";
-		$sql.= ", ".($this->cond_reglement_id>0?$this->cond_reglement_id:"null");
-		$sql.= ", ".($this->mode_reglement_id>0?$this->mode_reglement_id:"null");
-		$sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
-		$sql.= ", ".($this->availability_id>0?$this->availability_id:"null");
-		$sql.= ", ".($this->demand_reason_id>0?$this->demand_reason_id:"null");
-		$sql.= ", ".($this->date_livraison?"'".$this->db->idate($this->date_livraison)."'":"null");
-		$sql.= ", ".($this->fk_delivery_address>0?$this->fk_delivery_address:'NULL');
-		$sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
-		$sql.= ", ".($this->warehouse_id>0?$this->warehouse_id:'NULL');
-		$sql.= ", ".($this->remise_absolue>0?$this->db->escape($this->remise_absolue):'NULL');
-		$sql.= ", ".($this->remise_percent>0?$this->db->escape($this->remise_percent):0);
-		$sql.= ", ".(int) $this->fk_incoterms;
-		$sql.= ", '".$this->db->escape($this->location_incoterms)."'";
-		$sql.= ", ".setEntity($this);
-        $sql.= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
-		$sql.= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
-		$sql.= ", ".(int) $this->fk_multicurrency;
-		$sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
-		$sql.= ", ".(double) $this->multicurrency_tx;
-		$sql.= ")";
+		$sql .= " ref, fk_soc, date_creation, fk_user_author, fk_projet, date_commande, source, note_private, note_public, ref_ext, ref_client, ref_int";
+		$sql .= ", model_pdf, fk_cond_reglement, fk_mode_reglement, fk_account, fk_availability, fk_input_reason, date_livraison, fk_delivery_address";
+		$sql .= ", fk_shipping_method";
+		$sql .= ", fk_warehouse";
+		$sql .= ", remise_absolue, remise_percent";
+		$sql .= ", fk_incoterms, location_incoterms";
+		$sql .= ", entity, module_source, pos_source";
+		$sql .= ", fk_multicurrency";
+		$sql .= ", multicurrency_code";
+		$sql .= ", multicurrency_tx";
+		$sql .= ")";
+		$sql .= " VALUES ('(PROV)', ".$this->socid.", '".$this->db->idate($now)."', ".$user->id;
+		$sql .= ", ".($this->fk_project > 0 ? $this->fk_project : "null");
+		$sql .= ", '".$this->db->idate($date)."'";
+		$sql .= ", ".($this->source >= 0 && $this->source != '' ? $this->db->escape($this->source) : 'null');
+		$sql .= ", '".$this->db->escape($this->note_private)."'";
+		$sql .= ", '".$this->db->escape($this->note_public)."'";
+		$sql .= ", ".($this->ref_ext ? "'".$this->db->escape($this->ref_ext)."'" : "null");
+		$sql .= ", ".($this->ref_client ? "'".$this->db->escape($this->ref_client)."'" : "null");
+		$sql .= ", ".($this->ref_int ? "'".$this->db->escape($this->ref_int)."'" : "null");
+		$sql .= ", '".$this->db->escape($this->modelpdf)."'";
+		$sql .= ", ".($this->cond_reglement_id > 0 ? $this->cond_reglement_id : "null");
+		$sql .= ", ".($this->mode_reglement_id > 0 ? $this->mode_reglement_id : "null");
+		$sql .= ", ".($this->fk_account > 0 ? $this->fk_account : 'NULL');
+		$sql .= ", ".($this->availability_id > 0 ? $this->availability_id : "null");
+		$sql .= ", ".($this->demand_reason_id > 0 ? $this->demand_reason_id : "null");
+		$sql .= ", ".($this->date_livraison ? "'".$this->db->idate($this->date_livraison)."'" : "null");
+		$sql .= ", ".($this->fk_delivery_address > 0 ? $this->fk_delivery_address : 'NULL');
+		$sql .= ", ".($this->shipping_method_id > 0 ? $this->shipping_method_id : 'NULL');
+		$sql .= ", ".($this->warehouse_id > 0 ? $this->warehouse_id : 'NULL');
+		$sql .= ", ".($this->remise_absolue > 0 ? $this->db->escape($this->remise_absolue) : 'NULL');
+		$sql .= ", ".($this->remise_percent > 0 ? $this->db->escape($this->remise_percent) : 0);
+		$sql .= ", ".(int) $this->fk_incoterms;
+		$sql .= ", '".$this->db->escape($this->location_incoterms)."'";
+		$sql .= ", ".setEntity($this);
+        $sql .= ", ".($this->module_source ? "'".$this->db->escape($this->module_source)."'" : "null");
+		$sql .= ", ".($this->pos_source != '' ? "'".$this->db->escape($this->pos_source)."'" : "null");
+		$sql .= ", ".(int) $this->fk_multicurrency;
+		$sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
+		$sql .= ", ".(double) $this->multicurrency_tx;
+		$sql .= ")";
 
 		dol_syslog(get_class($this)."::create", LOG_DEBUG);
-		$resql=$this->db->query($sql);
+		$resql = $this->db->query($sql);
 		if ($resql)
 		{
 			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commande');
 
 			if ($this->id)
 			{
-				$fk_parent_line=0;
-				$num=count($this->lines);
+				$fk_parent_line = 0;
+				$num = count($this->lines);
 
 				/*
 				 *  Insert products details into db
 				 */
-				for ($i=0;$i<$num;$i++)
+				for ($i = 0; $i < $num; $i++)
 				{
 					$line = $this->lines[$i];
 
 					// Test and convert into object this->lines[$i]. When coming from REST API, we may still have an array
 					//if (! is_object($line)) $line=json_decode(json_encode($line), false);  // convert recursively array into object.
-					if (! is_object($line)) $line = (object) $line;
+					if (!is_object($line)) $line = (object) $line;
 
 					// Reset fk_parent_line for no child products and special product
 					if (($line->product_type != 9 && empty($line->fk_parent_line)) || $line->product_type == 9) {
@@ -1499,69 +1499,69 @@ class Commande extends CommonOrder
 			}
 
 			// Insert line
-			$this->line=new OrderLine($this->db);
+			$this->line = new OrderLine($this->db);
 
 			$this->line->context = $this->context;
 
-			$this->line->fk_commande=$this->id;
-			$this->line->label=$label;
-			$this->line->desc=$desc;
-			$this->line->qty=$qty;
-
-			$this->line->vat_src_code=$vat_src_code;
-			$this->line->tva_tx=$txtva;
-			$this->line->localtax1_tx=($total_localtax1?$localtaxes_type[1]:0);
-			$this->line->localtax2_tx=($total_localtax2?$localtaxes_type[3]:0);
-			$this->line->localtax1_type=$localtaxes_type[0];
-			$this->line->localtax2_type=$localtaxes_type[2];
-			$this->line->fk_product=$fk_product;
-			$this->line->product_type=$product_type;
-			$this->line->fk_remise_except=$fk_remise_except;
-			$this->line->remise_percent=$remise_percent;
-			$this->line->subprice=$pu_ht;
-			$this->line->rang=$ranktouse;
-			$this->line->info_bits=$info_bits;
-			$this->line->total_ht=$total_ht;
-			$this->line->total_tva=$total_tva;
-			$this->line->total_localtax1=$total_localtax1;
-			$this->line->total_localtax2=$total_localtax2;
-			$this->line->total_ttc=$total_ttc;
-			$this->line->special_code=$special_code;
-			$this->line->origin=$origin;
-			$this->line->origin_id=$origin_id;
-			$this->line->fk_parent_line=$fk_parent_line;
-			$this->line->fk_unit=$fk_unit;
-
-			$this->line->date_start=$date_start;
-			$this->line->date_end=$date_end;
+			$this->line->fk_commande = $this->id;
+			$this->line->label = $label;
+			$this->line->desc = $desc;
+			$this->line->qty = $qty;
+
+			$this->line->vat_src_code = $vat_src_code;
+			$this->line->tva_tx = $txtva;
+			$this->line->localtax1_tx = ($total_localtax1 ? $localtaxes_type[1] : 0);
+			$this->line->localtax2_tx = ($total_localtax2 ? $localtaxes_type[3] : 0);
+			$this->line->localtax1_type = $localtaxes_type[0];
+			$this->line->localtax2_type = $localtaxes_type[2];
+			$this->line->fk_product = $fk_product;
+			$this->line->product_type = $product_type;
+			$this->line->fk_remise_except = $fk_remise_except;
+			$this->line->remise_percent = $remise_percent;
+			$this->line->subprice = $pu_ht;
+			$this->line->rang = $ranktouse;
+			$this->line->info_bits = $info_bits;
+			$this->line->total_ht = $total_ht;
+			$this->line->total_tva = $total_tva;
+			$this->line->total_localtax1 = $total_localtax1;
+			$this->line->total_localtax2 = $total_localtax2;
+			$this->line->total_ttc = $total_ttc;
+			$this->line->special_code = $special_code;
+			$this->line->origin = $origin;
+			$this->line->origin_id = $origin_id;
+			$this->line->fk_parent_line = $fk_parent_line;
+			$this->line->fk_unit = $fk_unit;
+
+			$this->line->date_start = $date_start;
+			$this->line->date_end = $date_end;
 
 			$this->line->fk_fournprice = $fk_fournprice;
 			$this->line->pa_ht = $pa_ht;
 
 			// Multicurrency
-			$this->line->fk_multicurrency			= $this->fk_multicurrency;
-			$this->line->multicurrency_code			= $this->multicurrency_code;
+			$this->line->fk_multicurrency = $this->fk_multicurrency;
+			$this->line->multicurrency_code = $this->multicurrency_code;
 			$this->line->multicurrency_subprice		= $pu_ht_devise;
 			$this->line->multicurrency_total_ht 	= $multicurrency_total_ht;
 			$this->line->multicurrency_total_tva 	= $multicurrency_total_tva;
 			$this->line->multicurrency_total_ttc 	= $multicurrency_total_ttc;
 
 			// TODO Ne plus utiliser
-			$this->line->price=$price;
-			$this->line->remise=$remise;
+			$this->line->price = $price;
+			$this->line->remise = $remise;
 
-			if (is_array($array_options) && count($array_options)>0) {
-				$this->line->array_options=$array_options;
+			if (is_array($array_options) && count($array_options) > 0) {
+				$this->line->array_options = $array_options;
 			}
 
-			$result=$this->line->insert($user);
+			$result = $this->line->insert($user);
 			if ($result > 0)
 			{
 				// Reorder if child line
-				if (! empty($fk_parent_line)) $this->line_order(true, 'DESC');
+				if (!empty($fk_parent_line)) $this->line_order(true, 'DESC');
 
 				// Mise a jour informations denormalisees au niveau de la commande meme
-				$result=$this->update_price(1, 'auto', 0, $mysoc);	// This method is designed to add line from user input so total calculation must be done using 'auto' mode.
+				$result = $this->update_price(1, 'auto', 0, $mysoc); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
 				if ($result > 0)
 				{
 					$this->db->commit();
@@ -1695,35 +1695,35 @@ class Commande extends CommonOrder
 		if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1;
 
 		$sql = 'SELECT c.rowid, c.entity, c.date_creation, c.ref, c.fk_soc, c.fk_user_author, c.fk_user_valid, c.fk_statut';
-		$sql.= ', c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
-		$sql.= ', c.fk_account';
-		$sql.= ', c.date_commande, c.date_valid, c.tms';
-		$sql.= ', c.date_livraison';
-		$sql.= ', c.fk_shipping_method';
-		$sql.= ', c.fk_warehouse';
-		$sql.= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
-		$sql.= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.ref_int, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
-		$sql.= ', c.fk_incoterms, c.location_incoterms';
-		$sql.= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
-		$sql.= ", c.module_source, c.pos_source";
-        $sql.= ", i.libelle as label_incoterms";
-		$sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
-		$sql.= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
-		$sql.= ', ca.code as availability_code, ca.label as availability_label';
-		$sql.= ', dr.code as demand_reason_code';
-		$sql.= ' FROM '.MAIN_DB_PREFIX.'commande as c';
-		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
-		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
-		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
-		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
-		$sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
-
-		if ($id) $sql.= " WHERE c.rowid=".$id;
-		else $sql.= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
-
-		if ($ref)     $sql.= " AND c.ref='".$this->db->escape($ref)."'";
-		if ($ref_ext) $sql.= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
-		if ($ref_int) $sql.= " AND c.ref_int='".$this->db->escape($ref_int)."'";
+		$sql .= ', c.amount_ht, c.total_ht, c.total_ttc, c.tva as total_tva, c.localtax1 as total_localtax1, c.localtax2 as total_localtax2, c.fk_cond_reglement, c.fk_mode_reglement, c.fk_availability, c.fk_input_reason';
+		$sql .= ', c.fk_account';
+		$sql .= ', c.date_commande, c.date_valid, c.tms';
+		$sql .= ', c.date_livraison';
+		$sql .= ', c.fk_shipping_method';
+		$sql .= ', c.fk_warehouse';
+		$sql .= ', c.fk_projet as fk_project, c.remise_percent, c.remise, c.remise_absolue, c.source, c.facture as billed';
+		$sql .= ', c.note_private, c.note_public, c.ref_client, c.ref_ext, c.ref_int, c.model_pdf, c.last_main_doc, c.fk_delivery_address, c.extraparams';
+		$sql .= ', c.fk_incoterms, c.location_incoterms';
+		$sql .= ", c.fk_multicurrency, c.multicurrency_code, c.multicurrency_tx, c.multicurrency_total_ht, c.multicurrency_total_tva, c.multicurrency_total_ttc";
+		$sql .= ", c.module_source, c.pos_source";
+        $sql .= ", i.libelle as label_incoterms";
+		$sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
+		$sql .= ', cr.code as cond_reglement_code, cr.libelle as cond_reglement_libelle, cr.libelle_facture as cond_reglement_libelle_doc';
+		$sql .= ', ca.code as availability_code, ca.label as availability_label';
+		$sql .= ', dr.code as demand_reason_code';
+		$sql .= ' FROM '.MAIN_DB_PREFIX.'commande as c';
+		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON c.fk_cond_reglement = cr.rowid';
+		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON c.fk_mode_reglement = p.id';
+		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON c.fk_availability = ca.rowid';
+		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON c.fk_input_reason = dr.rowid';
+		$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_incoterms as i ON c.fk_incoterms = i.rowid';
+
+		if ($id) $sql .= " WHERE c.rowid=".$id;
+		else $sql .= " WHERE c.entity IN (".getEntity('commande').")"; // Dont't use entity if you use rowid
+
+		if ($ref)     $sql .= " AND c.ref='".$this->db->escape($ref)."'";
+		if ($ref_ext) $sql .= " AND c.ref_ext='".$this->db->escape($ref_ext)."'";
+		if ($ref_int) $sql .= " AND c.ref_int='".$this->db->escape($ref_int)."'";
 
 		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
 		$result = $this->db->query($sql);
@@ -2017,7 +2017,7 @@ class Commande extends CommonOrder
 				$line->fetch_optionals();
 
 				// multilangs
-        		if (! empty($conf->global->MAIN_MULTILANGS) && ! empty($objp->fk_product) && ! empty($loadalsotranslation)) {
+        		if (!empty($conf->global->MAIN_MULTILANGS) && !empty($objp->fk_product) && !empty($loadalsotranslation)) {
             		$line = new Product($this->db);
             		$line->fetch($objp->fk_product);
             		$line->getMultiLangs();
@@ -2860,44 +2860,44 @@ class Commande extends CommonOrder
 		$this->db->begin();
 
 		$sql = 'UPDATE '.MAIN_DB_PREFIX.'commande SET facture = 1';
-		$sql.= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
+		$sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > '.self::STATUS_DRAFT;
 
 		dol_syslog(get_class($this)."::classifyBilled", LOG_DEBUG);
 		if ($this->db->query($sql))
 		{
-			if (! $error)
+			if (!$error)
 			{
-				$this->oldcopy= clone $this;
-				$this->billed=1;
+				$this->oldcopy = clone $this;
+				$this->billed = 1;
 			}
 
-			if (! $notrigger && empty($error))
+			if (!$notrigger && empty($error))
 			{
 				// Call trigger
-				$result=$this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
+				$result = $this->call_trigger('ORDER_CLASSIFY_BILLED', $user);
 				if ($result < 0) $error++;
 				// End call triggers
 			}
 
-			if (! $error)
+			if (!$error)
 			{
 				$this->db->commit();
 				return 1;
 			}
 			else
 			{
-				foreach($this->errors as $errmsg)
+				foreach ($this->errors as $errmsg)
 				{
 					dol_syslog(get_class($this)."::classifyBilled ".$errmsg, LOG_ERR);
-					$this->error.=($this->error?', '.$errmsg:$errmsg);
+					$this->error .= ($this->error ? ', '.$errmsg : $errmsg);
 				}
 				$this->db->rollback();
-				return -1*$error;
+				return -1 * $error;
 			}
 		}
 		else
 		{
-			$this->error=$this->db->error();
+			$this->error = $this->db->error();
 			$this->db->rollback();
 			return -1;
 		}
@@ -3100,18 +3100,18 @@ class Commande extends CommonOrder
 			$this->line->context = $this->context;
 
 			// Reorder if fk_parent_line change
-			if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
+			if (!empty($fk_parent_line) && !empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
 			{
 				$rangmax = $this->line_max($fk_parent_line);
 				$this->line->rang = $rangmax + 1;
 			}
 
-			$this->line->id=$rowid;
-			$this->line->label=$label;
-			$this->line->desc=$desc;
-			$this->line->qty=$qty;
+			$this->line->id = $rowid;
+			$this->line->label = $label;
+			$this->line->desc = $desc;
+			$this->line->qty = $qty;
 
-			$this->line->vat_src_code	= $vat_src_code;
+			$this->line->vat_src_code = $vat_src_code;
 			$this->line->tva_tx         = $txtva;
 			$this->line->localtax1_tx   = $txlocaltax1;
 			$this->line->localtax2_tx   = $txlocaltax2;
@@ -3148,7 +3148,7 @@ class Commande extends CommonOrder
 
 			if (is_array($array_options) && count($array_options) > 0) {
 				// We replace values in this->line->array_options only for entries defined into $array_options
-				foreach($array_options as $key => $value) {
+				foreach ($array_options as $key => $value) {
 					$this->line->array_options[$key] = $array_options[$key];
 				}
 			}
@@ -3347,30 +3347,30 @@ class Commande extends CommonOrder
 			}
 		}
 
-		if (! $error)
+		if (!$error)
 		{
 			// Delete object
 			$sql = 'DELETE FROM '.MAIN_DB_PREFIX."commande WHERE rowid = ".$this->id;
-			if (! $this->db->query($sql) )
+			if (!$this->db->query($sql))
 			{
 				$error++;
-				$this->errors[]=$this->db->lasterror();
+				$this->errors[] = $this->db->lasterror();
 			}
 		}
 
-		if (! $error)
+		if (!$error)
 		{
 			// Remove directory with files
 			$comref = dol_sanitizeFileName($this->ref);
 			if ($conf->commande->multidir_output[$this->entity] && !empty($this->ref))
 			{
-				$dir = $conf->commande->multidir_output[$this->entity] . "/" . $comref ;
-				$file = $conf->commande->multidir_output[$this->entity] . "/" . $comref . "/" . $comref . ".pdf";
+				$dir = $conf->commande->multidir_output[$this->entity]."/".$comref;
+				$file = $conf->commande->multidir_output[$this->entity]."/".$comref."/".$comref.".pdf";
 				if (file_exists($file))	// We must delete all files before deleting directory
 				{
 					dol_delete_preview($this);
 
-					if (! dol_delete_file($file, 0, 0, 0, $this)) // For triggers
+					if (!dol_delete_file($file, 0, 0, 0, $this)) // For triggers
 					{
 						$this->db->rollback();
 						return 0;
@@ -3420,34 +3420,34 @@ class Commande extends CommonOrder
 		$clause = " WHERE";
 
 		$sql = "SELECT c.rowid, c.date_creation as datec, c.date_commande, c.date_livraison as delivery_date, c.fk_statut, c.total_ht";
-		$sql.= " FROM ".MAIN_DB_PREFIX."commande as c";
+		$sql .= " FROM ".MAIN_DB_PREFIX."commande as c";
 		if (!$user->rights->societe->client->voir && !$user->socid)
 		{
-			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
-			$sql.= " WHERE sc.fk_user = " .$user->id;
+			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc";
+			$sql .= " WHERE sc.fk_user = ".$user->id;
 			$clause = " AND";
 		}
-		$sql.= $clause." c.entity IN (".getEntity('commande').")";
+		$sql .= $clause." c.entity IN (".getEntity('commande').")";
 		//$sql.= " AND c.fk_statut IN (1,2,3) AND c.facture = 0";
-		$sql.= " AND ((c.fk_statut IN (".self::STATUS_VALIDATED.",".self::STATUS_SHIPMENTONPROCESS.")) OR (c.fk_statut = ".self::STATUS_CLOSED." AND c.facture = 0))";    // If status is 2 and facture=1, it must be selected
-		if ($user->socid) $sql.=" AND c.fk_soc = ".$user->socid;
+		$sql .= " AND ((c.fk_statut IN (".self::STATUS_VALIDATED.",".self::STATUS_SHIPMENTONPROCESS.")) OR (c.fk_statut = ".self::STATUS_CLOSED." AND c.facture = 0))"; // If status is 2 and facture=1, it must be selected
+		if ($user->socid) $sql .= " AND c.fk_soc = ".$user->socid;
 
-		$resql=$this->db->query($sql);
+		$resql = $this->db->query($sql);
 		if ($resql)
 		{
 			$response = new WorkboardResponse();
-			$response->warning_delay=$conf->commande->client->warning_delay/60/60/24;
-			$response->label=$langs->trans("OrdersToProcess");
+			$response->warning_delay = $conf->commande->client->warning_delay / 60 / 60 / 24;
+			$response->label = $langs->trans("OrdersToProcess");
 			$response->labelShort = $langs->trans("Opened");
-			$response->url=DOL_URL_ROOT.'/commande/list.php?viewstatut=-3&mainmenu=commercial&leftmenu=orders';
-			$response->img=img_object('', "order");
+			$response->url = DOL_URL_ROOT.'/commande/list.php?viewstatut=-3&mainmenu=commercial&leftmenu=orders';
+			$response->img = img_object('', "order");
 
 			$generic_commande = new Commande($this->db);
 
-			while ($obj=$this->db->fetch_object($resql))
+			while ($obj = $this->db->fetch_object($resql))
 			{
 				$response->nbtodo++;
-				$response->total+= $obj->total_ht;
+				$response->total += $obj->total_ht;
 
 				$generic_commande->statut = $obj->fk_statut;
 				$generic_commande->date_commande = $this->db->jdate($obj->date_commande);
@@ -3509,47 +3509,47 @@ class Commande extends CommonOrder
 		global $langs, $conf;
 
 		$billedtext = '';
-		if (empty($donotshowbilled)) $billedtext .= ($billed?' - '.$langs->trans("Billed"):'');
+		if (empty($donotshowbilled)) $billedtext .= ($billed ? ' - '.$langs->trans("Billed") : '');
 
-		if ($status==self::STATUS_CANCELED){
+		if ($status == self::STATUS_CANCELED) {
 		    $labelStatus = $langs->trans('StatusOrderCanceled');
 		    $labelStatusShort = $langs->trans('StatusOrderCanceledShort');
-		    $statusType='status5';
+		    $statusType = 'status5';
 		}
-		elseif ($status==self::STATUS_DRAFT){
+		elseif ($status == self::STATUS_DRAFT) {
 		    $labelStatus = $langs->trans('StatusOrderDraft');
 		    $labelStatusShort = $langs->trans('StatusOrderDraftShort');
-		    $statusType='status0';
+		    $statusType = 'status0';
 		}
-		elseif ($status==self::STATUS_VALIDATED){
+		elseif ($status == self::STATUS_VALIDATED) {
 		    $labelStatus = $langs->trans('StatusOrderValidated').$billedtext;
 		    $labelStatusShort = $langs->trans('StatusOrderValidatedShort').$billedtext;
-		    $statusType='status1';
+		    $statusType = 'status1';
 		}
-		elseif ($status==self::STATUS_SHIPMENTONPROCESS){
+		elseif ($status == self::STATUS_SHIPMENTONPROCESS) {
 		    $labelStatus = $langs->trans('StatusOrderSentShort').$billedtext;
 		    $labelStatusShort = $langs->trans('StatusOrderSentShort').$billedtext;
-		    $statusType='status3';
+		    $statusType = 'status3';
 		}
-		elseif ($status==self::STATUS_CLOSED && (! $billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))){
+		elseif ($status == self::STATUS_CLOSED && (!$billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
 		    $labelStatus = $langs->trans('StatusOrderToBill');
 		    $labelStatusShort = $langs->trans('StatusOrderToBillShort');
-		    $statusType='status4';
+		    $statusType = 'status4';
 		}
-		elseif ($status==self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))){
+		elseif ($status == self::STATUS_CLOSED && ($billed && empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
 		    $labelStatus = $langs->trans('StatusOrderProcessed').$billedtext;
 		    $labelStatusShort = $langs->trans('StatusOrderProcessed').$billedtext;
-		    $statusType='status6';
+		    $statusType = 'status6';
 		}
-		elseif ($status==self::STATUS_CLOSED && (! empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))){
+		elseif ($status == self::STATUS_CLOSED && (!empty($conf->global->WORKFLOW_BILL_ON_SHIPMENT))) {
 		    $labelStatus = $langs->trans('StatusOrderDelivered');
 		    $labelStatusShort = $langs->trans('StatusOrderDelivered');
-		    $statusType='status6';
+		    $statusType = 'status6';
 		}
-		else{
+		else {
 		    $labelStatus = $langs->trans('Unknown');
 		    $labelStatusShort = '';
-		    $statusType='';
+		    $statusType = '';
 		    $mode = 0;
 		}
 
@@ -3818,26 +3818,26 @@ class Commande extends CommonOrder
         // phpcs:enable
 		global $user;
 
-		$this->nb=array();
+		$this->nb = array();
 		$clause = "WHERE";
 
 		$sql = "SELECT count(co.rowid) as nb";
-		$sql.= " FROM ".MAIN_DB_PREFIX."commande as co";
-		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
+		$sql .= " FROM ".MAIN_DB_PREFIX."commande as co";
+		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON co.fk_soc = s.rowid";
 		if (!$user->rights->societe->client->voir && !$user->socid)
 		{
-			$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
-			$sql.= " WHERE sc.fk_user = " .$user->id;
+			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
+			$sql .= " WHERE sc.fk_user = ".$user->id;
 			$clause = "AND";
 		}
-		$sql.= " ".$clause." co.entity IN (".getEntity('commande').")";
+		$sql .= " ".$clause." co.entity IN (".getEntity('commande').")";
 
-		$resql=$this->db->query($sql);
+		$resql = $this->db->query($sql);
 		if ($resql)
 		{
-			while ($obj=$this->db->fetch_object($resql))
+			while ($obj = $this->db->fetch_object($resql))
 			{
-				$this->nb["orders"]=$obj->nb;
+				$this->nb["orders"] = $obj->nb;
 			}
 			$this->db->free($resql);
 			return 1;
@@ -3873,16 +3873,16 @@ class Commande extends CommonOrder
 	 */
 	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
 	{
-		global $conf,$langs;
+		global $conf, $langs;
 
 		$langs->load("orders");
 
-		if (! dol_strlen($modele)) {
+		if (!dol_strlen($modele)) {
 			$modele = 'einstein';
 
 			if ($this->modelpdf) {
 				$modele = $this->modelpdf;
-			} elseif (! empty($conf->global->COMMANDE_ADDON_PDF)) {
+			} elseif (!empty($conf->global->COMMANDE_ADDON_PDF)) {
 				$modele = $conf->global->COMMANDE_ADDON_PDF;
 			}
 		}
@@ -4113,13 +4113,13 @@ class OrderLine extends CommonOrderLine
 	{
 		global $conf, $langs;
 
-		$error=0;
+		$error = 0;
 
         // check if order line is not in a shipment line before deleting
         $sqlCheckShipmentLine  = "SELECT";
         $sqlCheckShipmentLine .= " ed.rowid";
-        $sqlCheckShipmentLine .= " FROM " . MAIN_DB_PREFIX . "expeditiondet ed";
-        $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = " . $this->rowid;
+        $sqlCheckShipmentLine .= " FROM ".MAIN_DB_PREFIX."expeditiondet ed";
+        $sqlCheckShipmentLine .= " WHERE ed.fk_origin_line = ".$this->rowid;
 
         $resqlCheckShipmentLine = $this->db->query($sqlCheckShipmentLine);
         if (!$resqlCheckShipmentLine) {
@@ -4132,13 +4132,13 @@ class OrderLine extends CommonOrderLine
             if ($num > 0) {
                 $error++;
                 $objCheckShipmentLine = $this->db->fetch_object($resqlCheckShipmentLine);
-                $this->error = $langs->trans('ErrorRecordAlreadyExists') . ' : ' . $langs->trans('ShipmentLine') . ' ' . $objCheckShipmentLine->rowid;
+                $this->error = $langs->trans('ErrorRecordAlreadyExists').' : '.$langs->trans('ShipmentLine').' '.$objCheckShipmentLine->rowid;
                 $this->errors[] = $this->error;
             }
             $this->db->free($resqlCheckShipmentLine);
         }
         if ($error) {
-            dol_syslog(__METHOD__ . 'Error ; ' . $this->error, LOG_ERR);
+            dol_syslog(__METHOD__.'Error ; '.$this->error, LOG_ERR);
             return -1;
         }
 
@@ -4147,14 +4147,14 @@ class OrderLine extends CommonOrderLine
 		$sql = 'DELETE FROM '.MAIN_DB_PREFIX."commandedet WHERE rowid=".$this->rowid;
 
 		dol_syslog("OrderLine::delete", LOG_DEBUG);
-		$resql=$this->db->query($sql);
+		$resql = $this->db->query($sql);
 		if ($resql)
 		{
 			// Remove extrafields
-			if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
+			if ((!$error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
 			{
-				$this->id=$this->rowid;
-				$result=$this->deleteExtraFields();
+				$this->id = $this->rowid;
+				$result = $this->deleteExtraFields();
 				if ($result < 0)
 				{
 					$error++;
@@ -4243,73 +4243,73 @@ class OrderLine extends CommonOrderLine
 
 		// Insertion dans base de la ligne
 		$sql = 'INSERT INTO '.MAIN_DB_PREFIX.'commandedet';
-		$sql.= ' (fk_commande, fk_parent_line, label, description, qty, ';
-		$sql.= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
-		$sql.= ' fk_product, product_type, remise_percent, subprice, price, remise, fk_remise_except,';
-		$sql.= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
-		$sql.= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
-		$sql.= ' fk_unit';
-		$sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
-		$sql.= ')';
-		$sql.= " VALUES (".$this->fk_commande.",";
-		$sql.= " ".($this->fk_parent_line>0?"'".$this->db->escape($this->fk_parent_line)."'":"null").",";
-		$sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
-		$sql.= " '".$this->db->escape($this->desc)."',";
-		$sql.= " '".price2num($this->qty)."',";
-		$sql.= " ".(empty($this->vat_src_code)?"''":"'".$this->db->escape($this->vat_src_code)."'").",";
-		$sql.= " '".price2num($this->tva_tx)."',";
-		$sql.= " '".price2num($this->localtax1_tx)."',";
-		$sql.= " '".price2num($this->localtax2_tx)."',";
-		$sql.= " '".$this->db->escape($this->localtax1_type)."',";
-		$sql.= " '".$this->db->escape($this->localtax2_type)."',";
-		$sql.= ' '.(! empty($this->fk_product)?$this->fk_product:"null").',';
-		$sql.= " '".$this->db->escape($this->product_type)."',";
-		$sql.= " '".price2num($this->remise_percent)."',";
-		$sql.= " ".(price2num($this->subprice)!==''?price2num($this->subprice):"null").",";
-		$sql.= " ".($this->price!=''?"'".price2num($this->price)."'":"null").",";
-		$sql.= " '".price2num($this->remise)."',";
-		$sql.= ' '.(! empty($this->fk_remise_except)?$this->fk_remise_except:"null").',';
-		$sql.= ' '.$this->special_code.',';
-		$sql.= ' '.$this->rang.',';
-		$sql.= ' '.(! empty($this->fk_fournprice)?$this->fk_fournprice:"null").',';
-		$sql.= ' '.price2num($this->pa_ht).',';
-		$sql.= " '".$this->db->escape($this->info_bits)."',";
-		$sql.= " ".price2num($this->total_ht).",";
-		$sql.= " ".price2num($this->total_tva).",";
-		$sql.= " ".price2num($this->total_localtax1).",";
-		$sql.= " ".price2num($this->total_localtax2).",";
-		$sql.= " ".price2num($this->total_ttc).",";
-		$sql.= " ".(! empty($this->date_start)?"'".$this->db->idate($this->date_start)."'":"null").',';
-		$sql.= " ".(! empty($this->date_end)?"'".$this->db->idate($this->date_end)."'":"null").',';
-		$sql.= ' '.(!$this->fk_unit ? 'NULL' : $this->fk_unit);
-		$sql.= ", ".(! empty($this->fk_multicurrency) ? $this->fk_multicurrency : 'NULL');
-		$sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
-		$sql.= ", ".$this->multicurrency_subprice;
-		$sql.= ", ".$this->multicurrency_total_ht;
-		$sql.= ", ".$this->multicurrency_total_tva;
-		$sql.= ", ".$this->multicurrency_total_ttc;
-		$sql.= ')';
+		$sql .= ' (fk_commande, fk_parent_line, label, description, qty, ';
+		$sql .= ' vat_src_code, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
+		$sql .= ' fk_product, product_type, remise_percent, subprice, price, remise, fk_remise_except,';
+		$sql .= ' special_code, rang, fk_product_fournisseur_price, buy_price_ht,';
+		$sql .= ' info_bits, total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, date_start, date_end,';
+		$sql .= ' fk_unit';
+		$sql .= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc';
+		$sql .= ')';
+		$sql .= " VALUES (".$this->fk_commande.",";
+		$sql .= " ".($this->fk_parent_line > 0 ? "'".$this->db->escape($this->fk_parent_line)."'" : "null").",";
+		$sql .= " ".(!empty($this->label) ? "'".$this->db->escape($this->label)."'" : "null").",";
+		$sql .= " '".$this->db->escape($this->desc)."',";
+		$sql .= " '".price2num($this->qty)."',";
+		$sql .= " ".(empty($this->vat_src_code) ? "''" : "'".$this->db->escape($this->vat_src_code)."'").",";
+		$sql .= " '".price2num($this->tva_tx)."',";
+		$sql .= " '".price2num($this->localtax1_tx)."',";
+		$sql .= " '".price2num($this->localtax2_tx)."',";
+		$sql .= " '".$this->db->escape($this->localtax1_type)."',";
+		$sql .= " '".$this->db->escape($this->localtax2_type)."',";
+		$sql .= ' '.(!empty($this->fk_product) ? $this->fk_product : "null").',';
+		$sql .= " '".$this->db->escape($this->product_type)."',";
+		$sql .= " '".price2num($this->remise_percent)."',";
+		$sql .= " ".(price2num($this->subprice) !== '' ?price2num($this->subprice) : "null").",";
+		$sql .= " ".($this->price != '' ? "'".price2num($this->price)."'" : "null").",";
+		$sql .= " '".price2num($this->remise)."',";
+		$sql .= ' '.(!empty($this->fk_remise_except) ? $this->fk_remise_except : "null").',';
+		$sql .= ' '.$this->special_code.',';
+		$sql .= ' '.$this->rang.',';
+		$sql .= ' '.(!empty($this->fk_fournprice) ? $this->fk_fournprice : "null").',';
+		$sql .= ' '.price2num($this->pa_ht).',';
+		$sql .= " '".$this->db->escape($this->info_bits)."',";
+		$sql .= " ".price2num($this->total_ht).",";
+		$sql .= " ".price2num($this->total_tva).",";
+		$sql .= " ".price2num($this->total_localtax1).",";
+		$sql .= " ".price2num($this->total_localtax2).",";
+		$sql .= " ".price2num($this->total_ttc).",";
+		$sql .= " ".(!empty($this->date_start) ? "'".$this->db->idate($this->date_start)."'" : "null").',';
+		$sql .= " ".(!empty($this->date_end) ? "'".$this->db->idate($this->date_end)."'" : "null").',';
+		$sql .= ' '.(!$this->fk_unit ? 'NULL' : $this->fk_unit);
+		$sql .= ", ".(!empty($this->fk_multicurrency) ? $this->fk_multicurrency : 'NULL');
+		$sql .= ", '".$this->db->escape($this->multicurrency_code)."'";
+		$sql .= ", ".$this->multicurrency_subprice;
+		$sql .= ", ".$this->multicurrency_total_ht;
+		$sql .= ", ".$this->multicurrency_total_tva;
+		$sql .= ", ".$this->multicurrency_total_ttc;
+		$sql .= ')';
 
 		dol_syslog(get_class($this)."::insert", LOG_DEBUG);
-		$resql=$this->db->query($sql);
+		$resql = $this->db->query($sql);
 		if ($resql)
 		{
-			$this->id=$this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
+			$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX.'commandedet');
 			$this->rowid = $this->id;
 
 			if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
 			{
-				$result=$this->insertExtraFields();
+				$result = $this->insertExtraFields();
 				if ($result < 0)
 				{
 					$error++;
 				}
 			}
 
-			if (! $error && ! $notrigger)
+			if (!$error && !$notrigger)
 			{
 				// Call trigger
-				$result=$this->call_trigger('LINEORDER_INSERT', $user);
+				$result = $this->call_trigger('LINEORDER_INSERT', $user);
 				if ($result < 0) $error++;
 				// End call triggers
 			}

+ 107 - 69
htdocs/commande/list.php

@@ -56,12 +56,10 @@ $confirm = GETPOST('confirm', 'alpha');
 $toselect = GETPOST('toselect', 'array');
 $contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'orderlist';
 
-$search_orderyear = GETPOST("search_orderyear", "int");
-$search_ordermonth = GETPOST("search_ordermonth", "int");
-$search_orderday = GETPOST("search_orderday", "int");
-$search_deliveryyear = GETPOST("search_deliveryyear", "int");
-$search_deliverymonth = GETPOST("search_deliverymonth", "int");
-$search_deliveryday = GETPOST("search_deliveryday", "int");
+$search_dateorder_start = dol_mktime(0, 0, 0, GETPOST('search_dateorder_startmonth', 'int'), GETPOST('search_dateorder_startday', 'int'), GETPOST('search_dateorder_startyear', 'int'));
+$search_dateorder_end = dol_mktime(23, 59, 59, GETPOST('search_dateorder_endmonth', 'int'), GETPOST('search_dateorder_endday', 'int'), GETPOST('search_dateorder_endyear', 'int'));
+$search_datedelivery_start = dol_mktime(0, 0, 0, GETPOST('search_datedelivery_startmonth', 'int'), GETPOST('search_datedelivery_startday', 'int'), GETPOST('search_datedelivery_startyear', 'int'));
+$search_datedelivery_end = dol_mktime(23, 59, 59, GETPOST('search_datedelivery_endmonth', 'int'), GETPOST('search_datedelivery_endday', 'int'), GETPOST('search_datedelivery_endyear', 'int'));
 $search_product_category = GETPOST('search_product_category', 'int');
 $search_ref = GETPOST('search_ref', 'alpha') != '' ?GETPOST('search_ref', 'alpha') : GETPOST('sref', 'alpha');
 $search_ref_customer = GETPOST('search_ref_customer', 'alpha');
@@ -77,6 +75,7 @@ $search_user = GETPOST('search_user', 'int');
 $search_sale = GETPOST('search_sale', 'int');
 $search_total_ht = GETPOST('search_total_ht', 'alpha');
 $search_total_ttc = GETPOST('search_total_ttc', 'alpha');
+$search_login = GETPOST('search_login', 'alpha');
 $search_categ_cus = trim(GETPOST("search_categ_cus", 'int'));
 $optioncss = GETPOST('optioncss', 'alpha');
 $billed = GETPOST('billed', 'int');
@@ -142,6 +141,7 @@ $arrayfields = array(
 	'c.total_ht'=>array('label'=>"AmountHT", 'checked'=>1),
 	'c.total_vat'=>array('label'=>"AmountVAT", 'checked'=>0),
 	'c.total_ttc'=>array('label'=>"AmountTTC", 'checked'=>0),
+	'u.login'=>array('label'=>"Author", 'checked'=>1, 'position'=>10),
 	'c.datec'=>array('label'=>"DateCreation", 'checked'=>0, 'position'=>500),
 	'c.tms'=>array('label'=>"DateModificationShort", 'checked'=>0, 'position'=>500),
     'c.date_cloture'=>array('label'=>"DateClosing", 'checked'=>0, 'position'=>500),
@@ -197,12 +197,11 @@ if (empty($reshook))
 		$search_total_ht = '';
 		$search_total_vat = '';
 		$search_total_ttc = '';
-		$search_orderyear = '';
-		$search_ordermonth = '';
-		$search_orderday = '';
-		$search_deliveryday = '';
-		$search_deliverymonth = '';
-		$search_deliveryyear = '';
+		$search_login = '';
+		$search_dateorder_start = '';
+		$search_dateorder_end = '';
+		$search_datedelivery_start = '';
+		$search_datedelivery_end = '';
 		$search_project_ref = '';
 		$search_project = '';
 		$viewstatut = '';
@@ -250,10 +249,11 @@ if ($sall || $search_product_category > 0) $sql = 'SELECT DISTINCT';
 $sql .= ' s.rowid as socid, s.nom as name, s.email, s.town, s.zip, s.fk_pays, s.client, s.code_client,';
 $sql .= " typent.code as typent_code,";
 $sql .= " state.code_departement as state_code, state.nom as state_name,";
-$sql .= ' c.rowid, c.ref, c.total_ht, c.tva as total_tva, c.total_ttc, c.ref_client,';
+$sql .= ' c.rowid, c.ref, c.total_ht, c.tva as total_tva, c.total_ttc, c.ref_client, c.fk_user_author,';
 $sql .= ' c.date_valid, c.date_commande, c.note_private, c.date_livraison as date_delivery, c.fk_statut, c.facture as billed,';
 $sql .= ' c.date_creation as date_creation, c.tms as date_update, c.date_cloture as date_cloture,';
-$sql .= " p.rowid as project_id, p.ref as project_ref, p.title as project_label";
+$sql .= " p.rowid as project_id, p.ref as project_ref, p.title as project_label,";
+$sql .= " u.login";
 if ($search_categ_cus) $sql .= ", cc.fk_categorie, cc.fk_soc";
 // Add fields from extrafields
 if (!empty($extrafields->attributes[$object->table_element]['label']))
@@ -272,6 +272,8 @@ if (is_array($extrafields->attributes[$object->table_element]['label']) && count
 if ($sall || $search_product_category > 0) $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'commandedet as pd ON c.rowid=pd.fk_commande';
 if ($search_product_category > 0) $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product as cp ON cp.fk_product=pd.fk_product';
 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."projet as p ON p.rowid = c.fk_projet";
+$sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'user as u ON c.fk_user_author = u.rowid';
+
 // We'll need this table joined to the select in order to filter by sale
 if ($search_sale > 0 || (!$user->rights->societe->client->voir && !$socid)) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
 if ($search_user > 0)
@@ -311,22 +313,27 @@ if ($viewstatut <> '')
 		$sql .= ' AND ((c.fk_statut IN (1,2)) OR (c.fk_statut = 3 AND c.facture = 0))'; // validated, in process or closed but not billed
 	}
 }
-$sql .= dolSqlDateFilter("c.date_commande", $search_orderday, $search_ordermonth, $search_orderyear);
-$sql .= dolSqlDateFilter("c.date_livraison", $search_deliveryday, $search_deliverymonth, $search_deliveryyear);
-if ($search_town)  $sql .= natural_search('s.town', $search_town);
-if ($search_zip)   $sql .= natural_search("s.zip", $search_zip);
-if ($search_state) $sql .= natural_search("state.nom", $search_state);
-if ($search_country) $sql .= " AND s.fk_pays IN (".$search_country.')';
-if ($search_type_thirdparty) $sql .= " AND s.fk_typent IN (".$search_type_thirdparty.')';
-if ($search_company) $sql .= natural_search('s.nom', $search_company);
-if ($search_sale > 0) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$search_sale;
-if ($search_user > 0) $sql .= " AND ec.fk_c_type_contact = tc.rowid AND tc.element='commande' AND tc.source='internal' AND ec.element_id = c.rowid AND ec.fk_socpeople = ".$search_user;
-if ($search_total_ht != '') $sql .= natural_search('c.total_ht', $search_total_ht, 1);
-if ($search_total_ttc != '') $sql .= natural_search('c.total_ttc', $search_total_ttc, 1);
-if ($search_project_ref != '') $sql .= natural_search("p.ref", $search_project_ref);
-if ($search_project != '') $sql .= natural_search("p.title", $search_project);
-if ($search_categ_cus > 0) $sql .= " AND cc.fk_categorie = ".$db->escape($search_categ_cus);
-if ($search_categ_cus == -2)   $sql .= " AND cc.fk_categorie IS NULL";
+
+if ($search_dateorder_start)        $sql .= " AND c.date_commande >= '".$db->idate($search_dateorder_start)."'";
+if ($search_dateorder_end)          $sql .= " AND c.date_commande <= '".$db->idate($search_dateorder_end)."'";
+if ($search_datedelivery_start)		$sql .= " AND c.date_livraison >= '".$db->idate($search_datedelivery_start)."'";
+if ($search_datedelivery_end)		$sql .= " AND c.date_livraison <= '".$db->idate($search_datedelivery_end)."'";
+if ($search_town)					$sql .= natural_search('s.town', $search_town);
+if ($search_zip)					$sql .= natural_search("s.zip", $search_zip);
+if ($search_state)					$sql .= natural_search("state.nom", $search_state);
+if ($search_country)				$sql .= " AND s.fk_pays IN (".$search_country.')';
+if ($search_type_thirdparty)		$sql .= " AND s.fk_typent IN (".$search_type_thirdparty.')';
+if ($search_company)				$sql .= natural_search('s.nom', $search_company);
+if ($search_sale > 0)				$sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$search_sale;
+if ($search_user > 0)				$sql .= " AND ec.fk_c_type_contact = tc.rowid AND tc.element='commande' AND tc.source='internal' AND ec.element_id = c.rowid AND ec.fk_socpeople = ".$search_user;
+if ($search_total_ht != '')			$sql .= natural_search('c.total_ht', $search_total_ht, 1);
+if ($search_total_ttc != '')		$sql .= natural_search('c.total_ttc', $search_total_ttc, 1);
+if ($search_login)       $sql .= natural_search("u.login", $search_login);
+if ($search_project_ref != '')		$sql .= natural_search("p.ref", $search_project_ref);
+if ($search_project != '')			$sql .= natural_search("p.title", $search_project);
+if ($search_categ_cus > 0)			$sql .= " AND cc.fk_categorie = ".$db->escape($search_categ_cus);
+if ($search_categ_cus == -2)		$sql .= " AND cc.fk_categorie IS NULL";
+
 // Add where from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
 // Add where from hooks
@@ -402,34 +409,33 @@ if ($resql)
 
 	if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
 	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
-	if ($sall)					$param .= '&sall='.urlencode($sall);
-	if ($socid > 0)             $param .= '&socid='.urlencode($socid);
-	if ($viewstatut != '')      $param .= '&viewstatut='.urlencode($viewstatut);
-	if ($search_orderday)      		$param .= '&search_orderday='.urlencode($search_orderday);
-	if ($search_ordermonth)      		$param .= '&search_ordermonth='.urlencode($search_ordermonth);
-	if ($search_orderyear)       		$param .= '&search_orderyear='.urlencode($search_orderyear);
-	if ($search_deliveryday)   		$param .= '&search_deliveryday='.urlencode($search_deliveryday);
-	if ($search_deliverymonth)   		$param .= '&search_deliverymonth='.urlencode($search_deliverymonth);
-	if ($search_deliveryyear)    		$param .= '&search_deliveryyear='.urlencode($search_deliveryyear);
-	if ($search_ref)      		$param .= '&search_ref='.urlencode($search_ref);
-	if ($search_company)  		$param .= '&search_company='.urlencode($search_company);
-	if ($search_ref_customer)	$param .= '&search_ref_customer='.urlencode($search_ref_customer);
-	if ($search_user > 0) 		$param .= '&search_user='.urlencode($search_user);
-	if ($search_sale > 0) 		$param .= '&search_sale='.urlencode($search_sale);
-	if ($search_total_ht != '') $param .= '&search_total_ht='.urlencode($search_total_ht);
-	if ($search_total_vat != '')  $param .= '&search_total_vat='.urlencode($search_total_vat);
-	if ($search_total_ttc != '')  $param .= '&search_total_ttc='.urlencode($search_total_ttc);
-	if ($search_project_ref >= 0) $param .= "&search_project_ref=".urlencode($search_project_ref);
-	if ($search_town != '')       $param .= '&search_town='.urlencode($search_town);
-	if ($search_zip != '')        $param .= '&search_zip='.urlencode($search_zip);
-	if ($search_state != '')      $param .= '&search_state='.urlencode($search_state);
-	if ($search_country != '')    $param .= '&search_country='.urlencode($search_country);
+	if ($sall)						$param .= '&sall='.urlencode($sall);
+	if ($socid > 0)					$param .= '&socid='.urlencode($socid);
+	if ($viewstatut != '')			$param .= '&viewstatut='.urlencode($viewstatut);
+	if ($search_dateorder_start)    $param .= '&search_dateorder_start='.urlencode($search_dateorder_start);
+	if ($search_dateorder_end)      $param .= '&search_dateorder_end='.urlencode($search_dateorder_end);
+	if ($search_datedelivery_start) $param .= '&search_datedelivery_start='.urlencode($search_datedelivery_start);
+	if ($search_datedelivery_end)   $param .= '&search_datedelivery_end='.urlencode($search_datedelivery_end);
+	if ($search_ref)      			$param .= '&search_ref='.urlencode($search_ref);
+	if ($search_company)  			$param .= '&search_company='.urlencode($search_company);
+	if ($search_ref_customer)		$param .= '&search_ref_customer='.urlencode($search_ref_customer);
+	if ($search_user > 0) 			$param .= '&search_user='.urlencode($search_user);
+	if ($search_sale > 0) 			$param .= '&search_sale='.urlencode($search_sale);
+	if ($search_total_ht != '') 	$param .= '&search_total_ht='.urlencode($search_total_ht);
+	if ($search_total_vat != '')  	$param .= '&search_total_vat='.urlencode($search_total_vat);
+	if ($search_total_ttc != '')  	$param .= '&search_total_ttc='.urlencode($search_total_ttc);
+	if ($search_login)  	 $param .= '&search_login='.urlencode($search_login);
+	if ($search_project_ref >= 0) 	$param .= "&search_project_ref=".urlencode($search_project_ref);
+	if ($search_town != '')       	$param .= '&search_town='.urlencode($search_town);
+	if ($search_zip != '')        	$param .= '&search_zip='.urlencode($search_zip);
+	if ($search_state != '')      	$param .= '&search_state='.urlencode($search_state);
+	if ($search_country != '')    	$param .= '&search_country='.urlencode($search_country);
 	if ($search_type_thirdparty != '')  $param .= '&search_type_thirdparty='.urlencode($search_type_thirdparty);
 	if ($search_product_category != '') $param .= '&search_product_category='.urlencode($search_product_category);
-	if ($search_categ_cus > 0)          $param .= '&search_categ_cus='.urlencode($search_categ_cus);
-	if ($show_files)            $param .= '&show_files='.urlencode($show_files);
-	if ($optioncss != '')       $param .= '&optioncss='.urlencode($optioncss);
-	if ($billed != '')			$param .= '&billed='.urlencode($billed);
+	if ($search_categ_cus > 0)      $param .= '&search_categ_cus='.urlencode($search_categ_cus);
+	if ($show_files)            	$param .= '&show_files='.urlencode($show_files);
+	if ($optioncss != '')       	$param .= '&optioncss='.urlencode($optioncss);
+	if ($billed != '')				$param .= '&billed='.urlencode($billed);
 
 	// Add $param from extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
@@ -646,18 +652,28 @@ if ($resql)
 	// Date order
 	if (!empty($arrayfields['c.date_commande']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_orderday" value="'.$search_orderday.'">';
-		print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_ordermonth" value="'.$search_ordermonth.'">';
-		$formother->select_year($search_orderyear ? $search_orderyear : -1, 'search_orderyear', 1, 20, 5);
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_dateorder_start ? $search_dateorder_start : -1, 'search_dateorder_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_dateorder_end ? $search_dateorder_end : -1, 'search_dateorder_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	if (!empty($arrayfields['c.date_delivery']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_deliveryday" value="'.$search_deliveryday.'">';
-		print '<input class="flat width25 valignmiddle" type="text" maxlength="2" name="search_deliverymonth" value="'.$search_deliverymonth.'">';
-		$formother->select_year($search_deliveryyear ? $search_deliveryyear : -1, 'search_deliveryyear', 1, 20, 5);
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_datedelivery_start ? $search_datedelivery_start : -1, 'search_datedelivery_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_datedelivery_end ? $search_datedelivery_end : -1, 'search_datedelivery_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	if (!empty($arrayfields['c.total_ht']['checked']))
@@ -681,6 +697,13 @@ if ($resql)
 		print '<input class="flat" type="text" size="5" name="search_total_ttc" value="'.$search_total_ttc.'">';
 		print '</td>';
 	}
+	if (!empty($arrayfields['u.login']['checked']))
+	{
+		// Author
+		print '<td class="liste_titre" align="center">';
+		print '<input class="flat" size="4" type="text" name="search_login" value="'.dol_escape_htmltag($search_login).'">';
+		print '</td>';
+	}
 	// Extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php';
 	// Fields from hook
@@ -752,6 +775,8 @@ if ($resql)
 	if (!empty($arrayfields['c.total_ht']['checked']))       print_liste_field_titre($arrayfields['c.total_ht']['label'], $_SERVER["PHP_SELF"], 'c.total_ht', '', $param, '', $sortfield, $sortorder, 'right ');
 	if (!empty($arrayfields['c.total_vat']['checked']))      print_liste_field_titre($arrayfields['c.total_vat']['label'], $_SERVER["PHP_SELF"], 'c.tva', '', $param, '', $sortfield, $sortorder, 'right ');
 	if (!empty($arrayfields['c.total_ttc']['checked']))      print_liste_field_titre($arrayfields['c.total_ttc']['label'], $_SERVER["PHP_SELF"], 'c.total_ttc', '', $param, '', $sortfield, $sortorder, 'right ');
+	if (!empty($arrayfields['u.login']['checked']))       	  print_liste_field_titre($arrayfields['u.login']['label'], $_SERVER["PHP_SELF"], 'u.login', '', $param, 'align="center"', $sortfield, $sortorder);
+
 	// Extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_title.tpl.php';
 	// Hook fields
@@ -773,7 +798,7 @@ if ($resql)
 
 	$generic_commande = new Commande($db);
 	$generic_product = new Product($db);
-
+	$userstatic = new User($db);
 	$i = 0;
 	$totalarray = array();
 	while ($i < min($num, $limit))
@@ -818,7 +843,7 @@ if ($resql)
 		{
 			print '<td class="nowrap">';
 
-			$generic_commande->getLinesArray();		// This set ->lines
+			$generic_commande->getLinesArray(); // This set ->lines
 
 			print $generic_commande->getNomUrl(1, ($viewstatut != 2 ? 0 : $obj->fk_statut), 0, 0, 0, 1, 1);
 
@@ -1050,7 +1075,7 @@ if ($resql)
 		// Amount HT
 		if (!empty($arrayfields['c.total_ht']['checked']))
 		{
-			  print '<td class="right">'.price($obj->total_ht)."</td>\n";
+			  print '<td class="nowrap right">'.price($obj->total_ht)."</td>\n";
 			  if (!$i) $totalarray['nbfield']++;
 			  if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'c.total_ht';
 			  $totalarray['val']['c.total_ht'] += $obj->total_ht;
@@ -1058,7 +1083,7 @@ if ($resql)
 		// Amount VAT
 		if (!empty($arrayfields['c.total_vat']['checked']))
 		{
-			print '<td class="right">'.price($obj->total_tva)."</td>\n";
+			print '<td class="nowrap right">'.price($obj->total_tva)."</td>\n";
 			if (!$i) $totalarray['nbfield']++;
 			if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'c.total_tva';
 			$totalarray['val']['c.total_tva'] += $obj->total_tva;
@@ -1066,12 +1091,25 @@ if ($resql)
 		// Amount TTC
 		if (!empty($arrayfields['c.total_ttc']['checked']))
 		{
-			print '<td class="right">'.price($obj->total_ttc)."</td>\n";
+			print '<td class="nowrap right">'.price($obj->total_ttc)."</td>\n";
 			if (!$i) $totalarray['nbfield']++;
 			if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'c.total_ttc';
 			$totalarray['val']['c.total_ttc'] += $obj->total_ttc;
 		}
 
+		$userstatic->id = $obj->fk_user_author;
+		$userstatic->login = $obj->login;
+
+		// Author
+		if (!empty($arrayfields['u.login']['checked']))
+		{
+			print '<td align="center">';
+			if ($userstatic->id) print $userstatic->getLoginUrl(1);
+			else print '&nbsp;';
+			print "</td>\n";
+			if (!$i) $totalarray['nbfield']++;
+		}
+
 		// Extra fields
 		include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
 		// Fields from hook

+ 1 - 1
htdocs/compta/bank/card.php

@@ -690,7 +690,7 @@ else
 		// Categories
 		if ($conf->categorie->enabled) {
 			print '<tr><td class="titlefield">'.$langs->trans("Categories").'</td><td>';
-			print $form->showCategories($object->id, 'bank_account', 1);
+			print $form->showCategories($object->id, Categorie::TYPE_ACCOUNT, 1);
 			print "</td></tr>";
 		}
 

+ 109 - 77
htdocs/compta/bank/various_payment/list.php

@@ -1,5 +1,5 @@
 <?php
-/* Copyright (C) 2017       Alexandre Spangaro      <aspangaro@open-dsi.fr>
+/* Copyright (C) 2017-2019	Alexandre Spangaro      <aspangaro@open-dsi.fr>
  * Copyright (C) 2017       Laurent Destailleur     <eldy@users.sourceforge.net>
  * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
  *
@@ -31,24 +31,28 @@ require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
 
 // Load translation files required by the page
-$langs->loadLangs(array("compta","banks","bills","accountancy"));
+$langs->loadLangs(array("compta", "banks", "bills", "accountancy"));
 
 // Security check
 $socid = GETPOST("socid", "int");
-if ($user->socid) $socid=$user->socid;
+if ($user->socid) $socid = $user->socid;
 $result = restrictedArea($user, 'banque', '', '', '');
 
 $optioncss = GETPOST('optioncss', 'alpha');
 
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $search_ref = GETPOST('search_ref', 'int');
 $search_user = GETPOST('search_user', 'alpha');
 $search_label = GETPOST('search_label', 'alpha');
+$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
+$search_date_end = dol_mktime(23, 59, 59, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
 $search_amount_deb = GETPOST('search_amount_deb', 'alpha');
 $search_amount_cred = GETPOST('search_amount_cred', 'alpha');
 $search_account = GETPOST('search_account', 'int');
-$search_date = dol_mktime(0, 0, 0, GETPOST('date_docmonth', 'int'), GETPOST('date_docday', 'int'), GETPOST('date_docyear', 'int'));
-$search_accountancy_code = GETPOST("search_accountancy_code");
+$search_accountancy_account = GETPOST("search_accountancy_account");
+if ($search_accountancy_account == - 1) $search_accountancy_account = '';
+$search_accountancy_subledger = GETPOST("search_accountancy_subledger");
+if ($search_accountancy_subledger == - 1) $search_accountancy_subledger = '';
 
 $sortfield = GETPOST("sortfield", 'alpha');
 $sortorder = GETPOST("sortorder", 'alpha');
@@ -57,36 +61,38 @@ if (empty($page) || $page == -1) { $page = 0; }	 // If $page is not defined, or
 $offset = $conf->liste_limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortfield) $sortfield="v.datep,v.rowid";
-if (! $sortorder) $sortorder="DESC";
+if (!$sortfield) $sortfield = "v.datep,v.rowid";
+if (!$sortorder) $sortorder = "DESC";
 
-$filtre=GETPOST("filtre", 'alpha');
+$filtre = GETPOST("filtre", 'alpha');
 
-if (! GETPOST('typeid'))
+if (!GETPOST('typeid'))
 {
-	$newfiltre=str_replace('filtre=', '', $filtre);
-	$filterarray=explode('-', $newfiltre);
-	foreach($filterarray as $val)
+	$newfiltre = str_replace('filtre=', '', $filtre);
+	$filterarray = explode('-', $newfiltre);
+	foreach ($filterarray as $val)
 	{
-		$part=explode(':', $val);
-		if ($part[0] == 'v.fk_typepayment') $typeid=$part[1];
+		$part = explode(':', $val);
+		if ($part[0] == 'v.fk_typepayment') $typeid = $part[1];
 	}
 }
 else
 {
-	$typeid=GETPOST('typeid');
+	$typeid = GETPOST('typeid');
 }
 
 if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x', 'alpha') || GETPOST('button_removefilter', 'alpha')) // All test are required to be compatible with all browsers
 {
-	$search_ref="";
-	$search_label="";
-	$search_amount_deb="";
-	$search_amount_cred="";
-	$search_account='';
-	$typeid="";
-	$search_date = '';
-	$search_accountancy_code = '';
+	$search_ref = "";
+	$search_label = "";
+	$search_date_start = '';
+	$search_date_end = '';
+	$search_amount_deb = "";
+	$search_amount_cred = "";
+	$search_account = '';
+	$search_accountancy_account = '';
+	$search_accountancy_subledger = '';
+	$typeid = "";
 }
 
 /*
@@ -100,59 +106,63 @@ $formaccounting = new FormAccounting($db);
 $variousstatic = new PaymentVarious($db);
 $accountstatic = new Account($db);
 
-$sql = "SELECT v.rowid, v.sens, v.amount, v.label, v.datep as datep, v.datev as datev, v.fk_typepayment as type, v.num_payment, v.fk_bank, v.accountancy_code,";
-$sql.= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number as bank_account_number, ba.fk_accountancy_journal as accountancy_journal, ba.label as blabel,";
-$sql.= " pst.code as payment_code";
-$sql.= " FROM ".MAIN_DB_PREFIX."payment_various as v";
-$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pst ON v.fk_typepayment = pst.id";
-$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON v.fk_bank = b.rowid";
-$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid";
-$sql.= " WHERE v.entity IN (".getEntity('payment_various').")";
+$sql = "SELECT v.rowid, v.sens, v.amount, v.label, v.datep as datep, v.datev as datev, v.fk_typepayment as type, v.num_payment, v.fk_bank, v.accountancy_code, v.subledger_account,";
+$sql .= " ba.rowid as bid, ba.ref as bref, ba.number as bnumber, ba.account_number as bank_account_number, ba.fk_accountancy_journal as accountancy_journal, ba.label as blabel,";
+$sql .= " pst.code as payment_code";
+$sql .= " FROM ".MAIN_DB_PREFIX."payment_various as v";
+$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_paiement as pst ON v.fk_typepayment = pst.id";
+$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank as b ON v.fk_bank = b.rowid";
+$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."bank_account as ba ON b.fk_account = ba.rowid";
+$sql .= " WHERE v.entity IN (".getEntity('payment_various').")";
 
 // Search criteria
-if ($search_ref)					$sql.=" AND v.rowid=".$db->escape($search_ref);
-if ($search_label)					$sql.=natural_search(array('v.label'), $search_label);
-if ($search_amount_deb)				$sql.=natural_search("v.amount", $search_amount_deb, 1);
-if ($search_amount_cred)			$sql.=natural_search("v.amount", $search_amount_cred, 1);
-if ($search_account > 0)			$sql.=" AND b.fk_account=".$db->escape($search_account);
-if ($search_date)					$sql.=" AND v.datep = '".$db->idate($search_date)."'";
-if ($search_accountancy_code > 0)	$sql.=" AND v.accountancy_code=".$db->escape($search_accountancy_code);
-if ($typeid > 0) $sql .= " AND v.fk_typepayment=".$typeid;
+if ($search_ref)						$sql .= " AND v.rowid=".$db->escape($search_ref);
+if ($search_label)						$sql .= natural_search(array('v.label'), $search_label);
+if ($search_date_start)					$sql .= " AND v.datep >= '".$db->idate($search_date_start)."'";
+if ($search_date_end)           	    $sql .= " AND v.datep <= '".$db->idate($search_date_end)."'";
+if ($search_amount_deb)					$sql .= natural_search("v.amount", $search_amount_deb, 1);
+if ($search_amount_cred)				$sql .= natural_search("v.amount", $search_amount_cred, 1);
+if ($search_account > 0)				$sql .= " AND b.fk_account=".$db->escape($search_account);
+if ($search_accountancy_account > 0)	$sql .= " AND v.accountancy_code=".$db->escape($search_accountancy_account);
+if ($search_accountancy_subledger > 0)	$sql .= " AND v.subledger_account=".$db->escape($search_accountancy_subledger);
+if ($typeid > 0)						$sql .= " AND v.fk_typepayment=".$typeid;
 if ($filtre) {
-	$filtre=str_replace(":", "=", $filtre);
+	$filtre = str_replace(":", "=", $filtre);
 	$sql .= " AND ".$filtre;
 }
 
-$sql.= $db->order($sortfield, $sortorder);
+$sql .= $db->order($sortfield, $sortorder);
 
-$totalnboflines=0;
-$result=$db->query($sql);
+$totalnboflines = 0;
+$result = $db->query($sql);
 if ($result)
 {
 	$totalnboflines = $db->num_rows($result);
 }
-$sql.= $db->plimit($limit+1, $offset);
+$sql .= $db->plimit($limit + 1, $offset);
 
 $result = $db->query($sql);
 if ($result)
 {
 	$num = $db->num_rows($result);
 	$i = 0;
-	$total = 0 ;
-
-	$param='';
-	if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
-	if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
-	if ($search_ref)			$param.='&search_ref='.urlencode($search_ref);
-	if ($search_label)			$param.='&search_label='.urlencode($search_label);
-	if ($typeid > 0)            $param.='&typeid='.urlencode($typeid);
-	if ($search_amount_deb)     $param.='&search_amount_deb='.urlencode($search_amount_deb);
-	if ($search_amount_cred)    $param.='&search_amount_cred='.urlencode($search_amount_cred);
-	if ($search_account > 0)			$param.='&search_amount='.urlencode($search_account);
-	//if ($search_date)					$param.='&search_date='.$search_date;
-	if ($search_accountancy_code > 0)	$param.='&search_accountancy_code='.urlencode($search_accountancy_code);
-
-	if ($optioncss != '') $param.='&amp;optioncss='.urlencode($optioncss);
+	$total = 0;
+
+	$param = '';
+	if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
+	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
+	if ($search_ref)						$param .= '&search_ref='.urlencode($search_ref);
+	if ($search_label)						$param .= '&search_label='.urlencode($search_label);
+	if ($search_date_start)					$param .= '&search_date_start='.urlencode($search_date_start);
+	if ($search_date_end)					$param .= '&search_date_end='.urlencode($search_date_end);
+	if ($typeid > 0)            			$param .= '&typeid='.urlencode($typeid);
+	if ($search_amount_deb)     			$param .= '&search_amount_deb='.urlencode($search_amount_deb);
+	if ($search_amount_cred)    			$param .= '&search_amount_cred='.urlencode($search_amount_cred);
+	if ($search_account > 0)				$param .= '&search_amount='.urlencode($search_account);
+	if ($search_accountancy_account > 0)	$param .= '&search_accountancy_account='.urlencode($search_accountancy_account);
+	if ($search_accountancy_subledger > 0)	$param .= '&search_accountancy_subledger='.urlencode($search_accountancy_subledger);
+
+	if ($optioncss != '') $param .= '&amp;optioncss='.urlencode($optioncss);
 
 	$newcardbutton = '';
 	if ($user->rights->banque->modifier)
@@ -188,7 +198,13 @@ if ($result)
 	// Date
 	print '<td class="liste_titre center">';
 	print '<div class="nowrap">';
-	print $form->selectDate($search_date, 'date_doc', 0, 0, 1);
+	print $langs->trans('From').' ';
+	print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1);
+	print '</div>';
+	print '<div class="nowrap">';
+	print $langs->trans('to').' ';
+	print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1);
+
 	print '</div>';
 	print '</td>';
 
@@ -208,9 +224,17 @@ if ($result)
 	// Accounting account
 	if (!empty($conf->accounting->enabled))
 	{
+		// Accounting account
 		print '<td class="liste_titre">';
 		print '<div class="nowrap">';
-		print $formaccounting->select_account($search_accountancy_code, 'search_accountancy_code', 1, array(), 1, 1, 'maxwidth200');
+		print $formaccounting->select_account($search_accountancy_account, 'search_accountancy_account', 1, array(), 1, 1, 'maxwidth200');
+		print '</div>';
+		print '</td>';
+
+		// Subledger account
+		print '<td class="liste_titre">';
+		print '<div class="nowrap">';
+		print $formaccounting->select_auxaccount($search_accountancy_subledger, 'search_accountancy_subledger', 1, 'maxwidth200');
 		print '</div>';
 		print '</td>';
 	}
@@ -222,7 +246,7 @@ if ($result)
 	print '<td class="liste_titre right"><input name="search_amount_cred" class="flat" type="text" size="8" value="'.$search_amount_cred.'"></td>';
 
 	print '<td class="liste_titre maxwidthsearch">';
-	$searchpicto=$form->showFilterAndCheckAddButtons(0);
+	$searchpicto = $form->showFilterAndCheckAddButtons(0);
 	print $searchpicto;
 	print '</td>';
 
@@ -235,7 +259,8 @@ if ($result)
 	print_liste_field_titre("DatePayment", $_SERVER["PHP_SELF"], "v.datep,v.rowid", "", $param, '', $sortfield, $sortorder, 'center ');
 	print_liste_field_titre("PaymentMode", $_SERVER["PHP_SELF"], "type", "", $param, '', $sortfield, $sortorder, 'left ');
 	if (!empty($conf->banque->enabled))     print_liste_field_titre("BankAccount", $_SERVER["PHP_SELF"], "ba.label", "", $param, "", $sortfield, $sortorder);
-	if (!empty($conf->accounting->enabled)) print_liste_field_titre("AccountAccounting", $_SERVER["PHP_SELF"], "v.accountancy_code", "", $param, '', $sortfield, $sortorder, 'left ');
+	if (!empty($conf->accounting->enabled)) print_liste_field_titre("AccountAccountingShort", $_SERVER["PHP_SELF"], "v.accountancy_code", "", $param, '', $sortfield, $sortorder, 'left ');
+	if (!empty($conf->accounting->enabled)) print_liste_field_titre("SubledgerAccount", $_SERVER["PHP_SELF"], "v.subledger_account", "", $param, '', $sortfield, $sortorder, 'left ');
 	print_liste_field_titre("Debit", $_SERVER["PHP_SELF"], "v.amount", "", $param, '', $sortfield, $sortorder, 'right ');
 	print_liste_field_titre("Credit", $_SERVER["PHP_SELF"], "v.amount", "", $param, '', $sortfield, $sortorder, 'right ');
 	print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch ');
@@ -254,19 +279,19 @@ if ($result)
 
 		// Ref
 		print "<td>".$variousstatic->getNomUrl(1)."</td>\n";
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 
 		// Label payment
 		print "<td>".dol_trunc($obj->label, 40)."</td>\n";
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 
 		// Date payment
 		print '<td class="center">'.dol_print_date($db->jdate($obj->datep), 'day')."</td>\n";
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 
 		// Type
 		print '<td>'.$langs->trans("PaymentTypeShort".$obj->payment_code).' '.$obj->num_payment.'</td>';
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 
 		// Account
 		if (!empty($conf->banque->enabled))
@@ -291,7 +316,7 @@ if ($result)
 			}
 			else print '&nbsp;';
 			print '</td>';
-			if (! $i) $totalarray['nbfield']++;
+			if (!$i) $totalarray['nbfield']++;
 		}
 
 		// Accounting account
@@ -300,7 +325,14 @@ if ($result)
 			$accountingaccount->fetch('', $obj->accountancy_code, 1);
 
 			print '<td>'.$accountingaccount->getNomUrl(0, 1, 1, '', 1).'</td>';
-			if (! $i) $totalarray['nbfield']++;
+			if (!$i) $totalarray['nbfield']++;
+		}
+
+		// Accounting subledger account
+		if (!empty($conf->accounting->enabled))
+		{
+			print '<td>'.length_accounta($obj->subledger_account).'</td>';
+			if (!$i) $totalarray['nbfield']++;
 		}
 
 		// Debit
@@ -310,9 +342,9 @@ if ($result)
 			print price($obj->amount);
 			$totalarray['val']['total_deb'] += $obj->amount;
 		}
-		if (! $i) $totalarray['nbfield']++;
-		if (! $i) $totalarray['pos'][$totalarray['nbfield']]='total_deb';
-		print "</td>";
+		if (!$i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'total_deb';
+		print '</td>';
 
 		// Credit
 		print '<td class="nowrap right">';
@@ -321,12 +353,12 @@ if ($result)
 			print price($obj->amount);
 			$totalarray['val']['total_cred'] += $obj->amount;
 		}
-		if (! $i) $totalarray['nbfield']++;
-		if (! $i) $totalarray['pos'][$totalarray['nbfield']]='total_cred';
-		print '</td>' ;
+		if (!$i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'total_cred';
+		print '</td>';
 		print '<td></td>';
 
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 
 		print "</tr>\n";
 

+ 27 - 27
htdocs/compta/cashcontrol/report.php

@@ -39,15 +39,15 @@ $langs->load("bills");
 
 $id = GETPOST('id', 'int');
 
-$_GET['optioncss']="print";
-$cashcontrol= new CashControl($db);
+$_GET['optioncss'] = "print";
+$cashcontrol = new CashControl($db);
 $cashcontrol->fetch($id);
 
 //$limit = GETPOST('limit')?GETPOST('limit', 'int'):$conf->liste_limit;
-$sortorder='ASC';
-$sortfield='b.datev,b.dateo,b.rowid';
+$sortorder = 'ASC';
+$sortfield = 'b.datev,b.dateo,b.rowid';
 
-$arrayfields=array(
+$arrayfields = array(
     'b.rowid'=>array('label'=>$langs->trans("Ref"), 'checked'=>1),
     'b.dateo'=>array('label'=>$langs->trans("DateOperationShort"), 'checked'=>1),
     'b.num_chq'=>array('label'=>$langs->trans("Number"), 'checked'=>1),
@@ -99,12 +99,12 @@ $sql.=" OR b.fk_account=".$conf->global->CASHDESK_ID_BANKACCOUNT_CHEQUE;
 $sql.=")";
 */
 $sql = "SELECT f.rowid as facid, f.ref, f.datef as do, pf.amount as amount, b.fk_account as bankid, cp.code";
-$sql.= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."paiement as p, ".MAIN_DB_PREFIX."c_paiement as cp, ".MAIN_DB_PREFIX."bank as b";
-$sql.= " WHERE pf.fk_facture = f.rowid AND p.rowid = pf.fk_paiement AND cp.id = p.fk_paiement AND p.fk_bank = b.rowid";
-$sql.= " AND f.module_source = '".$db->escape($posmodule)."'";
-$sql.= " AND f.pos_source = '".$db->escape($terminalid)."'";
-$sql.= " AND f.paye = 1";
-$sql.= " AND p.entity IN (".getEntity('facture').")";
+$sql .= " FROM ".MAIN_DB_PREFIX."paiement_facture as pf, ".MAIN_DB_PREFIX."facture as f, ".MAIN_DB_PREFIX."paiement as p, ".MAIN_DB_PREFIX."c_paiement as cp, ".MAIN_DB_PREFIX."bank as b";
+$sql .= " WHERE pf.fk_facture = f.rowid AND p.rowid = pf.fk_paiement AND cp.id = p.fk_paiement AND p.fk_bank = b.rowid";
+$sql .= " AND f.module_source = '".$db->escape($posmodule)."'";
+$sql .= " AND f.pos_source = '".$db->escape($terminalid)."'";
+$sql .= " AND f.paye = 1";
+$sql .= " AND p.entity IN (".getEntity('facture').")";
 /*if ($key == 'cash')       $sql.=" AND cp.code = 'LIQ'";
 elseif ($key == 'cheque') $sql.=" AND cp.code = 'CHQ'";
 elseif ($key == 'card')   $sql.=" AND cp.code = 'CB'";
@@ -113,9 +113,9 @@ else
 	dol_print_error('Value for key = '.$key.' not supported');
 	exit;
 }*/
-if ($syear && ! $smonth)              $sql.= " AND datef BETWEEN '".$db->idate(dol_get_first_day($syear, 1))."' AND '".$db->idate(dol_get_last_day($syear, 12))."'";
-elseif ($syear && $smonth && ! $sday) $sql.= " AND datef BETWEEN '".$db->idate(dol_get_first_day($syear, $smonth))."' AND '".$db->idate(dol_get_last_day($syear, $smonth))."'";
-elseif ($syear && $smonth && $sday)   $sql.= " AND datef BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $smonth, $sday, $syear))."' AND '".$db->idate(dol_mktime(23, 59, 59, $smonth, $sday, $syear))."'";
+if ($syear && !$smonth)              $sql .= " AND datef BETWEEN '".$db->idate(dol_get_first_day($syear, 1))."' AND '".$db->idate(dol_get_last_day($syear, 12))."'";
+elseif ($syear && $smonth && !$sday) $sql .= " AND datef BETWEEN '".$db->idate(dol_get_first_day($syear, $smonth))."' AND '".$db->idate(dol_get_last_day($syear, $smonth))."'";
+elseif ($syear && $smonth && $sday)   $sql .= " AND datef BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $smonth, $sday, $syear))."' AND '".$db->idate(dol_mktime(23, 59, 59, $smonth, $sday, $syear))."'";
 else dol_print_error('', 'Year not defined');
 
 $resql = $db->query($sql);
@@ -125,7 +125,7 @@ if ($resql)
 	$i = 0;
 
 	print "<center><h2>";
-	if ($cashcontrol->status==2) print $langs->trans("CashControl")." ".$cashcontrol->id;
+	if ($cashcontrol->status == 2) print $langs->trans("CashControl")." ".$cashcontrol->id;
 	else print $langs->trans("CashControl")." - ".$langs->trans("Draft");
 	print "<br>".$langs->trans("DateCreationShort").": ".dol_print_date($cashcontrol->date_creation, 'dayhour')."</h2></center>";
 
@@ -154,7 +154,7 @@ if ($resql)
 
 	// Loop on each record
 	$sign = 1;
-	$cash=$bank=$cheque=$other=0;
+	$cash = $bank = $cheque = $other = 0;
 
     $totalarray = array();
     $cachebankaccount = array();
@@ -167,7 +167,7 @@ if ($resql)
         {
             $bankaccounttmp = new Account($db);
             $bankaccounttmp->fetch($objp->bankid);
-            $cachebankaccount[$objp->bankid]=$bankaccounttmp;
+            $cachebankaccount[$objp->bankid] = $bankaccounttmp;
             $bankaccount = $bankaccounttmp;
         }
         else
@@ -192,21 +192,21 @@ if ($resql)
         print '<td class="nowrap left">';
         print $invoicetmp->getNomUrl(1);
         print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 
         // Date ope
     	print '<td class="nowrap left">';
     	print '<span id="dateoperation_'.$objp->rowid.'">'.dol_print_date($db->jdate($objp->do), "day")."</span>";
     	print "</td>\n";
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 
     	// Bank account
         print '<td class="nowrap right">';
 		print $bankaccount->getNomUrl(1);
-		if ($cashcontrol->posmodule=="takepos"){
+		if ($cashcontrol->posmodule == "takepos") {
 			$var1 = 'CASHDESK_ID_BANKACCOUNT_CASH'.$cashcontrol->posnumber;
 		}
-		else{
+		else {
 			$var1 = 'CASHDESK_ID_BANKACCOUNT_CASH';
 		}
 		if ($objp->code == 'CHQ') {
@@ -220,14 +220,14 @@ if ($resql)
 			else $other += $objp->amount;
 		}
 		print "</td>\n";
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 
         // Type
         print '<td class="right">';
        	print $objp->code;
        	if (empty($amountpertype[$objp->code])) $amountpertype[$objp->code] = 0;
         print "</td>\n";
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 
         // Debit
     	print '<td class="right">';
@@ -238,8 +238,8 @@ if ($resql)
     	    $amountpertype[$objp->code] += $objp->amount;
     	}
     	print "</td>\n";
-    	if (! $i) $totalarray['nbfield']++;
-    	if (! $i) $totalarray['pos'][$totalarray['nbfield']]='totaldebfield';
+    	if (!$i) $totalarray['nbfield']++;
+    	if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'totaldebfield';
 
     	// Credit
     	print '<td class="right">';
@@ -250,8 +250,8 @@ if ($resql)
     	    $amountpertype[$objp->code] -= $objp->amount;
     	}
     	print "</td>\n";
-    	if (! $i) $totalarray['nbfield']++;
-    	if (! $i) $totalarray['pos'][$totalarray['nbfield']]='totalcredfield';
+    	if (!$i) $totalarray['nbfield']++;
+    	if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'totalcredfield';
 
 		print "</tr>";
 

+ 35 - 16
htdocs/compta/facture/card.php

@@ -298,14 +298,14 @@ if (empty($reshook))
 			// Note: Other solution if you want to add a negative line on invoice, is to create a discount for customer and consumme it (but this is possible on standard invoice only).
 			$array_of_pu_ht_per_vat_rate = array();
 			$array_of_pu_ht_devise_per_vat_rate = array();
-			foreach($object->lines as $line) {
+			foreach ($object->lines as $line) {
 				if (empty($array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code])) $array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] = 0;
 				if (empty($array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code])) $array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] = 0;
 				$array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] += $line->subprice;
 				$array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] += $line->multicurrency_subprice;
 			}
 			//var_dump($array_of_pu_ht_per_vat_rate);exit;
-			foreach($array_of_pu_ht_per_vat_rate as $vatrate => $tmpvalue)
+			foreach ($array_of_pu_ht_per_vat_rate as $vatrate => $tmpvalue)
 			{
 				$pu_ht = $array_of_pu_ht_per_vat_rate[$vatrate];
 				$pu_ht_devise = $array_of_pu_ht_devise_per_vat_rate[$vatrate];
@@ -818,11 +818,11 @@ if (empty($reshook))
 			}
 
 			// If some payments were already done, we change the amount to pay using same prorate
-			if (! empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED)) {
-				$alreadypaid = $object->getSommePaiement();		// This can be not 0 if we allow to create credit to reuse from credit notes partially refunded.
+			if (!empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED)) {
+				$alreadypaid = $object->getSommePaiement(); // This can be not 0 if we allow to create credit to reuse from credit notes partially refunded.
 				if ($alreadypaid && abs($alreadypaid) < abs($object->total_ttc)) {
 					$ratio = abs(($object->total_ttc - $alreadypaid) / $object->total_ttc);
-					foreach($amount_ht as $vatrate => $val) {
+					foreach ($amount_ht as $vatrate => $val) {
 						$amount_ht[$vatrate] = price2num($amount_ht[$vatrate] * $ratio, 'MU');
 						$amount_tva[$vatrate] = price2num($amount_tva[$vatrate] * $ratio, 'MU');
 						$amount_ttc[$vatrate] = price2num($amount_ttc[$vatrate] * $ratio, 'MU');
@@ -1386,12 +1386,12 @@ if (empty($reshook))
 						dol_syslog("Try to find source object origin=".$object->origin." originid=".$object->origin_id." to add lines or deposit lines");
 						$result = $srcobject->fetch($object->origin_id);
 
+						$typeamount = GETPOST('typedeposit', 'aZ09');
+						$valuedeposit = GETPOST('valuedeposit', 'int');
+
 						// If deposit invoice
-						if ($_POST['type'] == Facture::TYPE_DEPOSIT)
+						if ($_POST['type'] == Facture::TYPE_DEPOSIT && in_array($typeamount, array('amount', 'variable')))
 						{
-							$typeamount = GETPOST('typedeposit', 'alpha');
-							$valuedeposit = GETPOST('valuedeposit', 'int');
-
 							$amountdeposit = array();
 							if (!empty($conf->global->MAIN_DEPOSIT_MULTI_TVA))
 							{
@@ -1419,7 +1419,7 @@ if (empty($reshook))
 								{
 									$amountdeposit[0] = $valuedeposit;
 								}
-								else
+								elseif ($typeamount == 'variable')
 								{
 									if ($result > 0)
 									{
@@ -1449,11 +1449,15 @@ if (empty($reshook))
 
 								$amount_ttc_diff = $amountdeposit[0];
 							}
+
 							foreach ($amountdeposit as $tva => $amount)
 							{
 								if (empty($amount)) continue;
 
-								$arraylist = array('amount' => 'FixAmount', 'variable' => 'VarAmount');
+								$arraylist = array(
+									'amount' => 'FixAmount',
+									'variable' => 'VarAmount'
+								);
 								$descline = '(DEPOSIT)';
 								//$descline.= ' - '.$langs->trans($arraylist[$typeamount]);
 								if ($typeamount == 'amount') {
@@ -1500,7 +1504,8 @@ if (empty($reshook))
 								$object->updateline($object->lines[0]->id, $object->lines[0]->desc, $subprice_diff, $object->lines[0]->qty, $object->lines[0]->remise_percent, $object->lines[0]->date_start, $object->lines[0]->date_end, $object->lines[0]->tva_tx, 0, 0, 'HT', $object->lines[0]->info_bits, $object->lines[0]->product_type, 0, 0, 0, $object->lines[0]->pa_ht, $object->lines[0]->label, 0, array(), 100);
 							}
 						}
-						else
+
+						if ($_POST['type'] != Facture::TYPE_DEPOSIT || ($_POST['type'] == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines'))
 						{
 							if ($result > 0)
 							{
@@ -1511,6 +1516,16 @@ if (empty($reshook))
 									$lines = $srcobject->lines;
 								}
 
+								// If we create a deposit with all lines and a percent, we change amount
+								if ($_POST['type'] == Facture::TYPE_DEPOSIT && $typeamount == 'variablealllines') {
+									if (is_array($lines)) {
+										foreach($lines as $line) {
+											// We keep ->subprice and ->pa_ht, but we change the qty
+											$line->qty = price2num($line->qty * $valuedeposit / 100, 'MS');
+										}
+									}
+								}
+
 								$fk_parent_line = 0;
 								$num = count($lines);
 								for ($i = 0; $i < $num; $i++)
@@ -2994,8 +3009,12 @@ if ($action == 'create')
 			if (($origin == 'propal') || ($origin == 'commande'))
 			{
 				print '<td class="nowrap" style="padding-left: 5px">';
-				$arraylist = array('amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')), 'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')));
-				print $form->selectarray('typedeposit', $arraylist, GETPOST('typedeposit'), 0, 0, 0, '', 1);
+				$arraylist = array(
+					'amount' => $langs->transnoentitiesnoconv('FixAmount', $langs->transnoentitiesnoconv('Deposit')),
+					'variable' => $langs->transnoentitiesnoconv('VarAmountOneLine', $langs->transnoentitiesnoconv('Deposit')),
+					'variablealllines' => $langs->transnoentitiesnoconv('VarAmountAllLines')
+				);
+				print $form->selectarray('typedeposit', $arraylist, GETPOST('typedeposit', 'aZ09'), 0, 0, 0, '', 1);
 				print '</td>';
 				print '<td class="nowrap" style="padding-left: 5px">'.$langs->trans('Value').':<input type="text" id="valuedeposit" name="valuedeposit" size="3" value="'.GETPOST('valuedeposit', 'int').'"/>';
 			}
@@ -3903,7 +3922,7 @@ elseif ($id > 0 || !empty($ref))
 
 	$morehtmlref = '<div class="refidno">';
 	// Ref invoice
-	if ($object->status == $object::STATUS_DRAFT && ! $mysoc->isInEEC() && ! empty($conf->global->INVOICE_ALLOW_FREE_REF)) {
+	if ($object->status == $object::STATUS_DRAFT && !$mysoc->isInEEC() && !empty($conf->global->INVOICE_ALLOW_FREE_REF)) {
 		$morehtmlref .= $form->editfieldkey("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', 0, 1);
 		$morehtmlref .= $form->editfieldval("Ref", 'ref', $object->ref, $object, $usercancreate, 'string', '', null, null, '', 1);
 		$morehtmlref .= '<br>';
@@ -5095,7 +5114,7 @@ elseif ($id > 0 || !empty($ref))
 				}
 				// For credit note
 				if ($object->type == Facture::TYPE_CREDIT_NOTE && $object->statut == 1 && $object->paye == 0 && $usercancreate
-					&& (! empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED) || $object->getSommePaiement() == 0)
+					&& (!empty($conf->global->INVOICE_ALLOW_REUSE_OF_CREDIT_WHEN_PARTIALLY_REFUNDED) || $object->getSommePaiement() == 0)
 					) {
 					print '<a class="butAction'.($conf->use_javascript_ajax ? ' reposition' : '').'" href="'.$_SERVER["PHP_SELF"].'?facid='.$object->id.'&amp;action=converttoreduc" title="'.dol_escape_htmltag($langs->trans("ConfirmConvertToReduc2")).'">'.$langs->trans('ConvertToReduc').'</a>';
 				}

+ 77 - 4
htdocs/compta/facture/class/facture-rec.class.php

@@ -71,7 +71,6 @@ class FactureRec extends CommonInvoice
 
 	public $number;
 	public $date;
-	public $amount;
 	public $remise;
 	public $tva;
 	public $total;
@@ -93,6 +92,81 @@ class FactureRec extends CommonInvoice
 
 	public $suspended; // status
 
+	/**
+	 *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
+	 *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
+	 *  'label' the translation key.
+	 *  'enabled' is a condition when the field must be managed.
+	 *  'position' is the sort order of field.
+	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
+	 *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
+	 *  'noteditable' says if field is not editable (1 or 0)
+	 *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
+	 *  'index' if we want an index in database.
+	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
+	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
+	 *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
+	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
+	 *  'help' is a string visible as a tooltip on field
+	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
+	 *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
+	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
+	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
+	 *
+	 *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
+	 */
+
+	// BEGIN MODULEBUILDER PROPERTIES
+	/**
+	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
+	 */
+	public $fields=array(
+		'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
+		'titre' =>array('type'=>'varchar(100)', 'label'=>'Titre', 'enabled'=>1, 'visible'=>-1, 'position'=>15),
+		'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
+		'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>25),
+		'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>30),
+		//'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
+		'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
+		//'remise_percent' =>array('type'=>'double', 'label'=>'Remise percent', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
+		//'remise_absolue' =>array('type'=>'double', 'label'=>'Remise absolue', 'enabled'=>1, 'visible'=>-1, 'position'=>50),
+		'tva' =>array('type'=>'double(24,8)', 'label'=>'Tva', 'enabled'=>1, 'visible'=>-1, 'position'=>55, 'isameasure'=>1),
+		'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'isameasure'=>1),
+		'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>65, 'isameasure'=>1),
+		'total' =>array('type'=>'double(24,8)', 'label'=>'Total', 'enabled'=>1, 'visible'=>-1, 'position'=>70, 'isameasure'=>1),
+		'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>75, 'isameasure'=>1),
+		'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
+		'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Fk projet', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
+		'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'Fk cond reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
+		'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'Fk mode reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
+		'date_lim_reglement' =>array('type'=>'date', 'label'=>'Date lim reglement', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
+		'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>105),
+		'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>110),
+		'modelpdf' =>array('type'=>'varchar(255)', 'label'=>'Modelpdf', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
+		'last_gen' =>array('type'=>'varchar(7)', 'label'=>'Last gen', 'enabled'=>1, 'visible'=>-1, 'position'=>120),
+		'unit_frequency' =>array('type'=>'varchar(2)', 'label'=>'Unit frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>125),
+		'date_when' =>array('type'=>'datetime', 'label'=>'Date when', 'enabled'=>1, 'visible'=>-1, 'position'=>130),
+		'date_last_gen' =>array('type'=>'datetime', 'label'=>'Date last gen', 'enabled'=>1, 'visible'=>-1, 'position'=>135),
+		'nb_gen_done' =>array('type'=>'integer', 'label'=>'Nb gen done', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
+		'nb_gen_max' =>array('type'=>'integer', 'label'=>'Nb gen max', 'enabled'=>1, 'visible'=>-1, 'position'=>145),
+		'frequency' =>array('type'=>'integer', 'label'=>'Frequency', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
+		'usenewprice' =>array('type'=>'integer', 'label'=>'UseNewPrice', 'enabled'=>1, 'visible'=>0, 'position'=>155),
+		'revenuestamp' =>array('type'=>'double(24,8)', 'label'=>'RevenueStamp', 'enabled'=>1, 'visible'=>-1, 'position'=>160, 'isameasure'=>1),
+		'auto_validate' =>array('type'=>'integer', 'label'=>'Auto validate', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
+		'generate_pdf' =>array('type'=>'integer', 'label'=>'Generate pdf', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
+		'fk_account' =>array('type'=>'integer', 'label'=>'Fk account', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
+		'fk_multicurrency' =>array('type'=>'integer', 'label'=>'Fk multicurrency', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
+		'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'Multicurrency code', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
+		'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency tx', 'enabled'=>1, 'visible'=>-1, 'position'=>190, 'isameasure'=>1),
+		'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>1, 'visible'=>-1, 'position'=>195, 'isameasure'=>1),
+		'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>1, 'visible'=>-1, 'position'=>200, 'isameasure'=>1),
+		'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>1, 'visible'=>-1, 'position'=>205, 'isameasure'=>1),
+		'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>210),
+		'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>215),
+		'suspended' =>array('type'=>'integer', 'label'=>'Suspended', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
+	);
+	// END MODULEBUILDER PROPERTIES
+
 	const STATUS_NOTSUSPENDED = 0;
 	const STATUS_SUSPENDED = 1;
 
@@ -377,7 +451,7 @@ class FactureRec extends CommonInvoice
 	 */
 	public function fetch($rowid, $ref = '', $ref_ext = '', $ref_int = '')
 	{
-		$sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.amount, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
+		$sql = 'SELECT f.rowid, f.entity, f.titre as title, f.suspended, f.fk_soc, f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc';
 		$sql .= ', f.remise_percent, f.remise_absolue, f.remise';
 		$sql .= ', f.date_lim_reglement as dlr';
 		$sql .= ', f.note_private, f.note_public, f.fk_user_author';
@@ -419,7 +493,6 @@ class FactureRec extends CommonInvoice
 				$this->type                   = $obj->type;
 				$this->datep                  = $obj->dp;
 				$this->date                   = $obj->df;
-				$this->amount                 = $obj->amount;
 				$this->remise_percent         = $obj->remise_percent;
 				$this->remise_absolue         = $obj->remise_absolue;
 				$this->remise                 = $obj->remise;
@@ -1602,7 +1675,7 @@ class FactureRec extends CommonInvoice
 			$xnbp++;
 		}
 
-		$this->usenewprice = 1;
+		$this->usenewprice = 0;
 	}
 
 	/**

+ 104 - 7
htdocs/compta/facture/class/facture.class.php

@@ -221,6 +221,102 @@ class Facture extends CommonInvoice
 	 */
 	public $retained_warranty_fk_cond_reglement;
 
+
+	/**
+	 *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
+	 *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
+	 *  'label' the translation key.
+	 *  'enabled' is a condition when the field must be managed.
+	 *  'position' is the sort order of field.
+	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
+	 *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
+	 *  'noteditable' says if field is not editable (1 or 0)
+	 *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
+	 *  'index' if we want an index in database.
+	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
+	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
+	 *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
+	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
+	 *  'help' is a string visible as a tooltip on field
+	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
+	 *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
+	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
+	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
+	 *
+	 *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
+	 */
+
+	// BEGIN MODULEBUILDER PROPERTIES
+	/**
+	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
+	 */
+	public $fields=array(
+		'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
+		'ref' =>array('type'=>'varchar(30)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'showoncombobox'=>1, 'position'=>15),
+		'entity' =>array('type'=>'integer', 'label'=>'Entity', 'default'=>1, 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'position'=>20, 'index'=>1),
+		'ref_ext' =>array('type'=>'varchar(255)', 'label'=>'Ref ext', 'enabled'=>1, 'visible'=>0, 'position'=>25),
+		'ref_int' =>array('type'=>'varchar(255)', 'label'=>'Ref int', 'enabled'=>1, 'visible'=>0, 'position'=>30),
+		'type' =>array('type'=>'smallint(6)', 'label'=>'Type', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
+		'ref_client' =>array('type'=>'varchar(255)', 'label'=>'Ref client', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
+		'increment' =>array('type'=>'varchar(10)', 'label'=>'Increment', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
+		'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>50),
+		'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
+		'datef' =>array('type'=>'date', 'label'=>'DateInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
+		'date_valid' =>array('type'=>'date', 'label'=>'DateValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
+		'date_closing' =>array('type'=>'datetime', 'label'=>'Date closing', 'enabled'=>1, 'visible'=>-1, 'position'=>70),
+		'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>75),
+		'paye' =>array('type'=>'smallint(6)', 'label'=>'InvoicePaidCompletely', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>80),
+		//'amount' =>array('type'=>'double(24,8)', 'label'=>'Amount', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>85),
+		'remise_percent' =>array('type'=>'double', 'label'=>'Remise percent', 'enabled'=>1, 'visible'=>-1, 'position'=>90),
+		'remise_absolue' =>array('type'=>'double', 'label'=>'Remise absolue', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
+		'remise' =>array('type'=>'double', 'label'=>'Remise', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
+		'close_code' =>array('type'=>'varchar(16)', 'label'=>'EarlyClosingReason', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
+		'close_note' =>array('type'=>'varchar(128)', 'label'=>'EarlyClosingComment', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
+		'tva' =>array('type'=>'double(24,8)', 'label'=>'TotalVAT', 'enabled'=>1, 'visible'=>-1, 'position'=>115, 'isameasure'=>1),
+		'localtax1' =>array('type'=>'double(24,8)', 'label'=>'Localtax1', 'enabled'=>1, 'visible'=>-1, 'position'=>120, 'isameasure'=>1),
+		'localtax2' =>array('type'=>'double(24,8)', 'label'=>'Localtax2', 'enabled'=>1, 'visible'=>-1, 'position'=>125, 'isameasure'=>1),
+		'revenuestamp' =>array('type'=>'double(24,8)', 'label'=>'RevenueStamp', 'enabled'=>1, 'visible'=>-1, 'position'=>130, 'isameasure'=>1),
+		'total' =>array('type'=>'double(24,8)', 'label'=>'TotalHT', 'enabled'=>1, 'visible'=>-1, 'position'=>135, 'isameasure'=>1),
+		'total_ttc' =>array('type'=>'double(24,8)', 'label'=>'TotalTTC', 'enabled'=>1, 'visible'=>-1, 'position'=>140, 'isameasure'=>1),
+		'fk_statut' =>array('type'=>'smallint(6)', 'label'=>'Status', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>500, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 2=>'Paid', 3=>'Abandonned')),
+		'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>150),
+		'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>155),
+		'fk_user_valid' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'enabled'=>1, 'visible'=>-1, 'position'=>160),
+		'fk_user_closing' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserClosing', 'enabled'=>1, 'visible'=>-1, 'position'=>165),
+		'fk_facture_source' =>array('type'=>'integer', 'label'=>'SourceInvoice', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
+		'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Project', 'enabled'=>1, 'visible'=>-1, 'position'=>175),
+		'fk_account' =>array('type'=>'integer', 'label'=>'Fk account', 'enabled'=>1, 'visible'=>-1, 'position'=>180),
+		'fk_currency' =>array('type'=>'varchar(3)', 'label'=>'CurrencyCode', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
+		'fk_cond_reglement' =>array('type'=>'integer', 'label'=>'PaymentTerm', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>190),
+		'fk_mode_reglement' =>array('type'=>'integer', 'label'=>'PaymentMode', 'enabled'=>1, 'visible'=>-1, 'position'=>195),
+		'date_lim_reglement' =>array('type'=>'date', 'label'=>'DateDue', 'enabled'=>1, 'visible'=>-1, 'position'=>200),
+		'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>205),
+		'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>210),
+		'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>215),
+		'extraparams' =>array('type'=>'varchar(255)', 'label'=>'Extraparams', 'enabled'=>1, 'visible'=>-1, 'position'=>225),
+		'situation_cycle_ref' =>array('type'=>'smallint(6)', 'label'=>'Situation cycle ref', 'enabled'=>'$conf->global->INVOICE_USE_SITUATION', 'visible'=>-1, 'position'=>230),
+		'situation_counter' =>array('type'=>'smallint(6)', 'label'=>'Situation counter', 'enabled'=>'$conf->global->INVOICE_USE_SITUATION', 'visible'=>-1, 'position'=>235),
+		'situation_final' =>array('type'=>'smallint(6)', 'label'=>'Situation final', 'enabled'=>'empty($conf->global->INVOICE_USE_SITUATION) ? 0 : 1', 'visible'=>-1, 'position'=>240),
+		'retained_warranty' =>array('type'=>'double', 'label'=>'Retained warranty', 'enabled'=>'$conf->global->INVOICE_USE_SITUATION_RETAINED_WARRANTY', 'visible'=>-1, 'position'=>245),
+		'retained_warranty_date_limit' =>array('type'=>'date', 'label'=>'Retained warranty date limit', 'enabled'=>'$conf->global->INVOICE_USE_SITUATION_RETAINED_WARRANTY', 'visible'=>-1, 'position'=>250),
+		'retained_warranty_fk_cond_reglement' =>array('type'=>'integer', 'label'=>'Retained warranty fk cond reglement', 'enabled'=>'$conf->global->INVOICE_USE_SITUATION_RETAINED_WARRANTY', 'visible'=>-1, 'position'=>255),
+		'fk_incoterms' =>array('type'=>'integer', 'label'=>'IncotermsCode', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>260),
+		'location_incoterms' =>array('type'=>'varchar(255)', 'label'=>'IncotermsLocation', 'enabled'=>'$conf->incoterm->enabled', 'visible'=>-1, 'position'=>265),
+		'date_pointoftax' =>array('type'=>'date', 'label'=>'DatePointOfTax', 'enabled'=>'$conf->global->INVOICE_POINTOFTAX_DATE', 'visible'=>-1, 'position'=>270),
+		'fk_multicurrency' =>array('type'=>'integer', 'label'=>'MulticurrencyID', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>275),
+		'multicurrency_code' =>array('type'=>'varchar(255)', 'label'=>'MulticurrencyCode', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>280),
+		'multicurrency_tx' =>array('type'=>'double(24,8)', 'label'=>'MulticurrencyRate', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>285),
+		'multicurrency_total_ht' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ht', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>290),
+		'multicurrency_total_tva' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total tva', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>295),
+		'multicurrency_total_ttc' =>array('type'=>'double(24,8)', 'label'=>'Multicurrency total ttc', 'enabled'=>'$conf->multicurrency->enabled', 'visible'=>-1, 'position'=>300),
+		'fk_fac_rec_source' =>array('type'=>'integer', 'label'=>'RecurringInvoiceSource', 'enabled'=>1, 'visible'=>-1, 'position'=>305),
+		'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>310),
+		'module_source' =>array('type'=>'varchar(32)', 'label'=>'POSModule', 'enabled'=>1, 'visible'=>-1, 'position'=>315),
+		'pos_source' =>array('type'=>'varchar(32)', 'label'=>'POSTerminal', 'enabled'=>1, 'visible'=>-1, 'position'=>320),
+		'import_key' =>array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'position'=>220),
+	);
+	// END MODULEBUILDER PROPERTIES
+
     /**
      * Standard invoice
      */
@@ -284,6 +380,7 @@ class Facture extends CommonInvoice
 	const CLOSECODE_ABANDONED = 'abandon'; // Abandonned - other
 	const CLOSECODE_REPLACED = 'replaced'; // Closed after doing a replacement invoice
 
+
 	/**
 	 * 	Constructor
 	 *
@@ -1175,7 +1272,7 @@ class Facture extends CommonInvoice
 		$this->availability_id      = $object->availability_id;
 		$this->demand_reason_id     = $object->demand_reason_id;
 		$this->date_livraison       = $object->date_livraison;
-		$this->fk_delivery_address  = $object->fk_delivery_address;		// deprecated
+		$this->fk_delivery_address  = $object->fk_delivery_address; // deprecated
 		$this->contact_id           = $object->contactid;
 		$this->ref_client           = $object->ref_client;
 
@@ -1354,7 +1451,7 @@ class Facture extends CommonInvoice
 
 		if (empty($rowid) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1;
 
-		$sql = 'SELECT f.rowid,f.entity,f.ref,f.ref_client,f.ref_ext,f.ref_int,f.type,f.fk_soc,f.amount';
+		$sql = 'SELECT f.rowid,f.entity,f.ref,f.ref_client,f.ref_ext,f.ref_int,f.type,f.fk_soc';
 		$sql .= ', f.tva, f.localtax1, f.localtax2, f.total, f.total_ttc, f.revenuestamp';
 		$sql .= ', f.remise_percent, f.remise_absolue, f.remise';
 		$sql .= ', f.datef as df, f.date_pointoftax';
@@ -1591,7 +1688,7 @@ class Facture extends CommonInvoice
 				$line->special_code = $objp->special_code;
 				$line->fk_parent_line = $objp->fk_parent_line;
 				$line->situation_percent = $objp->situation_percent;
-				$line->fk_prev_id       = $objp->fk_prev_id;
+				$line->fk_prev_id = $objp->fk_prev_id;
 				$line->fk_unit = $objp->fk_unit;
 
 				// Accountancy
@@ -2035,7 +2132,7 @@ class Facture extends CommonInvoice
 				}
 			}
 
-			// If we decrement stock on invoice validation, we increment
+			// If we decrease stock on invoice validation, we increase back if a warehouse id was provided
 			if ($this->type != self::TYPE_DEPOSIT && $result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL) && $idwarehouse != -1)
 			{
 				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
@@ -2646,7 +2743,7 @@ class Facture extends CommonInvoice
 				$this->oldcopy = clone $this;
 			}
 
-			// Si on decremente le produit principal et ses composants a la validation de facture, on réincrement
+			// If we decrease stock on invoice validation, we increase back
 			if ($this->type != self::TYPE_DEPOSIT && $result >= 0 && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL))
 			{
 				require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
@@ -3134,7 +3231,7 @@ class Facture extends CommonInvoice
 				$this->line->rang = $rangmax + 1;
 			}
 
-			$this->line->id					= $rowid;
+			$this->line->id = $rowid;
 			$this->line->rowid				= $rowid;
 			$this->line->label				= $label;
 			$this->line->desc = $desc;
@@ -3175,7 +3272,7 @@ class Facture extends CommonInvoice
 
 			if (is_array($array_options) && count($array_options) > 0) {
 				// We replace values in this->line->array_options only for entries defined into $array_options
-				foreach($array_options as $key => $value) {
+				foreach ($array_options as $key => $value) {
 					$this->line->array_options[$key] = $array_options[$key];
 				}
 			}

+ 37 - 31
htdocs/compta/facture/list.php

@@ -13,6 +13,7 @@
  * Copyright (C) 2015-2016 Ferran Marcet         <fmarcet@2byte.es>
  * Copyright (C) 2017      Josep Lluís Amador    <joseplluis@lliuretic.cat>
  * Copyright (C) 2018      Charlene Benke        <charlie@patas-monkey.com>
+ * Copyright (C) 2019	   Alexandre Spangaro	 <aspangaro@open-dsi.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -98,12 +99,10 @@ $search_country = GETPOST("search_country", 'int');
 $search_type_thirdparty = GETPOST("search_type_thirdparty", 'int');
 $search_user = GETPOST('search_user', 'int');
 $search_sale = GETPOST('search_sale', 'int');
-$search_day = GETPOST('search_day', 'int');
-$search_month = GETPOST('search_month', 'int');
-$search_year	= GETPOST('search_year', 'int');
-$search_day_lim		= GETPOST('search_day_lim', 'int');
-$search_month_lim = GETPOST('search_month_lim', 'int');
-$search_year_lim	= GETPOST('search_year_lim', 'int');
+$search_date_start = dol_mktime(0, 0, 0, GETPOST('search_date_startmonth', 'int'), GETPOST('search_date_startday', 'int'), GETPOST('search_date_startyear', 'int'));
+$search_date_end = dol_mktime(23, 59, 59, GETPOST('search_date_endmonth', 'int'), GETPOST('search_date_endday', 'int'), GETPOST('search_date_endyear', 'int'));
+$search_datelimit_start = dol_mktime(0, 0, 0, GETPOST('search_datelimit_startmonth', 'int'), GETPOST('search_datelimit_startday', 'int'), GETPOST('search_datelimit_startyear', 'int'));
+$search_datelimit_end = dol_mktime(23, 59, 59, GETPOST('search_datelimit_endmonth', 'int'), GETPOST('search_datelimit_endday', 'int'), GETPOST('search_datelimit_endyear', 'int'));
 $search_categ_cus = trim(GETPOST("search_categ_cus", 'int'));
 $search_btn = GETPOST('button_search', 'alpha');
 $search_remove_btn = GETPOST('button_removefilter', 'alpha');
@@ -248,14 +247,12 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter',
 	$search_type = '';
 	$search_country = '';
 	$search_type_thirdparty = '';
-	$search_day = '';
-	$search_year = '';
-	$search_month = '';
+	$search_date_start = '';
+	$search_date_end = '';
+	$search_datelimit_start = '';
+	$search_datelimit_end = '';
 	$option = '';
 	$filter = '';
-	$search_day_lim = '';
-	$search_year_lim = '';
-	$search_month_lim = '';
 	$toselect = '';
 	$search_array_options = array();
 	$search_categ_cus = 0;
@@ -478,12 +475,15 @@ if ($search_status != '-1' && $search_status != '')
 		$sql .= " AND f.fk_statut IN (".$db->escape($search_status).")"; // When search_status is '1,2' for example
 	}
 }
+
 if ($search_paymentmode > 0)  $sql .= " AND f.fk_mode_reglement = ".$db->escape($search_paymentmode);
 if ($search_paymentterms > 0) $sql .= " AND f.fk_cond_reglement = ".$db->escape($search_paymentterms);
 if ($search_module_source)    $sql .= natural_search("f.module_source", $search_module_source);
 if ($search_pos_source)       $sql .= natural_search("f.pos_source", $search_pos_source);
-$sql .= dolSqlDateFilter("f.datef", $search_day, $search_month, $search_year);
-$sql .= dolSqlDateFilter("f.date_lim_reglement", $search_day_lim, $search_month_lim, $search_year_lim);
+if ($search_date_start)       $sql .= " AND f.datef >= '".$db->idate($search_date_start)."'";
+if ($search_date_end)         $sql .= " AND f.datef <= '".$db->idate($search_date_end)."'";
+if ($search_datelimit_start)  $sql .= " AND f.date_lim_reglement >= '".$db->idate($search_datelimit_start)."'";
+if ($search_datelimit_end)    $sql .= " AND f.date_lim_reglement <= '".$db->idate($search_datelimit_end)."'";
 if ($option == 'late') $sql .= " AND f.date_lim_reglement < '".$db->idate(dol_now() - $conf->facture->client->warning_delay)."'";
 if ($search_sale > 0)  $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".(int) $search_sale;
 if ($search_user > 0)
@@ -571,12 +571,10 @@ if ($resql)
 	if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
 	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
 	if ($sall)				 $param .= '&sall='.urlencode($sall);
-	if ($search_day)         $param .= '&search_day='.urlencode($search_day);
-	if ($search_month)       $param .= '&search_month='.urlencode($search_month);
-	if ($search_year)        $param .= '&search_year='.urlencode($search_year);
-	if ($search_day_lim)     $param .= '&search_day_lim='.urlencode($search_day_lim);
-	if ($search_month_lim)   $param .= '&search_month_lim='.urlencode($search_month_lim);
-	if ($search_year_lim)    $param .= '&search_year_lim='.urlencode($search_year_lim);
+	if ($search_date_start)				$param .= '&search_date_start='.urlencode($search_date_start);
+	if ($search_date_end)				$param .= '&search_date_end='.urlencode($search_date_end);
+	if ($search_datelimit_start)		$param .= '&search_datelimit_start='.urlencode($search_datelimit_start);
+	if ($search_datelimit_end)			$param .= '&search_datelimit_end='.urlencode($search_datelimit_end);
 	if ($search_ref)         $param .= '&search_ref='.urlencode($search_ref);
 	if ($search_refcustomer) $param .= '&search_refcustomer='.urlencode($search_refcustomer);
 	if ($search_project_ref) $param .= '&search_project_ref='.urlencode($search_project_ref);
@@ -752,20 +750,29 @@ if ($resql)
 	// Date invoice
 	if (!empty($arrayfields['f.date']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_day" value="'.dol_escape_htmltag($search_day).'">';
-		print '<input class="flat valignmiddle width25" type="text" size="1" maxlength="2" name="search_month" value="'.dol_escape_htmltag($search_month).'">';
-		$formother->select_year($search_year ? $search_year : -1, 'search_year', 1, 20, 5, 0, 0, '', 'widthauto valignmiddle');
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_date_start ? $search_date_start : -1, 'search_date_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_date_end ? $search_date_end : -1, 'search_date_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	// Date due
 	if (!empty($arrayfields['f.date_lim_reglement']['checked']))
 	{
-		print '<td class="liste_titre nowraponall" align="center">';
-		if (!empty($conf->global->MAIN_LIST_FILTER_ON_DAY)) print '<input class="flat valignmiddle" type="text" size="1" maxlength="2" name="search_day_lim" value="'.dol_escape_htmltag($search_day_lim).'">';
-		print '<input class="flat valignmiddle width25" type="text" size="1" maxlength="2" name="search_month_lim" value="'.dol_escape_htmltag($search_month_lim).'">';
-		$formother->select_year($search_year_lim ? $search_year_lim : -1, 'search_year_lim', 1, 20, 5, 0, 0, '', 'widthauto valignmiddle');
-		print '<br><input type="checkbox" name="search_option" value="late"'.($option == 'late' ? ' checked' : '').'> '.$langs->trans("Alert");
+		print '<td class="liste_titre center">';
+		print '<div class="nowrap">';
+		print $langs->trans('From').' ';
+		print $form->selectDate($search_datelimit_start ? $search_datelimit_start : -1, 'search_datelimit_start', 0, 0, 1);
+		print '</div>';
+		print '<div class="nowrap">';
+		print $langs->trans('to').' ';
+		print $form->selectDate($search_datelimit_end ? $search_datelimit_end : -1, 'search_datelimit_end', 0, 0, 1);
+		print '</div>';
 		print '</td>';
 	}
 	// Project ref
@@ -778,7 +785,7 @@ if ($resql)
 	{
 	    print '<td class="liste_titre"><input class="flat maxwidth50imp" type="text" name="search_project" value="'.$search_project.'"></td>';
 	}
-	// Thirpdarty
+	// Thirdparty
 	if (!empty($arrayfields['s.nom']['checked']))
 	{
 		print '<td class="liste_titre"><input class="flat maxwidth75imp" type="text" name="search_societe" value="'.$search_societe.'"></td>';
@@ -1054,7 +1061,6 @@ if ($resql)
                 {
                     print $facturestatic->getNomUrl(1, '', 200, 0, '', 0, 1);
                 }
-				print empty($obj->increment) ? '' : ' ('.$obj->increment.')';
 
 				$filename = dol_sanitizeFileName($obj->ref);
 				$filedir = $conf->facture->dir_output.'/'.dol_sanitizeFileName($obj->ref);

+ 7 - 5
htdocs/compta/paiement.php

@@ -75,6 +75,8 @@ if ($facid > 0)
 // Initialize technical object to manage hooks of paiements. Note that conf->hooks_modules contains array array
 $hookmanager->initHooks(array('paiementcard', 'globalcard'));
 
+$formquestion = array();
+
 
 /*
  * Actions
@@ -859,7 +861,7 @@ if (!GETPOST('action', 'aZ09'))
     if (!$sortorder) $sortorder = 'DESC';
     if (!$sortfield) $sortfield = 'p.datep';
 
-    $sql = 'SELECT p.datep as dp, p.amount, f.amount as fa_amount, f.ref';
+    $sql = 'SELECT p.datep as dp, p.amount, f.total_ttc as fa_amount, f.ref';
     $sql .= ', f.rowid as facid, c.libelle as paiement_type, p.num_paiement';
     $sql .= ' FROM '.MAIN_DB_PREFIX.'paiement as p LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as c ON p.fk_paiement = c.id';
     $sql .= ', '.MAIN_DB_PREFIX.'facture as f';
@@ -882,10 +884,10 @@ if (!GETPOST('action', 'aZ09'))
         print_barre_liste($langs->trans('Payments'), $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', $num);
         print '<table class="noborder centpercent">';
         print '<tr class="liste_titre">';
-        print_liste_field_titre('Invoice', $_SERVER["PHP_SELF"], 'ref', '', '', '', $sortfield, $sortorder);
-        print_liste_field_titre('Date', $_SERVER["PHP_SELF"], 'dp', '', '', '', $sortfield, $sortorder);
-        print_liste_field_titre('Type', $_SERVER["PHP_SELF"], 'libelle', '', '', '', $sortfield, $sortorder);
-        print_liste_field_titre('Amount', $_SERVER["PHP_SELF"], 'fa_amount', '', '', '', $sortfield, $sortorder, 'right ');
+        print_liste_field_titre('Invoice', $_SERVER["PHP_SELF"], 'f.ref', '', '', '', $sortfield, $sortorder);
+        print_liste_field_titre('Date', $_SERVER["PHP_SELF"], 'p.datep', '', '', '', $sortfield, $sortorder);
+        print_liste_field_titre('Type', $_SERVER["PHP_SELF"], 'c.libelle', '', '', '', $sortfield, $sortorder);
+        print_liste_field_titre('Amount', $_SERVER["PHP_SELF"], 'p.amount', '', '', '', $sortfield, $sortorder, 'right ');
 		print_liste_field_titre('', $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'maxwidthsearch ');
         print "</tr>\n";
 

+ 0 - 22
htdocs/compta/paiement/class/paiement.class.php

@@ -327,28 +327,6 @@ class Paiement extends CommonObject
 
 							//var_dump($invoice->total_ttc.' - '.$paiement.' -'.$creditnotes.' - '.$deposits.' - '.$remaintopay);exit;
 
-                            /* Why this ? We can remove i think.
-                            // If there is withdrawals request to do and not done yet on the invoice the payment is on, we wait before closing.
-                            $mustwait=0;
-                            $sqlrequest ="SELECT COUNT(rowid) FROM ".MAIN_DB_PREFIX."prelevement_facture_demande";
-                            $sqlrequest.="WHERE fk_facture = ".$invoice->id." AND traite = 0";
-                            ...
-
-                            $listofpayments=$invoice->getListOfPayments();
-                            foreach($listofpayments as $paym)
-                            {
-                                // This payment on invoice $invoice might be the one we record or another one
-                                if ($paym['type']=='PRE')
-                                {
-                                    if (! empty($conf->prelevement->enabled))
-                                    {
-                                        // if not, $mustwait++;      // This will disable automatic close on invoice to allow to process
-
-                                    }
-                                }
-                            }
-                            */
-
                             //Invoice types that are eligible for changing status to paid
 							$affected_types = array(
 								Facture::TYPE_STANDARD,

+ 7 - 7
htdocs/compta/prelevement/card.php

@@ -362,14 +362,14 @@ if ($id > 0 || $ref)
 
 		$urladd = "&amp;id=".$id;
 
-		print '<form method="get" action="' . $_SERVER ['PHP_SELF'] . '" name="search_form">' . "\n";
-		print '<input type="hidden" name="id" value="' . $id . '"/>';
-		print '<input type="hidden" name="socid" value="' . $socid . '"/>';
-		if (! empty($page)) {
-			print '<input type="hidden" name="page" value="' . $page . '"/>';
+		print '<form method="get" action="'.$_SERVER ['PHP_SELF'].'" name="search_form">'."\n";
+		print '<input type="hidden" name="id" value="'.$id.'"/>';
+		print '<input type="hidden" name="socid" value="'.$socid.'"/>';
+		if (!empty($page)) {
+			print '<input type="hidden" name="page" value="'.$page.'"/>';
 		}
-		if (! empty($limit)) {
-			print '<input type="hidden" name="limit" value="' . $limit . '"/>';
+		if (!empty($limit)) {
+			print '<input type="hidden" name="limit" value="'.$limit.'"/>';
 		}
 		print_barre_liste($langs->trans("Lines"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, '', 0, '', '', $limit);
 

+ 42 - 42
htdocs/compta/prelevement/create.php

@@ -40,19 +40,19 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
 $langs->loadLangs(array('banks', 'categories', 'withdrawals', 'companies', 'bills'));
 
 // Security check
-if ($user->socid) $socid=$user->socid;
+if ($user->socid) $socid = $user->socid;
 $result = restrictedArea($user, 'prelevement', '', '', 'bons');
 
 // Get supervariables
 $action = GETPOST('action', 'alpha');
-$mode = GETPOST('mode', 'alpha')?GETPOST('mode', 'alpha'):'real';
+$mode = GETPOST('mode', 'alpha') ?GETPOST('mode', 'alpha') : 'real';
 $format = GETPOST('format', 'aZ09');
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $page = GETPOST("page", 'int');
 if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined, or '' or -1
 $offset = $limit * $page;
 
-$hookmanager->initHooks(array('directdebitcreatecard','globalcard'));
+$hookmanager->initHooks(array('directdebitcreatecard', 'globalcard'));
 
 
 /*
@@ -68,7 +68,7 @@ if (empty($reshook))
 	// Change customer bank information to withdraw
 	if ($action == 'modify')
 	{
-		for ($i = 1 ; $i < 9 ; $i++)
+		for ($i = 1; $i < 9; $i++)
 		{
 			dolibarr_set_const($db, GETPOST("nom$i"), GETPOST("value$i"), 'chaine', 0, '', $conf->entity);
 		}
@@ -77,7 +77,7 @@ if (empty($reshook))
 	{
 		// $conf->global->PRELEVEMENT_CODE_BANQUE and $conf->global->PRELEVEMENT_CODE_GUICHET should be empty
 		$bprev = new BonPrelevement($db);
-	    $executiondate = dol_mktime(0, 0, 0, GETPOST('remonth'), (GETPOST('reday')+$conf->global->PRELEVEMENT_ADDDAYS), GETPOST('reyear'));
+	    $executiondate = dol_mktime(0, 0, 0, GETPOST('remonth'), (GETPOST('reday') + $conf->global->PRELEVEMENT_ADDDAYS), GETPOST('reyear'));
 
 	    $result = $bprev->create($conf->global->PRELEVEMENT_CODE_BANQUE, $conf->global->PRELEVEMENT_CODE_GUICHET, $mode, $format, $executiondate);
 		if ($result < 0)
@@ -86,12 +86,12 @@ if (empty($reshook))
 		}
 		elseif ($result == 0)
 		{
-			$mesg=$langs->trans("NoInvoiceCouldBeWithdrawed", $format);
+			$mesg = $langs->trans("NoInvoiceCouldBeWithdrawed", $format);
 			setEventMessages($mesg, null, 'errors');
-			$mesg.='<br>'."\n";
-			foreach($bprev->invoice_in_error as $key => $val)
+			$mesg .= '<br>'."\n";
+			foreach ($bprev->invoice_in_error as $key => $val)
 			{
-				$mesg.='<span class="warning">'.$val."</span><br>\n";
+				$mesg .= '<span class="warning">'.$val."</span><br>\n";
 			}
 		}
 		else
@@ -108,8 +108,8 @@ if (empty($reshook))
 
 $form = new Form($db);
 
-$thirdpartystatic=new Societe($db);
-$invoicestatic=new Facture($db);
+$thirdpartystatic = new Societe($db);
+$invoicestatic = new Facture($db);
 $bprev = new BonPrelevement($db);
 
 llxHeader('', $langs->trans("NewStandingOrder"));
@@ -134,10 +134,10 @@ print load_fiche_titre($langs->trans("NewStandingOrder"));
 
 dol_fiche_head();
 
-$nb=$bprev->NbFactureAPrelever();
-$nb1=$bprev->NbFactureAPrelever(1);
-$nb11=$bprev->NbFactureAPrelever(1, 1);
-$pricetowithdraw=$bprev->SommeAPrelever();
+$nb = $bprev->NbFactureAPrelever();
+$nb1 = $bprev->NbFactureAPrelever(1);
+$nb11 = $bprev->NbFactureAPrelever(1, 1);
+$pricetowithdraw = $bprev->SommeAPrelever();
 if ($nb < 0 || $nb1 < 0 || $nb11 < 0)
 {
 	dol_print_error($bprev->error);
@@ -162,17 +162,17 @@ if ($mesg) print $mesg;
 
 print "<div class=\"tabsAction\">\n";
 
-print '<form action="' . $_SERVER['PHP_SELF'] . '?action=create" method="POST">';
-print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
+print '<form action="'.$_SERVER['PHP_SELF'].'?action=create" method="POST">';
+print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
 if ($nb) {
     if ($pricetowithdraw) {
         print $langs->trans('ExecutionDate').' ';
         print $form->selectDate();
         if ($mysoc->isInEEC()) {
             print '<select name="format"><option value="FRST">'.$langs->trans('SEPAFRST').'</option><option value="RCUR">'.$langs->trans('SEPARCUR').'</option></select>';
-            print '<input class="butAction" type="submit" value="' . $langs->trans("CreateForSepa") . '"/>';
+            print '<input class="butAction" type="submit" value="'.$langs->trans("CreateForSepa").'"/>';
         } else {
-            print '<a class="butAction"  type="submit" href="create.php?action=create&format=ALL">' . $langs->trans("CreateAll") . "</a>\n";
+            print '<a class="butAction"  type="submit" href="create.php?action=create&format=ALL">'.$langs->trans("CreateAll")."</a>\n";
 		}
 	}
 	else
@@ -205,20 +205,20 @@ print '<br>';
  */
 
 $sql = "SELECT f.ref, f.rowid, f.total_ttc, s.nom as name, s.rowid as socid,";
-$sql.= " pfd.date_demande, pfd.amount";
-$sql.= " FROM ".MAIN_DB_PREFIX."facture as f,";
-$sql.= " ".MAIN_DB_PREFIX."societe as s,";
-$sql.= " ".MAIN_DB_PREFIX."prelevement_facture_demande as pfd";
-$sql.= " WHERE s.rowid = f.fk_soc";
-$sql.= " AND f.entity IN (".getEntity('invoice').")";
+$sql .= " pfd.date_demande, pfd.amount";
+$sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
+$sql .= " ".MAIN_DB_PREFIX."societe as s,";
+$sql .= " ".MAIN_DB_PREFIX."prelevement_facture_demande as pfd";
+$sql .= " WHERE s.rowid = f.fk_soc";
+$sql .= " AND f.entity IN (".getEntity('invoice').")";
 if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS))
 {
-	$sql.= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
+	$sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
 }
-$sql.= " AND f.total_ttc > 0";
-$sql.= " AND pfd.traite = 0";
-$sql.= " AND pfd.fk_facture = f.rowid";
-if ($socid > 0) $sql.= " AND f.fk_soc = ".$socid;
+$sql .= " AND f.total_ttc > 0";
+$sql .= " AND pfd.traite = 0";
+$sql .= " AND pfd.fk_facture = f.rowid";
+if ($socid > 0) $sql .= " AND f.fk_soc = ".$socid;
 
 $nbtotalofrecords = '';
 if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
@@ -232,24 +232,24 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 	}
 }
 
-$sql.= $db->plimit($limit+1, $offset);
+$sql .= $db->plimit($limit + 1, $offset);
 
-$resql=$db->query($sql);
+$resql = $db->query($sql);
 if ($resql)
 {
 	$num = $db->num_rows($resql);
 	$i = 0;
 
-    $param='';
-	if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
-	if($socid) $param .= '&socid='.urlencode($socid);
-    if($option) $param .= "&option=".urlencode($option);
+    $param = '';
+	if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
+	if ($socid) $param .= '&socid='.urlencode($socid);
+    if ($option) $param .= "&option=".urlencode($option);
 
     print '<form method="POST" id="searchFormList" action="'.$_SERVER["PHP_SELF"].'">';
 	print '<input type="hidden" name="token" value="'.newToken().'">';
 	print '<input type="hidden" name="page" value="'.$page.'">';
-	if (! empty($limit)) {
-		print '<input type="hidden" name="limit" value="' . $limit . '"/>';
+	if (!empty($limit)) {
+		print '<input type="hidden" name="limit" value="'.$limit.'"/>';
 	}
 
     print_barre_liste($langs->trans("InvoiceWaitingWithdraw"), $page, $_SERVER['PHP_SELF'], $param, '', '', '', $num, $nbtotalofrecords, 'invoicing', 0, '', '', $limit);
@@ -266,7 +266,7 @@ if ($resql)
 
 	if ($num)
 	{
-		require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
+		require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
 		$bac = new CompanyBankAccount($db);
 
 		while ($i < $num && $i < $limit)
@@ -275,8 +275,8 @@ if ($resql)
 
 			print '<tr class="oddeven">';
 			print '<td>';
-			$invoicestatic->id=$obj->rowid;
-			$invoicestatic->ref=$obj->ref;
+			$invoicestatic->id = $obj->rowid;
+			$invoicestatic->ref = $obj->ref;
 			print $invoicestatic->getNomUrl(1, 'withdraw');
 			print '</td>';
 			// Thirdparty

+ 37 - 37
htdocs/compta/prelevement/demandes.php

@@ -36,18 +36,18 @@ $langs->loadLangs(array('banks', 'categories', 'withdrawals', 'companies'));
 // Security check
 $socid = GETPOST('socid', 'int');
 $status = GETPOST('status', 'int');
-if ($user->socid) $socid=$user->socid;
+if ($user->socid) $socid = $user->socid;
 $result = restrictedArea($user, 'prelevement', '', '', 'bons');
 
-$contextpage= GETPOST('contextpage', 'aZ')?GETPOST('contextpage', 'aZ'):'myobjectlist';   // To manage different context of search
-$backtopage = GETPOST('backtopage', 'alpha');											// Go back to a dedicated page
-$optioncss  = GETPOST('optioncss', 'aZ');												// Option for the css output (always '' except when 'print')
+$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'myobjectlist'; // To manage different context of search
+$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
+$optioncss  = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
 
 $search_facture = GETPOST('search_facture', 'alpha');
 $search_societe = trim(GETPOST('search_societe', 'alpha'));
 
 // Load variable for pagination
-$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit;
+$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
 $sortfield = GETPOST("sortfield", 'alpha');
 $sortorder = GETPOST("sortorder", 'alpha');
 $page = GETPOST("page", 'int');
@@ -55,8 +55,8 @@ if (empty($page) || $page == -1 || GETPOST('button_search', 'alpha') || GETPOST(
 $offset = $limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortorder) $sortorder="DESC";
-if (! $sortfield) $sortfield="f.ref";
+if (!$sortorder) $sortorder = "DESC";
+if (!$sortfield) $sortfield = "f.ref";
 
 $massactionbutton = '';
 
@@ -96,34 +96,34 @@ else
 
 llxHeader('', $title);
 
-$thirdpartystatic=new Societe($db);
-$invoicestatic=new Facture($db);
+$thirdpartystatic = new Societe($db);
+$invoicestatic = new Facture($db);
 
 // List of requests
 
-$sql= "SELECT f.ref, f.rowid, f.total_ttc,";
-$sql.= " s.nom as name, s.rowid as socid,";
-$sql.= " pfd.date_demande as date_demande,";
-$sql.= " pfd.fk_user_demande";
-$sql.= " FROM ".MAIN_DB_PREFIX."facture as f,";
-$sql.= " ".MAIN_DB_PREFIX."societe as s,";
-$sql.= " ".MAIN_DB_PREFIX."prelevement_facture_demande as pfd";
-if (!$user->rights->societe->client->voir && !$socid) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
-$sql.= " WHERE s.rowid = f.fk_soc";
-$sql.= " AND f.entity IN (".getEntity('invoice').")";
-if (!$user->rights->societe->client->voir && !$socid) $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
-if ($socid) $sql.= " AND f.fk_soc = ".$socid;
-if (!$status) $sql.= " AND pfd.traite = 0";
-if ($status) $sql.= " AND pfd.traite = ".$status;
-$sql.= " AND f.total_ttc > 0";
+$sql = "SELECT f.ref, f.rowid, f.total_ttc,";
+$sql .= " s.nom as name, s.rowid as socid,";
+$sql .= " pfd.date_demande as date_demande,";
+$sql .= " pfd.fk_user_demande";
+$sql .= " FROM ".MAIN_DB_PREFIX."facture as f,";
+$sql .= " ".MAIN_DB_PREFIX."societe as s,";
+$sql .= " ".MAIN_DB_PREFIX."prelevement_facture_demande as pfd";
+if (!$user->rights->societe->client->voir && !$socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
+$sql .= " WHERE s.rowid = f.fk_soc";
+$sql .= " AND f.entity IN (".getEntity('invoice').")";
+if (!$user->rights->societe->client->voir && !$socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
+if ($socid) $sql .= " AND f.fk_soc = ".$socid;
+if (!$status) $sql .= " AND pfd.traite = 0";
+if ($status) $sql .= " AND pfd.traite = ".$status;
+$sql .= " AND f.total_ttc > 0";
 if (empty($conf->global->WITHDRAWAL_ALLOW_ANY_INVOICE_STATUS))
 {
-	$sql.= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
+	$sql .= " AND f.fk_statut = ".Facture::STATUS_VALIDATED;
 }
-$sql.= " AND pfd.fk_facture = f.rowid";
-if ($search_facture) $sql.= natural_search("f.ref", $search_facture);
-if ($search_societe) $sql.= natural_search("s.nom", $search_societe);
-$sql.=$db->order($sortfield, $sortorder);
+$sql .= " AND pfd.fk_facture = f.rowid";
+if ($search_facture) $sql .= natural_search("f.ref", $search_facture);
+if ($search_societe) $sql .= natural_search("s.nom", $search_societe);
+$sql .= $db->order($sortfield, $sortorder);
 
 
 // Count total nb of records
@@ -145,10 +145,10 @@ if (is_numeric($nbtotalofrecords) && $limit > $nbtotalofrecords)
 }
 else
 {
-	$sql.= $db->plimit($limit+1, $offset);
+	$sql .= $db->plimit($limit + 1, $offset);
 
-	$resql=$db->query($sql);
-	if (! $resql)
+	$resql = $db->query($sql);
+	if (!$resql)
 	{
 		dol_print_error($db);
 		exit;
@@ -201,20 +201,20 @@ $i = 0;
 while ($i < min($num, $limit))
 {
 	$obj = $db->fetch_object($resql);
-	if (empty($obj)) break;		// Should not happen
+	if (empty($obj)) break; // Should not happen
 
 	print '<tr class="oddeven">';
 
 	// Ref facture
 	print '<td>';
-	$invoicestatic->id=$obj->rowid;
-	$invoicestatic->ref=$obj->ref;
+	$invoicestatic->id = $obj->rowid;
+	$invoicestatic->ref = $obj->ref;
 	print $invoicestatic->getNomUrl(1, 'withdraw');
 	print '</td>';
 
 	print '<td>';
-	$thirdpartystatic->id=$obj->socid;
-	$thirdpartystatic->name=$obj->name;
+	$thirdpartystatic->id = $obj->socid;
+	$thirdpartystatic->name = $obj->name;
 	print $thirdpartystatic->getNomUrl(1, 'customer');
 	print '</td>';
 

+ 1 - 1
htdocs/compta/recap-compta.php

@@ -117,7 +117,7 @@ if ($id > 0)
 
 		$TData = array();
 
-		$sql = "SELECT s.nom, s.rowid as socid, f.ref, f.amount, f.datef as df,";
+		$sql = "SELECT s.nom, s.rowid as socid, f.ref, f.total_ttc, f.datef as df,";
 		$sql .= " f.paye as paye, f.fk_statut as statut, f.rowid as facid,";
 		$sql .= " u.login, u.rowid as userid";
 		$sql .= " FROM ".MAIN_DB_PREFIX."societe as s,".MAIN_DB_PREFIX."facture as f,".MAIN_DB_PREFIX."user as u";

+ 43 - 43
htdocs/compta/sociales/card.php

@@ -30,26 +30,26 @@ require_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php'
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formsocialcontrib.class.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/tax.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
-if (! empty($conf->projet->enabled))
+if (!empty($conf->projet->enabled))
 {
 	include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 	include_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
 }
-if (! empty($conf->accounting->enabled)) {
-	include_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountingjournal.class.php';
+if (!empty($conf->accounting->enabled)) {
+	include_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
 }
 
 // Load translation files required by the page
 $langs->loadLangs(array('compta', 'bills', 'banks'));
 
-$id=GETPOST('id', 'int');
-$action=GETPOST('action', 'aZ09');
-$confirm=GETPOST('confirm');
+$id = GETPOST('id', 'int');
+$action = GETPOST('action', 'aZ09');
+$confirm = GETPOST('confirm');
 $projectid = (GETPOST('projectid') ? GETPOST('projectid', 'int') : 0);
 
 // Security check
 $socid = GETPOST('socid', 'int');
-if ($user->socid) $socid=$user->socid;
+if ($user->socid) $socid = $user->socid;
 $result = restrictedArea($user, 'tax', $id, 'chargesociales', 'charges');
 
 $object = new ChargeSociales($db);
@@ -159,44 +159,44 @@ if ($action == 'add' && $user->rights->tax->charges->creer)
 		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Amount")), null, 'errors');
 		$action = 'create';
 	}
-	elseif (! is_numeric($amount))
+	elseif (!is_numeric($amount))
 	{
 		setEventMessages($langs->trans("ErrorFieldMustBeANumeric", $langs->transnoentities("Amount")), null, 'errors');
 		$action = 'create';
 	}
 	else
 	{
-		$object->type				= $actioncode;
-		$object->label				= GETPOST('label', 'alpha');
-		$object->date_ech			= $dateech;
+		$object->type = $actioncode;
+		$object->label = GETPOST('label', 'alpha');
+		$object->date_ech = $dateech;
 		$object->periode			= $dateperiod;
 		$object->amount				= $amount;
-		$object->mode_reglement_id	= GETPOST('mode_reglement_id');
+		$object->mode_reglement_id = GETPOST('mode_reglement_id');
 		$object->fk_account			= GETPOST('fk_account', 'int');
 		$object->fk_project			= GETPOST('fk_project');
 
-		$id=$object->create($user);
+		$id = $object->create($user);
 		if ($id <= 0)
 		{
 			setEventMessages($object->error, $object->errors, 'errors');
-			$action='create';
+			$action = 'create';
 		}
 	}
 }
 
 
-if ($action == 'update' && ! $_POST["cancel"] && $user->rights->tax->charges->creer)
+if ($action == 'update' && !$_POST["cancel"] && $user->rights->tax->charges->creer)
 {
-	$dateech=dol_mktime(GETPOST('echhour'), GETPOST('echmin'), GETPOST('echsec'), GETPOST('echmonth'), GETPOST('echday'), GETPOST('echyear'));
-	$dateperiod=dol_mktime(GETPOST('periodhour'), GETPOST('periodmin'), GETPOST('periodsec'), GETPOST('periodmonth'), GETPOST('periodday'), GETPOST('periodyear'));
-	$amount=price2num(GETPOST('amount'));
+	$dateech = dol_mktime(GETPOST('echhour'), GETPOST('echmin'), GETPOST('echsec'), GETPOST('echmonth'), GETPOST('echday'), GETPOST('echyear'));
+	$dateperiod = dol_mktime(GETPOST('periodhour'), GETPOST('periodmin'), GETPOST('periodsec'), GETPOST('periodmonth'), GETPOST('periodday'), GETPOST('periodyear'));
+	$amount = price2num(GETPOST('amount'));
 
-	if (! $dateech)
+	if (!$dateech)
 	{
 		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Date")), null, 'errors');
 		$action = 'edit';
 	}
-	elseif (! $dateperiod)
+	elseif (!$dateperiod)
 	{
 		setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("Period")), null, 'errors');
 		$action = 'edit';
@@ -444,14 +444,14 @@ if ($id > 0)
 
 		if ($action == 'paid')
 		{
-			$text=$langs->trans('ConfirmPaySocialContribution');
+			$text = $langs->trans('ConfirmPaySocialContribution');
 			print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans('PaySocialContribution'), $text, "confirm_paid", '', '', 2);
 		}
 
 		// Confirmation of the removal of the Social Contribution
 		if ($action == 'delete')
 		{
-			$text=$langs->trans('ConfirmDeleteSocialContribution');
+			$text = $langs->trans('ConfirmDeleteSocialContribution');
 			print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans('DeleteSocialContribution'), $text, 'confirm_delete', '', '', 2);
 		}
 
@@ -463,48 +463,48 @@ if ($id > 0)
 
 		dol_fiche_head($head, 'card', $langs->trans("SocialContribution"), -1, 'bill');
 
-		$morehtmlref='<div class="refidno">';
+		$morehtmlref = '<div class="refidno">';
 		// Ref customer
-		$morehtmlref.=$form->editfieldkey("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', 0, 1);
-		$morehtmlref.=$form->editfieldval("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', null, null, '', 1);
+		$morehtmlref .= $form->editfieldkey("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', 0, 1);
+		$morehtmlref .= $form->editfieldval("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', null, null, '', 1);
 		// Project
-		if (! empty($conf->projet->enabled))
+		if (!empty($conf->projet->enabled))
 		{
 			$langs->load("projects");
-			$morehtmlref.='<br>'.$langs->trans('Project') . ' ';
+			$morehtmlref .= '<br>'.$langs->trans('Project').' ';
 			if ($user->rights->tax->charges->creer)
 			{
 				if ($action != 'classify') {
-					$morehtmlref.='<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&amp;id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> : ';
+					$morehtmlref .= '<a class="editfielda" href="'.$_SERVER['PHP_SELF'].'?action=classify&amp;id='.$object->id.'">'.img_edit($langs->transnoentitiesnoconv('SetProject')).'</a> : ';
 				}
 				if ($action == 'classify') {
 					//$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'projectid', 0, 0, 1, 1);
-					$morehtmlref.='<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
-					$morehtmlref.='<input type="hidden" name="action" value="classin">';
-					$morehtmlref.='<input type="hidden" name="token" value="'.newToken().'">';
-					$morehtmlref.=$formproject->select_projects(0, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
-					$morehtmlref.='<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
-					$morehtmlref.='</form>';
+					$morehtmlref .= '<form method="post" action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'">';
+					$morehtmlref .= '<input type="hidden" name="action" value="classin">';
+					$morehtmlref .= '<input type="hidden" name="token" value="'.newToken().'">';
+					$morehtmlref .= $formproject->select_projects(0, $object->fk_project, 'projectid', $maxlength, 0, 1, 0, 1, 0, 0, '', 1);
+					$morehtmlref .= '<input type="submit" class="button valignmiddle" value="'.$langs->trans("Modify").'">';
+					$morehtmlref .= '</form>';
 				} else {
-					$morehtmlref.=$form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
+					$morehtmlref .= $form->form_project($_SERVER['PHP_SELF'].'?id='.$object->id, $object->socid, $object->fk_project, 'none', 0, 0, 0, 1);
 				}
 			} else {
-				if (! empty($object->fk_project)) {
+				if (!empty($object->fk_project)) {
 					$proj = new Project($db);
 					$proj->fetch($object->fk_project);
-					$morehtmlref.='<a href="'.DOL_URL_ROOT.'/projet/card.php?id=' . $object->fk_project . '" title="' . $langs->trans('ShowProject') . '">';
-					$morehtmlref.=$proj->ref;
-					$morehtmlref.='</a>';
+					$morehtmlref .= '<a href="'.DOL_URL_ROOT.'/projet/card.php?id='.$object->fk_project.'" title="'.$langs->trans('ShowProject').'">';
+					$morehtmlref .= $proj->ref;
+					$morehtmlref .= '</a>';
 				} else {
-					$morehtmlref.='';
+					$morehtmlref .= '';
 				}
 			}
 		}
-		$morehtmlref.='</div>';
+		$morehtmlref .= '</div>';
 
-		$linkback = '<a href="' . DOL_URL_ROOT . '/compta/sociales/list.php?restore_lastsearch_values=1">' . $langs->trans("BackToList") . '</a>';
+		$linkback = '<a href="'.DOL_URL_ROOT.'/compta/sociales/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
 
-		$object->totalpaye = $totalpaye;   // To give a chance to dol_banner_tab to use already paid amount to show correct status
+		$object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status
 
 		dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright);
 

+ 44 - 44
htdocs/compta/sociales/class/chargesociales.class.php

@@ -132,41 +132,41 @@ class ChargeSociales extends CommonObject
     public function fetch($id, $ref = '')
     {
         $sql = "SELECT cs.rowid, cs.date_ech";
-        $sql.= ", cs.libelle as label, cs.fk_type, cs.amount, cs.fk_projet as fk_project, cs.paye, cs.periode, cs.import_key";
-        $sql.= ", cs.fk_account, cs.fk_mode_reglement";
-        $sql.= ", c.libelle";
-        $sql.= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
-        $sql.= " FROM ".MAIN_DB_PREFIX."chargesociales as cs";
-        $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_chargesociales as c ON cs.fk_type = c.id";
-        $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON cs.fk_mode_reglement = p.id';
-        $sql.= ' WHERE cs.entity IN ('.getEntity('tax').')';
-        if ($ref) $sql.= " AND cs.rowid = ".$ref;
-        else $sql.= " AND cs.rowid = ".$id;
+        $sql .= ", cs.libelle as label, cs.fk_type, cs.amount, cs.fk_projet as fk_project, cs.paye, cs.periode, cs.import_key";
+        $sql .= ", cs.fk_account, cs.fk_mode_reglement";
+        $sql .= ", c.libelle";
+        $sql .= ', p.code as mode_reglement_code, p.libelle as mode_reglement_libelle';
+        $sql .= " FROM ".MAIN_DB_PREFIX."chargesociales as cs";
+        $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_chargesociales as c ON cs.fk_type = c.id";
+        $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as p ON cs.fk_mode_reglement = p.id';
+        $sql .= ' WHERE cs.entity IN ('.getEntity('tax').')';
+        if ($ref) $sql .= " AND cs.rowid = ".$ref;
+        else $sql .= " AND cs.rowid = ".$id;
 
         dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
-        $resql=$this->db->query($sql);
+        $resql = $this->db->query($sql);
         if ($resql)
         {
             if ($this->db->num_rows($resql))
             {
                 $obj = $this->db->fetch_object($resql);
 
-                $this->id					= $obj->rowid;
+                $this->id = $obj->rowid;
                 $this->ref					= $obj->rowid;
-                $this->date_ech				= $this->db->jdate($obj->date_ech);
+                $this->date_ech = $this->db->jdate($obj->date_ech);
                 $this->lib					= $obj->label;
                 $this->label				= $obj->label;
                 $this->type					= $obj->fk_type;
                 $this->type_label			= $obj->libelle;
                 $this->fk_account			= $obj->fk_account;
-                $this->mode_reglement_id	= $obj->fk_mode_reglement;
-                $this->mode_reglement_code	= $obj->mode_reglement_code;
-                $this->mode_reglement		= $obj->mode_reglement_libelle;
-                $this->amount				= $obj->amount;
-				$this->fk_project			= $obj->fk_project;
-                $this->paye					= $obj->paye;
-                $this->periode				= $this->db->jdate($obj->periode);
-                $this->import_key			= $this->import_key;
+                $this->mode_reglement_id = $obj->fk_mode_reglement;
+                $this->mode_reglement_code = $obj->mode_reglement_code;
+                $this->mode_reglement = $obj->mode_reglement_libelle;
+                $this->amount = $obj->amount;
+				$this->fk_project = $obj->fk_project;
+                $this->paye = $obj->paye;
+                $this->periode = $this->db->jdate($obj->periode);
+                $this->import_key = $this->import_key;
 
                 $this->db->free($resql);
 
@@ -497,7 +497,7 @@ class ChargeSociales extends CommonObject
         global $langs;
 
         // Load translation files required by the page
-        $langs->loadLangs(array("customers","bills"));
+        $langs->loadLangs(array("customers", "bills"));
 
         // We reinit status array to force to redefine them because label may change according to properties values.
         $this->labelStatus = array();
@@ -548,41 +548,41 @@ class ChargeSociales extends CommonObject
         if ($option !== 'nolink')
         {
         	// Add param to save lastsearch_values or not
-        	$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
-        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
-        	if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
+        	$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
+        	if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1;
+        	if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1';
         }
 
 
-        if (empty($this->ref)) $this->ref=$this->label;
+        if (empty($this->ref)) $this->ref = $this->label;
 
         $label = '<u>'.$langs->trans("ShowSocialContribution").'</u>';
-        if (! empty($this->ref))
-        	$label .= '<br><b>'.$langs->trans('Ref') . ':</b> ' . $this->ref;
-        if (! empty($this->label))
-        	$label .= '<br><b>'.$langs->trans('Label') . ':</b> ' . $this->label;
-        if (! empty($this->type_label))
-        	$label .= '<br><b>'.$langs->trans('Type') . ':</b> ' . $this->type_label;
-
-        $linkclose='';
+        if (!empty($this->ref))
+        	$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
+        if (!empty($this->label))
+        	$label .= '<br><b>'.$langs->trans('Label').':</b> '.$this->label;
+        if (!empty($this->type_label))
+        	$label .= '<br><b>'.$langs->trans('Type').':</b> '.$this->type_label;
+
+        $linkclose = '';
         if (empty($notooltip) && $user->rights->facture->lire)
         {
-        	if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
+        	if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
         	{
-        		$label=$langs->trans("ShowSocialContribution");
-        		$linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
+        		$label = $langs->trans("ShowSocialContribution");
+        		$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
         	}
-        	$linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
-        	$linkclose.=' class="classfortooltip"';
+        	$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
+        	$linkclose .= ' class="classfortooltip"';
         }
 
-        $linkstart='<a href="'.$url.'"';
-        $linkstart.=$linkclose.'>';
-        $linkend='</a>';
+        $linkstart = '<a href="'.$url.'"';
+        $linkstart .= $linkclose.'>';
+        $linkend = '</a>';
 
         $result .= $linkstart;
-        if ($withpicto) $result.=img_object(($notooltip?'':$label), ($this->picto?$this->picto:'generic'), ($notooltip?(($withpicto != 2) ? 'class="paddingright"' : ''):'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip?0:1);
-        if ($withpicto != 2) $result.= ($maxlen?dol_trunc($this->ref, $maxlen):$this->ref);
+        if ($withpicto) $result .= img_object(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
+        if ($withpicto != 2) $result .= ($maxlen ?dol_trunc($this->ref, $maxlen) : $this->ref);
         $result .= $linkend;
 
         return $result;

+ 23 - 23
htdocs/compta/tva/document.php

@@ -34,7 +34,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/vat.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
-if (! empty($conf->projet->enabled))
+if (!empty($conf->projet->enabled))
 {
     require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
     require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
@@ -48,7 +48,7 @@ $action = GETPOST('action', 'aZ09');
 $confirm = GETPOST('confirm', 'alpha');
 
 // Security check
-if ($user->socid) $socid=$user->socid;
+if ($user->socid) $socid = $user->socid;
 $result = restrictedArea($user, 'tax', '', 'vat', 'charges');
 
 
@@ -63,22 +63,22 @@ if (empty($page) || $page == -1) {
 $offset = $conf->liste_limit * $page;
 $pageprev = $page - 1;
 $pagenext = $page + 1;
-if (! $sortorder) $sortorder="ASC";
-if (! $sortfield) $sortfield="name";
+if (!$sortorder) $sortorder = "ASC";
+if (!$sortfield) $sortfield = "name";
 
 
 $object = new Tva($db);
 if ($id > 0) $object->fetch($id);
 
 $upload_dir = $conf->tax->dir_output.'/'.dol_sanitizeFileName($object->ref);
-$modulepart='tax';
+$modulepart = 'tax';
 
 
 /*
  * Actions
  */
 
-include_once DOL_DOCUMENT_ROOT . '/core/actions_linkedfiles.inc.php';
+include_once DOL_DOCUMENT_ROOT.'/core/actions_linkedfiles.inc.php';
 
 if ($action == 'setlib' && $user->rights->tax->charges->creer)
 {
@@ -94,29 +94,29 @@ if ($action == 'setlib' && $user->rights->tax->charges->creer)
  */
 
 $form = new Form($db);
-if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); }
+if (!empty($conf->projet->enabled)) { $formproject = new FormProjets($db); }
 
-$title = $langs->trans("VATPayment") . ' - ' . $langs->trans("Documents");
-$help_url='EN:Module_Taxes_and_social_contributions|FR:Module Taxes et dividendes|ES:M&oacute;dulo Impuestos y cargas sociales (IVA, impuestos)';
+$title = $langs->trans("VATPayment").' - '.$langs->trans("Documents");
+$help_url = 'EN:Module_Taxes_and_social_contributions|FR:Module Taxes et dividendes|ES:M&oacute;dulo Impuestos y cargas sociales (IVA, impuestos)';
 llxHeader("", $title, $help_url);
 
 if ($object->id)
 {
-	$alreadypayed=$object->getSommePaiement();
+	$alreadypayed = $object->getSommePaiement();
 
-    $head=vat_prepare_head($object);
+    $head = vat_prepare_head($object);
 
     dol_fiche_head($head, 'documents', $langs->trans("VATPayment"), -1, 'bill');
 
-	$morehtmlref='<div class="refidno">';
+	$morehtmlref = '<div class="refidno">';
 	// Label of social contribution
-	$morehtmlref.=$form->editfieldkey("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', 0, 1);
-	$morehtmlref.=$form->editfieldval("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', null, null, '', 1);
-	$morehtmlref.='</div>';
+	$morehtmlref .= $form->editfieldkey("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', 0, 1);
+	$morehtmlref .= $form->editfieldval("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', null, null, '', 1);
+	$morehtmlref .= '</div>';
 
-	$linkback = '<a href="' . DOL_URL_ROOT . '/compta/tva/list.php?restore_lastsearch_values=1">' . $langs->trans("BackToList") . '</a>';
+	$linkback = '<a href="'.DOL_URL_ROOT.'/compta/tva/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
 
-	$object->totalpaye = $totalpaye;   // To give a chance to dol_banner_tab to use already paid amount to show correct status
+	$object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status
 
 	dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', $morehtmlref, '', 0, '', $morehtmlright);
 
@@ -124,11 +124,11 @@ if ($object->id)
 	print '<div class="underbanner clearboth"></div>';
 
     // Build file list
-    $filearray=dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder)=='desc'?SORT_DESC:SORT_ASC), 1);
-    $totalsize=0;
-    foreach($filearray as $key => $file)
+    $filearray = dol_dir_list($upload_dir, "files", 0, '', '(\.meta|_preview.*\.png)$', $sortfield, (strtolower($sortorder) == 'desc' ?SORT_DESC:SORT_ASC), 1);
+    $totalsize = 0;
+    foreach ($filearray as $key => $file)
     {
-        $totalsize+=$file['size'];
+        $totalsize += $file['size'];
     }
 
 
@@ -147,8 +147,8 @@ if ($object->id)
     $modulepart = 'tax';
     $permission = $user->rights->tax->charges->creer;
     $permtoedit = $user->rights->fournisseur->facture->creer;
-    $param = '&id=' . $object->id;
-    include_once DOL_DOCUMENT_ROOT . '/core/tpl/document_actions_post_headers.tpl.php';
+    $param = '&id='.$object->id;
+    include_once DOL_DOCUMENT_ROOT.'/core/tpl/document_actions_post_headers.tpl.php';
 }
 else
 {

+ 1 - 1
htdocs/contact/card.php

@@ -1364,7 +1364,7 @@ else
 		if (!empty($conf->categorie->enabled) && !empty($user->rights->categorie->lire)) {
 			print '<tr><td class="titlefield">'.$langs->trans("Categories").'</td>';
 			print '<td colspan="3">';
-			print $form->showCategories($object->id, 'contact', 1);
+			print $form->showCategories($object->id, Categorie::TYPE_CONTACT, 1);
 			print '</td></tr>';
 		}
 

+ 6 - 2
htdocs/contact/class/contact.class.php

@@ -86,9 +86,9 @@ class Contact extends CommonObject
 		'phone_mobile' =>array('type'=>'varchar(30)', 'label'=>'Phone mobile', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
 		'fax' =>array('type'=>'varchar(30)', 'label'=>'Fax', 'enabled'=>1, 'visible'=>-1, 'position'=>105),
 		'email' =>array('type'=>'varchar(255)', 'label'=>'Email', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
-		'socialnetworks' =>array('type'=>'text', 'label'=>'Socialnetworks', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
+		'socialnetworks' =>array('type'=>'text', 'label'=>'SocialNetworks', 'enabled'=>1, 'visible'=>-1, 'position'=>115),
 		'photo' =>array('type'=>'varchar(255)', 'label'=>'Photo', 'enabled'=>1, 'visible'=>-1, 'position'=>170),
-		'priv' =>array('type'=>'smallint(6)', 'label'=>'Priv', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>175),
+		'priv' =>array('type'=>'smallint(6)', 'label'=>'Private', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>175),
 		'no_email' =>array('type'=>'smallint(6)', 'label'=>'No email', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>180),
 		'fk_user_creat' =>array('type'=>'integer', 'label'=>'UserAuthor', 'enabled'=>1, 'visible'=>-1, 'position'=>185),
 		'fk_user_modif' =>array('type'=>'integer', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-1, 'position'=>190),
@@ -181,6 +181,10 @@ class Contact extends CommonObject
 	public $phone_mobile;
 	public $fax;
 
+	/**
+	 * Private or public
+	 * @var int
+	 */
 	public $priv;
 
 	public $birthday;

+ 1 - 1
htdocs/contrat/card.php

@@ -724,7 +724,7 @@ if (empty($reshook))
 
 			if (is_array($array_options) && count($array_options) > 0) {
 				// We replace values in this->line->array_options only for entries defined into $array_options
-				foreach($array_options as $key => $value) {
+				foreach ($array_options as $key => $value) {
 					$objectline->array_options[$key] = $array_options[$key];
 				}
 			}

+ 51 - 45
htdocs/contrat/class/contrat.class.php

@@ -9,7 +9,7 @@
  * Copyright (C) 2013		Florian Henry			<florian.henry@open-concept.pro>
  * Copyright (C) 2014-2015	Marcos García			<marcosgdf@gmail.com>
  * Copyright (C) 2018   	Nicolas ZABOURI			<info@inovea-conseil.com>
- * Copyright (C) 2018-2019  Frédéric France         <frederic.france@netlogic.fr>
+ * Copyright (C) 2018-2020  Frédéric France         <frederic.france@netlogic.fr>
  * Copyright (C) 2015-2018	Ferran Marcet			<fmarcet@2byte.es>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -73,6 +73,11 @@ class Contrat extends CommonObject
      */
     public $ismultientitymanaged = 1;
 
+    /**
+     * @var int  Does object support extrafields ? 0=No, 1=Yes
+     */
+    public $isextrafieldmanaged = 1;
+
     /**
      * 0=Default, 1=View may be restricted to sales representative only if no permission to see all or to company of external user if external user
      * @var integer
@@ -160,12 +165,6 @@ class Contrat extends CommonObject
 	 */
 	public $date_contrat;
 
-	/**
-	 * @var integer|string		Date of contract closure
-	 * @deprecated we close contract lines, not a contract
-	 */
-	public $date_cloture;
-
 	public $commercial_signature_id;
 	public $commercial_suivi_id;
 
@@ -189,6 +188,34 @@ class Contrat extends CommonObject
 	protected $lines_id_index_mapper = array();
 
 
+	/**
+	 *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
+	 *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
+	 *  'label' the translation key.
+	 *  'enabled' is a condition when the field must be managed.
+	 *  'position' is the sort order of field.
+	 *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
+	 *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
+	 *  'noteditable' says if field is not editable (1 or 0)
+	 *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
+	 *  'index' if we want an index in database.
+	 *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommanded to name the field fk_...).
+	 *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
+	 *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
+	 *  'css' is the CSS style to use on field. For example: 'maxwidth200'
+	 *  'help' is a string visible as a tooltip on field
+	 *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
+	 *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
+	 *  'arraykeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
+	 *  'comment' is not used. You can store here any text of your choice. It is not used by application.
+	 *
+	 *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
+	 */
+
+	// BEGIN MODULEBUILDER PROPERTIES
+	/**
+	 * @var array  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
+	 */
 	public $fields=array(
 		'rowid' =>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>10),
 		'ref' =>array('type'=>'varchar(50)', 'label'=>'Ref', 'enabled'=>1, 'visible'=>-1, 'showoncombobox'=>1, 'position'=>15),
@@ -198,17 +225,12 @@ class Contrat extends CommonObject
 		'tms' =>array('type'=>'timestamp', 'label'=>'DateModification', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>35),
 		'datec' =>array('type'=>'datetime', 'label'=>'DateCreation', 'enabled'=>1, 'visible'=>-1, 'position'=>40),
 		'date_contrat' =>array('type'=>'datetime', 'label'=>'Date contrat', 'enabled'=>1, 'visible'=>-1, 'position'=>45),
-		'statut' =>array('type'=>'smallint(6)', 'label'=>'Statut', 'enabled'=>1, 'visible'=>-1, 'position'=>500),
-		'mise_en_service' =>array('type'=>'datetime', 'label'=>'Mise en service', 'enabled'=>1, 'visible'=>-1, 'position'=>55),
-		'fin_validite' =>array('type'=>'datetime', 'label'=>'Fin validite', 'enabled'=>1, 'visible'=>-1, 'position'=>60),
-		'date_cloture' =>array('type'=>'datetime', 'label'=>'Date cloture', 'enabled'=>1, 'visible'=>-1, 'position'=>65),
+	    'statut' =>array('type'=>'smallint(6)', 'label'=>'Statut', 'enabled'=>1, 'visible'=>-1, 'position'=>500, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 2=>'Closed')),
 		'fk_soc' =>array('type'=>'integer:Societe:societe/class/societe.class.php', 'label'=>'ThirdParty', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>70),
 		'fk_projet' =>array('type'=>'integer:Project:projet/class/project.class.php:1:fk_statut=1', 'label'=>'Fk projet', 'enabled'=>1, 'visible'=>-1, 'position'=>75),
 		'fk_commercial_signature' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk commercial signature', 'enabled'=>1, 'visible'=>-1, 'position'=>80),
 		'fk_commercial_suivi' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk commercial suivi', 'enabled'=>1, 'visible'=>-1, 'position'=>85),
 		'fk_user_author' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user author', 'enabled'=>1, 'visible'=>-1, 'notnull'=>1, 'position'=>90),
-		'fk_user_mise_en_service' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user mise en service', 'enabled'=>1, 'visible'=>-1, 'position'=>95),
-		'fk_user_cloture' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'Fk user cloture', 'enabled'=>1, 'visible'=>-1, 'position'=>100),
 		'note_private' =>array('type'=>'text', 'label'=>'NotePublic', 'enabled'=>1, 'visible'=>0, 'position'=>105),
 		'note_public' =>array('type'=>'text', 'label'=>'NotePrivate', 'enabled'=>1, 'visible'=>0, 'position'=>110),
 		'model_pdf' =>array('type'=>'varchar(255)', 'label'=>'Model pdf', 'enabled'=>1, 'visible'=>0, 'position'=>115),
@@ -218,6 +240,7 @@ class Contrat extends CommonObject
 		'fk_user_modif' =>array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserModif', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'position'=>135),
 		'last_main_doc' =>array('type'=>'varchar(255)', 'label'=>'Last main doc', 'enabled'=>1, 'visible'=>-1, 'position'=>140),
 	);
+	// END MODULEBUILDER PROPERTIES
 
 	const STATUS_DRAFT = 0;
 	const STATUS_VALIDATED = 1;
@@ -662,12 +685,12 @@ class Contrat extends CommonObject
 	 */
 	public function fetch($id, $ref = '', $ref_customer = '', $ref_supplier = '')
 	{
-		$sql = "SELECT rowid, statut, ref, fk_soc, mise_en_service as datemise,";
+		$sql = "SELECT rowid, statut, ref, fk_soc,";
 		$sql .= " ref_supplier, ref_customer,";
 		$sql .= " ref_ext,";
         $sql .= " entity,";
-		$sql .= " fk_user_mise_en_service, date_contrat as datecontrat,";
-		$sql .= " fk_user_author, fin_validite, date_cloture,";
+		$sql .= " date_contrat as datecontrat,";
+		$sql .= " fk_user_author,";
 		$sql .= " fk_projet as fk_project,";
 		$sql .= " fk_commercial_signature, fk_commercial_suivi,";
 		$sql .= " note_private, note_public, model_pdf, extraparams";
@@ -705,19 +728,14 @@ class Contrat extends CommonObject
 				{
 					$this->id = $obj->rowid;
 					$this->ref = (!isset($obj->ref) || !$obj->ref) ? $obj->rowid : $obj->ref;
-					$this->ref_customer				= $obj->ref_customer;
-					$this->ref_supplier				= $obj->ref_supplier;
+					$this->ref_customer = $obj->ref_customer;
+					$this->ref_supplier = $obj->ref_supplier;
 					$this->ref_ext = $obj->ref_ext;
 	                $this->entity = $obj->entity;
 					$this->statut = $obj->statut;
-					$this->mise_en_service = $this->db->jdate($obj->datemise);
-
-					$this->date_contrat				= $this->db->jdate($obj->datecontrat);
-					$this->date_creation			= $this->db->jdate($obj->datecontrat);
-
-					$this->fin_validite				= $this->db->jdate($obj->fin_validite);
-					$this->date_cloture				= $this->db->jdate($obj->date_cloture);
 
+					$this->date_contrat = $this->db->jdate($obj->datecontrat);
+					$this->date_creation = $this->db->jdate($obj->datecontrat);
 
 					$this->user_author_id = $obj->fk_user_author;
 
@@ -726,9 +744,9 @@ class Contrat extends CommonObject
 
 					$this->note_private = $obj->note_private;
 					$this->note_public = $obj->note_public;
-					$this->modelpdf					= $obj->model_pdf;
+					$this->modelpdf = $obj->model_pdf;
 
-					$this->fk_projet				= $obj->fk_project; // deprecated
+					$this->fk_projet = $obj->fk_project; // deprecated
 					$this->fk_project = $obj->fk_project;
 
 					$this->socid = $obj->fk_soc;
@@ -738,7 +756,7 @@ class Contrat extends CommonObject
 
 					$this->db->free($resql);
 
-					// Retreive all extrafields
+					// Retrieve all extrafields
 					// fetch optionals attributes and labels
 					$this->fetch_optionals();
 
@@ -867,7 +885,7 @@ class Contrat extends CommonObject
 
 				$line->fk_user_author = $objp->fk_user_author;
 				$line->fk_user_ouverture = $objp->fk_user_ouverture;
-				$line->fk_user_cloture  = $objp->fk_user_cloture;
+				$line->fk_user_cloture = $objp->fk_user_cloture;
 				$line->fk_unit = $objp->fk_unit;
 
 				$line->ref = $objp->product_ref; // deprecated
@@ -1333,8 +1351,6 @@ class Contrat extends CommonObject
 		if (isset($this->fk_soc)) $this->fk_soc = (int) $this->fk_soc;
 		if (isset($this->fk_commercial_signature)) $this->fk_commercial_signature = trim($this->fk_commercial_signature);
 		if (isset($this->fk_commercial_suivi)) $this->fk_commercial_suivi = trim($this->fk_commercial_suivi);
-		if (isset($this->fk_user_mise_en_service)) $this->fk_user_mise_en_service = (int) $this->fk_user_mise_en_service;
-		if (isset($this->fk_user_cloture)) $this->fk_user_cloture = (int) $this->fk_user_cloture;
 		if (isset($this->note_private)) $this->note_private = trim($this->note_private);
 		if (isset($this->note_public)) $this->note_public = trim($this->note_public);
 		if (isset($this->import_key)) $this->import_key = trim($this->import_key);
@@ -1352,15 +1368,10 @@ class Contrat extends CommonObject
 		$sql .= " entity=".$conf->entity.",";
 		$sql .= " date_contrat=".(dol_strlen($this->date_contrat) != 0 ? "'".$this->db->idate($this->date_contrat)."'" : 'null').",";
 		$sql .= " statut=".(isset($this->statut) ? $this->statut : "null").",";
-		$sql .= " mise_en_service=".(dol_strlen($this->mise_en_service) != 0 ? "'".$this->db->idate($this->mise_en_service)."'" : 'null').",";
-		$sql .= " fin_validite=".(dol_strlen($this->fin_validite) != 0 ? "'".$this->db->idate($this->fin_validite)."'" : 'null').",";
-		$sql .= " date_cloture=".(dol_strlen($this->date_cloture) != 0 ? "'".$this->db->idate($this->date_cloture)."'" : 'null').",";
 		$sql .= " fk_soc=".($this->fk_soc > 0 ? $this->fk_soc : "null").",";
 		$sql .= " fk_projet=".($this->fk_project > 0 ? $this->fk_project : "null").",";
 		$sql .= " fk_commercial_signature=".(isset($this->fk_commercial_signature) ? $this->fk_commercial_signature : "null").",";
 		$sql .= " fk_commercial_suivi=".(isset($this->fk_commercial_suivi) ? $this->fk_commercial_suivi : "null").",";
-		$sql .= " fk_user_mise_en_service=".(isset($this->fk_user_mise_en_service) ? $this->fk_user_mise_en_service : "null").",";
-		$sql .= " fk_user_cloture=".(isset($this->fk_user_cloture) ? $this->fk_user_cloture : "null").",";
 		$sql .= " note_private=".(isset($this->note_private) ? "'".$this->db->escape($this->note_private)."'" : "null").",";
 		$sql .= " note_public=".(isset($this->note_public) ? "'".$this->db->escape($this->note_public)."'" : "null").",";
 		$sql .= " import_key=".(isset($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null")."";
@@ -1773,7 +1784,7 @@ class Contrat extends CommonObject
 					$contractline->fetch_optionals();
 
 					// We replace values in $contractline->array_options only for entries defined into $array_options
-					foreach($array_options as $key => $value) {
+					foreach ($array_options as $key => $value) {
 						$contractline->array_options[$key] = $array_options[$key];
 					}
 
@@ -2062,9 +2073,9 @@ class Contrat extends CommonObject
 	 */
 	public function info($id)
 	{
-		$sql = "SELECT c.rowid, c.ref, c.datec, c.date_cloture,";
+		$sql = "SELECT c.rowid, c.ref, c.datec,";
 		$sql .= " c.tms as date_modification,";
-		$sql .= " fk_user_author, fk_user_cloture";
+		$sql .= " fk_user_author";
 		$sql .= " FROM ".MAIN_DB_PREFIX."contrat as c";
 		$sql .= " WHERE c.rowid = ".$id;
 
@@ -2083,15 +2094,9 @@ class Contrat extends CommonObject
 					$this->user_creation = $cuser;
 				}
 
-				if ($obj->fk_user_cloture) {
-					$cuser = new User($this->db);
-					$cuser->fetch($obj->fk_user_cloture);
-					$this->user_cloture = $cuser;
-				}
 				$this->ref = (!$obj->ref) ? $obj->rowid : $obj->ref;
 				$this->date_creation     = $this->db->jdate($obj->datec);
 				$this->date_modification = $this->db->jdate($obj->date_modification);
-				$this->date_cloture      = $this->db->jdate($obj->date_cloture);
 			}
 
 			$this->db->free($result);
@@ -3040,6 +3045,7 @@ class ContratLigne extends CommonObjectLine
 
 		$this->oldcopy = new ContratLigne($this->db);
 		$this->oldcopy->fetch($this->id);
+        $this->oldcopy->fetch_optionals();
 
 		// Update request
 		$sql = "UPDATE ".MAIN_DB_PREFIX."contratdet SET";

+ 101 - 101
htdocs/contrat/services_list.php

@@ -86,36 +86,36 @@ $extrafields = new ExtraFields($db);
 // fetch optionals attributes and labels
 $extrafields->fetch_name_optionals_label('contratdet');
 
-$search_array_options=$extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
+$search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_');
 
 // Security check
 $contratid = GETPOST('id', 'int');
-if (! empty($user->socid)) $socid=$user->socid;
+if (!empty($user->socid)) $socid = $user->socid;
 $result = restrictedArea($user, 'contrat', $contratid);
 
 if ($search_status != '')
 {
-	$tmp=explode('&', $search_status);
-	$mode=$tmp[0];
-	if (empty($tmp[1])) $filter='';
+	$tmp = explode('&', $search_status);
+	$mode = $tmp[0];
+	if (empty($tmp[1])) $filter = '';
 	else
 	{
-		if ($tmp[1] == 'filter=notexpired') $filter='notexpired';
-		if ($tmp[1] == 'filter=expired') $filter='expired';
+		if ($tmp[1] == 'filter=notexpired') $filter = 'notexpired';
+		if ($tmp[1] == 'filter=expired') $filter = 'expired';
 	}
 }
 else
 {
 	$search_status = $mode;
-	if ($filter == 'expired') $search_status.='&filter=expired';
-	if ($filter == 'notexpired') $search_status.='&filter=notexpired';
+	if ($filter == 'expired') $search_status .= '&filter=expired';
+	if ($filter == 'notexpired') $search_status .= '&filter=notexpired';
 }
 
-$staticcontrat=new Contrat($db);
-$staticcontratligne=new ContratLigne($db);
-$companystatic=new Societe($db);
+$staticcontrat = new Contrat($db);
+$staticcontratligne = new ContratLigne($db);
+$companystatic = new Societe($db);
 
-$arrayfields=array(
+$arrayfields = array(
 	'c.ref'=>array('label'=>$langs->trans("Contract"), 'checked'=>1, 'position'=>80),
 	'p.description'=>array('label'=>$langs->trans("Service"), 'checked'=>1, 'position'=>80),
 	'cd.qty'=>array('label'=>$langs->trans("Qty"), 'checked'=>0, 'position'=>100),
@@ -198,71 +198,71 @@ if (empty($reshook))
  * View
  */
 
-$now=dol_now();
+$now = dol_now();
 
-$form=new Form($db);
+$form = new Form($db);
 
 $sql = "SELECT c.rowid as cid, c.ref, c.statut as cstatut,";
-$sql.= " s.rowid as socid, s.nom as name, s.email, s.client, s.fournisseur,";
-$sql.= " cd.rowid, cd.description, cd.statut,";
-$sql.= " p.rowid as pid, p.ref as pref, p.label as label, p.fk_product_type as ptype, p.entity as pentity,";
+$sql .= " s.rowid as socid, s.nom as name, s.email, s.client, s.fournisseur,";
+$sql .= " cd.rowid, cd.description, cd.statut,";
+$sql .= " p.rowid as pid, p.ref as pref, p.label as label, p.fk_product_type as ptype, p.entity as pentity,";
 if (!$user->rights->societe->client->voir && !$socid) $sql .= " sc.fk_soc, sc.fk_user,";
-$sql.= " cd.date_ouverture_prevue,";
-$sql.= " cd.date_ouverture,";
-$sql.= " cd.date_fin_validite,";
-$sql.= " cd.date_cloture,";
-$sql.= " cd.qty,";
-$sql.= " cd.total_ht,";
-$sql.= " cd.total_tva,";
-$sql.= " cd.tva_tx,";
-$sql.= " cd.subprice,";
+$sql .= " cd.date_ouverture_prevue,";
+$sql .= " cd.date_ouverture,";
+$sql .= " cd.date_fin_validite,";
+$sql .= " cd.date_cloture,";
+$sql .= " cd.qty,";
+$sql .= " cd.total_ht,";
+$sql .= " cd.total_tva,";
+$sql .= " cd.tva_tx,";
+$sql .= " cd.subprice,";
 //$sql.= " cd.date_c as date_creation,";
-$sql.= " cd.tms as date_update";
+$sql .= " cd.tms as date_update";
 // Add fields from extrafields
-if (! empty($extrafields->attributes[$object->table_element]['label'])) {
-	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql.=($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key : '');
+if (!empty($extrafields->attributes[$object->table_element]['label'])) {
+	foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) $sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key.' as options_'.$key : '');
 }
 // Add fields from hooks
-$parameters=array();
-$reshook=$hookmanager->executeHooks('printFieldListSelect', $parameters);    // Note that $action and $object may have been modified by hook
-$sql.=$hookmanager->resPrint;
-$sql.= " FROM ".MAIN_DB_PREFIX."contrat as c,";
-$sql.= " ".MAIN_DB_PREFIX."societe as s,";
+$parameters = array();
+$reshook = $hookmanager->executeHooks('printFieldListSelect', $parameters); // Note that $action and $object may have been modified by hook
+$sql .= $hookmanager->resPrint;
+$sql .= " FROM ".MAIN_DB_PREFIX."contrat as c,";
+$sql .= " ".MAIN_DB_PREFIX."societe as s,";
 if (!$user->rights->societe->client->voir && !$socid) $sql .= " ".MAIN_DB_PREFIX."societe_commerciaux as sc,";
-$sql.= " ".MAIN_DB_PREFIX."contratdet as cd";
-if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql.= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (cd.rowid = ef.fk_object)";
-$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON cd.fk_product = p.rowid";
-if ($search_product_category > 0) $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product as cp ON cp.fk_product=cd.fk_product';
-$sql.= " WHERE c.entity = ".$conf->entity;
-$sql.= " AND c.rowid = cd.fk_contrat";
-if ($search_product_category > 0) $sql.=" AND cp.fk_categorie = ".$search_product_category;
-$sql.= " AND c.fk_soc = s.rowid";
-if (!$user->rights->societe->client->voir && !$socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
-if ($mode == "0") $sql.= " AND cd.statut = 0";
-if ($mode == "4") $sql.= " AND cd.statut = 4";
-if ($mode == "5") $sql.= " AND cd.statut = 5";
-if ($filter == "expired") $sql.= " AND cd.date_fin_validite < '".$db->idate($now)."'";
-if ($filter == "notexpired") $sql.= " AND cd.date_fin_validite >= '".$db->idate($now)."'";
-if ($search_name)     $sql.= " AND s.nom LIKE '%".$db->escape($search_name)."%'";
-if ($search_contract) $sql.= " AND c.ref LIKE '%".$db->escape($search_contract)."%' ";
-if ($search_service)  $sql.= " AND (p.ref LIKE '%".$db->escape($search_service)."%' OR p.description LIKE '%".$db->escape($search_service)."%' OR cd.description LIKE '%".$db->escape($search_service)."%')";
-if ($socid > 0)       $sql.= " AND s.rowid = ".$socid;
-$filter_dateouvertureprevue=dol_mktime(0, 0, 0, $opouvertureprevuemonth, $opouvertureprevueday, $opouvertureprevueyear);
+$sql .= " ".MAIN_DB_PREFIX."contratdet as cd";
+if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (cd.rowid = ef.fk_object)";
+$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON cd.fk_product = p.rowid";
+if ($search_product_category > 0) $sql .= ' LEFT JOIN '.MAIN_DB_PREFIX.'categorie_product as cp ON cp.fk_product=cd.fk_product';
+$sql .= " WHERE c.entity = ".$conf->entity;
+$sql .= " AND c.rowid = cd.fk_contrat";
+if ($search_product_category > 0) $sql .= " AND cp.fk_categorie = ".$search_product_category;
+$sql .= " AND c.fk_soc = s.rowid";
+if (!$user->rights->societe->client->voir && !$socid) $sql .= " AND s.rowid = sc.fk_soc AND sc.fk_user = ".$user->id;
+if ($mode == "0") $sql .= " AND cd.statut = 0";
+if ($mode == "4") $sql .= " AND cd.statut = 4";
+if ($mode == "5") $sql .= " AND cd.statut = 5";
+if ($filter == "expired") $sql .= " AND cd.date_fin_validite < '".$db->idate($now)."'";
+if ($filter == "notexpired") $sql .= " AND cd.date_fin_validite >= '".$db->idate($now)."'";
+if ($search_name)     $sql .= " AND s.nom LIKE '%".$db->escape($search_name)."%'";
+if ($search_contract) $sql .= " AND c.ref LIKE '%".$db->escape($search_contract)."%' ";
+if ($search_service)  $sql .= " AND (p.ref LIKE '%".$db->escape($search_service)."%' OR p.description LIKE '%".$db->escape($search_service)."%' OR cd.description LIKE '%".$db->escape($search_service)."%')";
+if ($socid > 0)       $sql .= " AND s.rowid = ".$socid;
+$filter_dateouvertureprevue = dol_mktime(0, 0, 0, $opouvertureprevuemonth, $opouvertureprevueday, $opouvertureprevueyear);
 if ($filter_dateouvertureprevue != '' && $filter_opouvertureprevue == -1) $filter_opouvertureprevue = '=';
 
-$filter_date1=dol_mktime(0, 0, 0, $op1month, $op1day, $op1year);
+$filter_date1 = dol_mktime(0, 0, 0, $op1month, $op1day, $op1year);
 if ($filter_date1 != '' && $filter_op1 == -1) $filter_op1 = '=';
 
-$filter_date2=dol_mktime(0, 0, 0, $op2month, $op2day, $op2year);
+$filter_date2 = dol_mktime(0, 0, 0, $op2month, $op2day, $op2year);
 if ($filter_date2 != '' && $filter_op2 == -1) $filter_op2 = '=';
 
-$filter_datecloture=dol_mktime(0, 0, 0, $opcloturemonth, $opclotureday, $opclotureyear);
+$filter_datecloture = dol_mktime(0, 0, 0, $opcloturemonth, $opclotureday, $opclotureyear);
 if ($filter_datecloture != '' && $filter_opcloture == -1) $filter_opcloture = '=';
 
-if (! empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_dateouvertureprevue != '') $sql.= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue)."'";
-if (! empty($filter_op1) && $filter_op1 != -1 && $filter_date1 != '') $sql.= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1)."'";
-if (! empty($filter_op2) && $filter_op2 != -1 && $filter_date2 != '') $sql.= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2)."'";
-if (! empty($filter_opcloture) && $filter_opcloture != -1 && $filter_datecloture != '') $sql.= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture)."'";
+if (!empty($filter_opouvertureprevue) && $filter_opouvertureprevue != -1 && $filter_dateouvertureprevue != '') $sql .= " AND cd.date_ouverture_prevue ".$filter_opouvertureprevue." '".$db->idate($filter_dateouvertureprevue)."'";
+if (!empty($filter_op1) && $filter_op1 != -1 && $filter_date1 != '') $sql .= " AND cd.date_ouverture ".$filter_op1." '".$db->idate($filter_date1)."'";
+if (!empty($filter_op2) && $filter_op2 != -1 && $filter_date2 != '') $sql .= " AND cd.date_fin_validite ".$filter_op2." '".$db->idate($filter_date2)."'";
+if (!empty($filter_opcloture) && $filter_opcloture != -1 && $filter_datecloture != '') $sql .= " AND cd.date_cloture ".$filter_opcloture." '".$db->idate($filter_datecloture)."'";
 // Add where from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
 $sql .= $db->order($sortfield, $sortorder);
@@ -594,120 +594,120 @@ while ($i < min($num, $limit))
 			if ($obj->type == 1) print img_object($obj->description, 'service').' '.dol_trunc($obj->description, 24);
 		}
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 
-	if (! empty($arrayfields['cd.qty']['checked']))
+	if (!empty($arrayfields['cd.qty']['checked']))
 	{
 		print '<td>';
 		print $obj->qty;
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
-	if (! empty($arrayfields['cd.total_ht']['checked']))
+	if (!empty($arrayfields['cd.total_ht']['checked']))
 	{
 		print '<td class="right">';
 		print price($obj->total_ht);
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
-        if (! $i) $totalarray['pos'][$totalarray['nbfield']]='cd.total_ht';
+        if (!$i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'cd.total_ht';
         $totalarray['val']['cd.total_ht'] += $obj->total_ht;
     }
-	if (! empty($arrayfields['cd.total_tva']['checked']))
+	if (!empty($arrayfields['cd.total_tva']['checked']))
 	{
 		print '<td class="right">';
 		print price($obj->total_tva);
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
-        if (! $i) $totalarray['pos'][$totalarray['nbfield']]='cd.total_tva';
+        if (!$i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['pos'][$totalarray['nbfield']] = 'cd.total_tva';
         $totalarray['val']['cd.total_tva'] += $obj->total_tva;
     }
-	if (! empty($arrayfields['cd.tva_tx']['checked']))
+	if (!empty($arrayfields['cd.tva_tx']['checked']))
 	{
 		print '<td class="right">';
 		print price2num($obj->tva_tx).'%';
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
-	if (! empty($arrayfields['cd.subprice']['checked']))
+	if (!empty($arrayfields['cd.subprice']['checked']))
 	{
 		print '<td class="right">';
 		print price($obj->subprice);
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 
 
 	// Third party
-	if (! empty($arrayfields['s.nom']['checked']))
+	if (!empty($arrayfields['s.nom']['checked']))
 	{
 		print '<td>';
 		print $companystatic->getNomUrl(1, 'customer', 28);
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 
 	// Start date
-	if (! empty($arrayfields['cd.date_ouverture_prevue']['checked']))
+	if (!empty($arrayfields['cd.date_ouverture_prevue']['checked']))
 	{
 		print '<td class="center">';
-		print ($obj->date_ouverture_prevue?dol_print_date($db->jdate($obj->date_ouverture_prevue), 'dayhour'):'&nbsp;');
+		print ($obj->date_ouverture_prevue ?dol_print_date($db->jdate($obj->date_ouverture_prevue), 'dayhour') : '&nbsp;');
 		if ($db->jdate($obj->date_ouverture_prevue) && ($db->jdate($obj->date_ouverture_prevue) < ($now - $conf->contrat->services->inactifs->warning_delay)) && $obj->statut == 0)
 		print ' '.img_picto($langs->trans("Late"), "warning");
 		else print '&nbsp;&nbsp;&nbsp;&nbsp;';
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
-	if (! empty($arrayfields['cd.date_ouverture']['checked']))
+	if (!empty($arrayfields['cd.date_ouverture']['checked']))
 	{
-		print '<td class="center">'.($obj->date_ouverture?dol_print_date($db->jdate($obj->date_ouverture), 'dayhour'):'&nbsp;').'</td>';
-        if (! $i) $totalarray['nbfield']++;
+		print '<td class="center">'.($obj->date_ouverture ?dol_print_date($db->jdate($obj->date_ouverture), 'dayhour') : '&nbsp;').'</td>';
+        if (!$i) $totalarray['nbfield']++;
 	}
 	// End date
-	if (! empty($arrayfields['cd.date_fin_validite']['checked']))
+	if (!empty($arrayfields['cd.date_fin_validite']['checked']))
 	{
-		print '<td class="center">'.($obj->date_fin_validite?dol_print_date($db->jdate($obj->date_fin_validite), 'dayhour'):'&nbsp;');
+		print '<td class="center">'.($obj->date_fin_validite ?dol_print_date($db->jdate($obj->date_fin_validite), 'dayhour') : '&nbsp;');
 		if ($obj->date_fin_validite && $db->jdate($obj->date_fin_validite) < ($now - $conf->contrat->services->expires->warning_delay) && $obj->statut < 5)
 		{
-			$warning_delay=$conf->contrat->services->expires->warning_delay / 3600 / 24;
+			$warning_delay = $conf->contrat->services->expires->warning_delay / 3600 / 24;
 			$textlate = $langs->trans("Late").' = '.$langs->trans("DateReference").' > '.$langs->trans("DateToday").' '.(ceil($warning_delay) >= 0 ? '+' : '').ceil($warning_delay).' '.$langs->trans("days");
 			print img_warning($textlate);
 		}
 		else print '&nbsp;&nbsp;&nbsp;&nbsp;';
 		print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 	// Close date (real end date)
-	if (! empty($arrayfields['cd.date_cloture']['checked']))
+	if (!empty($arrayfields['cd.date_cloture']['checked']))
 	{
 		print '<td class="center">'.dol_print_date($db->jdate($obj->date_cloture), 'dayhour').'</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 
 	// Extra fields
 	include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
 	// Fields from hook
-	$parameters=array('arrayfields'=>$arrayfields, 'obj'=>$obj);
-	$reshook=$hookmanager->executeHooks('printFieldListValue', $parameters);    // Note that $action and $object may have been modified by hook
+	$parameters = array('arrayfields'=>$arrayfields, 'obj'=>$obj);
+	$reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook
 	print $hookmanager->resPrint;
 	// Date creation
-	if (! empty($arrayfields['cd.datec']['checked']))
+	if (!empty($arrayfields['cd.datec']['checked']))
 	{
 		print '<td class="center">';
 		print dol_print_date($db->jdate($obj->date_creation), 'dayhour', 'tzuser');
 		print '</td>';
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 	}
 	// Date modification
-	if (! empty($arrayfields['cd.tms']['checked']))
+	if (!empty($arrayfields['cd.tms']['checked']))
 	{
 		print '<td class="center">';
 		print dol_print_date($db->jdate($obj->date_update), 'dayhour', 'tzuser');
 		print '</td>';
-		if (! $i) $totalarray['nbfield']++;
+		if (!$i) $totalarray['nbfield']++;
 	}
 	// Status
-	if (! empty($arrayfields['status']['checked']))
+	if (!empty($arrayfields['status']['checked']))
 	{
 	    print '<td class="right">';
 	    if ($obj->cstatut == 0)
@@ -717,21 +717,21 @@ while ($i < min($num, $limit))
 	    }
 	    else
 	    {
-		    print $staticcontratligne->LibStatut($obj->statut, 5, ($obj->date_fin_validite && $db->jdate($obj->date_fin_validite) < $now)?1:0);
+		    print $staticcontratligne->LibStatut($obj->statut, 5, ($obj->date_fin_validite && $db->jdate($obj->date_fin_validite) < $now) ? 1 : 0);
 	    }
 	    print '</td>';
-        if (! $i) $totalarray['nbfield']++;
+        if (!$i) $totalarray['nbfield']++;
 	}
 	// Action column
 	print '<td class="nowrap 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"':'').'>';
+		$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']++;
+	if (!$i) $totalarray['nbfield']++;
 
 	print "</tr>\n";
 	$i++;

+ 24 - 20
htdocs/core/actions_setmoduleoptions.inc.php

@@ -31,18 +31,22 @@ if ($action == 'update' && is_array($arrayofparameters))
 {
 	$db->begin();
 
-	$ok=true;
-	foreach($arrayofparameters as $key => $val)
+	$ok = true;
+	foreach ($arrayofparameters as $key => $val)
 	{
-		$result=dolibarr_set_const($db, $key, GETPOST($key, 'alpha'), 'chaine', 0, '', $conf->entity);
-		if ($result < 0)
+		// Modify constant only if key was posted (avoid resetting key to the null value)
+		if (GETPOSTISSET($key))
 		{
-			$ok=false;
-			break;
+			$result = dolibarr_set_const($db, $key, GETPOST($key, 'alpha'), 'chaine', 0, '', $conf->entity);
+		    if ($result < 0)
+		    {
+			    $ok = false;
+			    break;
+		    }
 		}
 	}
 
-	if (! $error)
+	if (!$error)
 	{
 		$db->commit();
 		if (empty($nomessageinupdate)) setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');
@@ -62,16 +66,16 @@ if ($action == 'setModuleOptions')
     // Process common param fields
     if (is_array($_POST))
     {
-        foreach($_POST as $key => $val)
+        foreach ($_POST as $key => $val)
         {
             if (preg_match('/^param(\d*)$/', $key, $reg))    // Works for POST['param'], POST['param1'], POST['param2'], ...
             {
-                $param=GETPOST("param".$reg[1], 'alpha');
-                $value=GETPOST("value".$reg[1], 'alpha');
+                $param = GETPOST("param".$reg[1], 'alpha');
+                $value = GETPOST("value".$reg[1], 'alpha');
                 if ($param)
                 {
                     $res = dolibarr_set_const($db, $param, $value, 'chaine', 0, '', $conf->entity);
-                    if (! $res > 0) $error++;
+                    if (!$res > 0) $error++;
                 }
             }
         }
@@ -81,19 +85,19 @@ if ($action == 'setModuleOptions')
     if (GETPOST('upload', 'alpha') && GETPOST('keyforuploaddir', 'aZ09'))
     {
         include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
-        $keyforuploaddir=GETPOST('keyforuploaddir', 'aZ09');
-        $listofdir=explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->$keyforuploaddir)));
-        foreach($listofdir as $key=>$tmpdir)
+        $keyforuploaddir = GETPOST('keyforuploaddir', 'aZ09');
+        $listofdir = explode(',', preg_replace('/[\r\n]+/', ',', trim($conf->global->$keyforuploaddir)));
+        foreach ($listofdir as $key=>$tmpdir)
         {
-            $tmpdir=trim($tmpdir);
-            $tmpdir=preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
-            if (! $tmpdir) {
+            $tmpdir = trim($tmpdir);
+            $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
+            if (!$tmpdir) {
                 unset($listofdir[$key]); continue;
             }
-            if (! is_dir($tmpdir)) $texttitle.=img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
+            if (!is_dir($tmpdir)) $texttitle .= img_warning($langs->trans("ErrorDirNotFound", $tmpdir), 0);
             else
             {
-                $upload_dir=$tmpdir;
+                $upload_dir = $tmpdir;
             }
         }
         if ($upload_dir)
@@ -103,7 +107,7 @@ if ($action == 'setModuleOptions')
         }
     }
 
-    if (! $error)
+    if (!$error)
     {
         $db->commit();
         if (empty($nomessageinsetmoduleoptions)) setEventMessages($langs->trans("SetupSaved"), null, 'mesgs');

Some files were not shown because too many files changed in this diff