Browse Source

Merge branch 'develop' of https://github.com/Dolibarr/dolibarr.git into
develop_mc

Conflicts:
ChangeLog

Regis Houssin 6 years ago
parent
commit
8953a3ed73
100 changed files with 1636 additions and 922 deletions
  1. 2 1
      .travis.yml
  2. 99 7
      ChangeLog
  3. 14 2
      build/docker/Dockerfile
  4. 5 1
      build/makepack-dolibarr.pl
  5. 55 0
      dev/initdemo/mysqldump_dolibarr_8.0.0.sql
  6. 55 0
      dev/initdemo/mysqldump_dolibarr_9.0.0.sql
  7. 2 0
      dev/initdemo/savedemo.sh
  8. 5 4
      htdocs/accountancy/admin/card.php
  9. 3 4
      htdocs/accountancy/bookkeeping/balance.php
  10. 71 38
      htdocs/accountancy/class/accountancycategory.class.php
  11. 15 15
      htdocs/accountancy/class/bookkeeping.class.php
  12. 1 1
      htdocs/accountancy/class/lettering.class.php
  13. 4 3
      htdocs/accountancy/journal/bankjournal.php
  14. 5 2
      htdocs/adherents/card.php
  15. 79 29
      htdocs/adherents/class/adherent.class.php
  16. 3 2
      htdocs/admin/defaultvalues.php
  17. 2 0
      htdocs/admin/emailcollector_card.php
  18. 20 0
      htdocs/admin/geoipmaxmind.php
  19. 9 4
      htdocs/admin/mails_templates.php
  20. 4 1
      htdocs/admin/modules.php
  21. 1 1
      htdocs/admin/salaries.php
  22. 2 2
      htdocs/blockedlog/admin/blockedlog_list.php
  23. 17 1
      htdocs/categories/photos.php
  24. 3 3
      htdocs/comm/action/card.php
  25. 25 7
      htdocs/comm/action/class/actioncomm.class.php
  26. 30 27
      htdocs/comm/action/index.php
  27. 51 34
      htdocs/comm/action/list.php
  28. 40 26
      htdocs/comm/action/peruser.php
  29. 1 1
      htdocs/comm/card.php
  30. 1 1
      htdocs/comm/propal/card.php
  31. 1 1
      htdocs/comm/propal/class/propal.class.php
  32. 16 6
      htdocs/comm/propal/list.php
  33. 1 1
      htdocs/commande/card.php
  34. 15 3
      htdocs/commande/list.php
  35. 1 1
      htdocs/compta/bank/list.php
  36. 13 2
      htdocs/compta/facture/list.php
  37. 1 1
      htdocs/compta/localtax/quadri_detail.php
  38. 15 12
      htdocs/compta/paiement.php
  39. 5 9
      htdocs/compta/paiement/card.php
  40. 6 4
      htdocs/compta/paiement/class/paiement.class.php
  41. 15 8
      htdocs/compta/paiement/list.php
  42. 1 1
      htdocs/compta/resultat/clientfourn.php
  43. 73 56
      htdocs/compta/resultat/result.php
  44. 2 2
      htdocs/compta/salaries/card.php
  45. 8 6
      htdocs/compta/salaries/stats/index.php
  46. 14 20
      htdocs/contact/agenda.php
  47. 2 2
      htdocs/contact/class/contact.class.php
  48. 1 0
      htdocs/contact/list.php
  49. 1 1
      htdocs/core/actions_extrafields.inc.php
  50. 1 1
      htdocs/core/actions_massactions.inc.php
  51. 5 2
      htdocs/core/boxes/box_task.php
  52. 7 5
      htdocs/core/class/CMailFile.class.php
  53. 0 1
      htdocs/core/class/commondocgenerator.class.php
  54. 35 7
      htdocs/core/class/commonobject.class.php
  55. 5 1
      htdocs/core/class/conf.class.php
  56. 1 1
      htdocs/core/class/dolgraph.class.php
  57. 3 2
      htdocs/core/class/events.class.php
  58. 6 4
      htdocs/core/class/html.form.class.php
  59. 2 2
      htdocs/core/class/html.formactions.class.php
  60. 1 1
      htdocs/core/class/html.formfile.class.php
  61. 1 2
      htdocs/core/class/html.formmail.class.php
  62. 12 15
      htdocs/core/class/translate.class.php
  63. 1 1
      htdocs/core/class/utils.class.php
  64. 25 25
      htdocs/core/js/lib_head.js.php
  65. 12 9
      htdocs/core/lib/admin.lib.php
  66. 7 7
      htdocs/core/lib/agenda.lib.php
  67. 1 1
      htdocs/core/lib/ajax.lib.php
  68. 27 7
      htdocs/core/lib/company.lib.php
  69. 230 189
      htdocs/core/lib/functions.lib.php
  70. 3 2
      htdocs/core/lib/pdf.lib.php
  71. 1 1
      htdocs/core/lib/report.lib.php
  72. 8 8
      htdocs/core/lib/usergroups.lib.php
  73. 47 1
      htdocs/core/lib/website.lib.php
  74. 5 9
      htdocs/core/modules/DolibarrModules.class.php
  75. 66 20
      htdocs/core/modules/contract/doc/pdf_strato.modules.php
  76. 41 15
      htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php
  77. 206 182
      htdocs/core/modules/expensereport/doc/pdf_standard.modules.php
  78. 10 12
      htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php
  79. 1 1
      htdocs/core/modules/modAccounting.class.php
  80. 2 2
      htdocs/core/modules/modAdherent.class.php
  81. 1 1
      htdocs/core/modules/modCashDesk.class.php
  82. 1 1
      htdocs/core/modules/modDav.class.php
  83. 2 2
      htdocs/core/modules/modEmailCollector.class.php
  84. 1 1
      htdocs/core/modules/modProduct.class.php
  85. 1 1
      htdocs/core/modules/modProjet.class.php
  86. 5 0
      htdocs/core/modules/modPropale.class.php
  87. 1 1
      htdocs/core/modules/modResource.class.php
  88. 1 1
      htdocs/core/modules/modService.class.php
  89. 9 6
      htdocs/core/modules/modSociete.class.php
  90. 2 2
      htdocs/core/modules/modTakePos.class.php
  91. 1 1
      htdocs/core/modules/modUser.class.php
  92. 1 1
      htdocs/core/modules/modWebsite.class.php
  93. 1 1
      htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php
  94. 7 6
      htdocs/core/modules/project/doc/pdf_beluga.modules.php
  95. 2 2
      htdocs/core/modules/rapport/pdf_paiement.class.php
  96. 1 1
      htdocs/core/modules/societe/mod_codecompta_aquarium.php
  97. 1 1
      htdocs/core/modules/stock/doc/pdf_stdmovement.modules.php
  98. 1 1
      htdocs/core/tpl/extrafields_view.tpl.php
  99. 2 0
      htdocs/core/tpl/filemanager.tpl.php
  100. 8 3
      htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php

+ 2 - 1
.travis.yml

@@ -288,7 +288,8 @@ script:
   echo "Checking PHP syntax errors"
   # Ensure we catch errors
   set -e
-  parallel-lint --exclude htdocs/includes --blame .
+  #parallel-lint --exclude htdocs/includes --blame .
+  parallel-lint --exclude htdocs/includes/sabre --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 .
   set +e
   echo
 

+ 99 - 7
ChangeLog

@@ -5,21 +5,111 @@ English Dolibarr ChangeLog
 
 ***** ChangeLog for 9.0.0 compared to 8.0.0 *****
 For Users:
-NEW: Stable module: Website
-NEW: Stable module: WebDAV
-NEW: Stable module: Module Builder
+NEW: Stable module: DAV (WebDAV only for the moment)
 NEW: Stable module "Skype" has been replaced with module "Social Networks" to support more services.
+NEW: Stable module "Module Builder"
+NEW: Stable module: Website
 NEW: Experimental module "TakePos"
 NEW: Experimental module "Ticket"
+NEW: Experimental module "Data Privacy"
+NEW: Experimental module "Email Collector"
 NEW: Dolibarr can provide information in page title when multicompany is enabled of not, making
      Android application like DoliDroid able to provide native features for multicompany module.
-NEW: Compatibility with PHP 7.3
+NEW: Compatibility with PHP 7.3 => 
+NEW: Add admin page for modulebuilder
+NEW: Add civility in list of members. Close #9251
+NEW: Add configuration to disable "customer/prospect" thirdparty type
+NEW: Add CONTRACT_ALLOW_TO_LINK_FROM_OTHER_COMPANY and CONTRACT_HIDE_UNSELECTABLES by SELECT_HIDE_UNSELECTABLES
+NEW: Add __DAY_TEXT__ and __MONTH_TEXT__ substitutions vars
+NEW: Add due date column in payment lists
+NEW: Add email in event history, for reminder email of expired subsription
+NEW: Add event tab on resource record
+NEW: Add FEC Export in accountancy
+NEW: Add filter on staff range in list of thirdparties
+NEW: Add a first complete template of website
+NEW: Add format code into exported filename of ledger
+NEW: Add hidden option EXPENSEREPORT_DEFAULT_VALIDATOR_UNCHANGEABLE
+NEW: Add hidden option MAIN_DOCUMENTS_DESCRIPTION_FIRST
+NEW: Add link to inventory code
+NEW: Add more common social networks fields for business
+NEW: Add option PDF_DISABLE_MYCOMPANY_LOGO to disable logo on PDF
+NEW: add option PROPOSAL_AUTO_ADD_AUTHOR_AS_CONTACT
+NEW: Add option to display thirdparty adress in combolist
+NEW: Add option to swap sender/recipient address on PDF
+NEW: Add option to display thirdparty adress in combolist
+NEW: Add project on pament of salaries
+NEW: Add SHIPPING_PDF_HIDE_WEIGHT_AND_VOLUME and
+NEW: Add somes hooks in bank planned entries
+NEW: Add supplier ref in item reception page
+NEW: Advanced permission to ignore price min
+NEW: Allow to enter a timespent with a numeric value
+NEW: Automatic position of scroll when creating an extrafield
+NEW: Can add autorefresh=X in any URLs to refresh page after X seconds
+NEW: can add project's task to agenda on create event form
+NEW: Can delete a website in experimental website module
+NEW: Can disable meteo on smartphone only
+NEW: Can export/import a website template
+NEW: Can filter on EEC, not EEC, etc... in binding step of accountancy
+NEW: Can mix offset before and after with rules for due date of invoices
+NEW: Can record the supplier product description
+NEW: Can select several prospect level in thirdparty filter.
+NEW: Can set 2 url in url field of thirdparty
+NEW: Can set if a field is mandatory on form level.
+NEW: Can set the default focus of each page.
+NEW: Add category filter on user list
+NEW: Change forgotten password link in general parameters
+NEW: Child label of variants change if parent label changes
+NEW: Compatibility with new Paybox HMAC requirement
+NEW: Each user can set its prefered default calendar page
+NEW: Enhancement in process to make manual bank conciliation
+NEW: Enhancement in the generic file manager
+NEW: Extrafield totalizable
+NEW: Hidden conf INVOICE_USE_DEFAULT_DOCUMENT
+NEW: hidden conf to search product by supplier ref
+NEW: hidden constant to be able to use a thirdparty for donation
+NEW: hidden option to define an invoice template for each invoice type
+NEW: Highlight lines on lists when they are checked
+NEW: Notification module support expense report+holiday validation and approval
+NEW: On customer/supplier card, add simple tooltip to amount boxes
+NEW: Page to check if the operations/items created between two dates have attached item(s) and possibility to download all attachements
+NEW: possibility to add all rights of all modules in one time
+NEW: redirect if only one result on global search on card
+NEW: Permission to ignore price min
+NEW: Can build an archive of full documents directory from backup page
+NEW: tag odt line_product_ref_fourn for supplier doc lines
+NEW: The binding step in accountancy has a country filter with autocompletion
+NEW: Top menu is always on screen with MD theme.
+NEW: Withdraw request massaction can include already partially paid invoices
 
 
 For developers:
-* Code changes to be more compatible with PSR2
-* Removed trigger USER_LOGOUT, USER_LOGIN, USER_LOGIN_FAILED (Some hooks are already dedicated for that)
-* Change getEntity('invoice') instead getEntity('facture')
+NEW: Add lib for multiselect with checkboxes
+NEW: Add function isValidMXRecord
+NEW: Add hook changeRoundingMode in update_price
+NEW: Add hook formconfirm to contractcard
+NEW: Add hook for virtual stock
+NEW: ADD url to see the last version of a external module
+NEW: Can enable a module, even external module, from command line
+NEW: Can set a tooltip help text on extrafields
+NEW: Add product search from barcode via REST api
+NEW: can add documents on agenda events using API REST
+NEW: Can set the datestart and dateend of cron job into module descriptor
+NEW: Close #9296 Add field ref_ext into llx_categorie
+NEW: move ticket dictionary in API /setup
+NEW: PHPUnitTest on Loan class #3163
+NEW: Code changes to be more compatible with PSR2
+NEW: Removed trigger USER_LOGOUT, USER_LOGIN, USER_LOGIN_FAILED (Some hooks are already dedicated for that)
+NEW: Add agenda documents in API REST
+NEW: Add "checked" field for new list engine compatibility
+NEW: REST API improvements
+NEW: Save external payment IDs into table of payment
+NEW: triggers add commercial and del commercial
+NEW: #9236 Allow to import shipment lines via API
+NEW: ADD civility list in API
+NEW: support selllist in the  module builder
+NEW: optional param to show a specific extrafield
+NEW: hook formConfirm always called if hooked
+NEW: hook on dispatch order fourn
 
 WARNING:
 
@@ -28,6 +118,8 @@ Following changes may create regressions for some external modules, but were nec
   replace them with links like viewimages.php?modulepart=mycompany&file=logos/... (note that link change only for
   modulepart=mycompany that now works like others).
 * Hidden option MAIN_PDF_SHIPPING_DISPLAY_AMOUNT_HT has been renamed into SHIPPING_PDF_DISPLAY_AMOUNT_HT
+* Remove the no more used and deprecated dol_print_graph function
+
 
 
 ***** ChangeLog for 8.0.3 compared to 8.0.2 *****

+ 14 - 2
build/docker/Dockerfile

@@ -3,18 +3,30 @@ FROM php:7.0-apache
 ENV HOST_USER_ID 33
 ENV PHP_INI_DATE_TIMEZONE 'UTC'
 
-RUN apt-get update && apt-get install -y libpng12-dev libjpeg-dev libldap2-dev \
+RUN apt-get update && apt-get install -y libpng-dev libjpeg-dev libldap2-dev \
 	&& 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-configure ldap --with-libdir=lib/x86_64-linux-gnu/ \
         && docker-php-ext-install ldap \
         && docker-php-ext-install mysqli \
-        && apt-get purge -y libpng12-dev libjpeg-dev libldap2-dev
+        && apt-get purge -y libjpeg-dev libldap2-dev
 
 COPY docker-run.sh /usr/local/bin/
 RUN chmod +x /usr/local/bin/docker-run.sh
 
+RUN pecl install xdebug-2.5.5 && docker-php-ext-enable xdebug
+RUN echo 'zend_extension="/usr/local/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so"' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_autostart=0' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_enable=1' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.default_enable=0' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_host=docker.for.mac.host.internal' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_port=9000' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_connect_back=0' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.profiler_enable=0' >> /usr/local/etc/php/php.ini
+RUN echo 'xdebug.remote_log="/tmp/xdebug.log"' >> /usr/local/etc/php/php.ini
+
+
 EXPOSE 80
 
 ENTRYPOINT ["docker-run.sh"]

+ 5 - 1
build/makepack-dolibarr.pl

@@ -535,6 +535,8 @@ if ($nboftargetok) {
    	    $ret=`find $BUILDROOT/$PROJECT/htdocs/custom/* -type l -exec rm -fr {} \\; >/dev/null 2>&1`;	# For custom we want to remove all subdirs, even symbolic links, but not files
 
 		# Removed known external modules to avoid any error when packaging from env where external modules are tested 
+		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/abricot*`;
+		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/accountingexport*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/allscreens*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/ancotec*`;
 	    $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/cabinetmed*`;
@@ -549,12 +551,14 @@ if ($nboftargetok) {
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/multicompany*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/ndf*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/nltechno*`;
+		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/nomenclature*`;
+	    $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/of/`;
 	    $ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/oscim*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/pos*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/teclib*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/timesheet*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/webmail*`;
-		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/accountingexport*`;
+		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/workstation*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/themes/oblyon*`;
 		$ret=`rm -fr $BUILDROOT/$PROJECT/htdocs/themes/allscreen*`;
 		# Removed other test files

File diff suppressed because it is too large
+ 55 - 0
dev/initdemo/mysqldump_dolibarr_8.0.0.sql


File diff suppressed because it is too large
+ 55 - 0
dev/initdemo/mysqldump_dolibarr_9.0.0.sql


+ 2 - 0
dev/initdemo/savedemo.sh

@@ -171,6 +171,8 @@ export list="
     --ignore-table=$base.llx_abonne_extrafields 
     --ignore-table=$base.llx_abonne_type
     --ignore-table=$base.llx_abonnement 
+    --ignore-table=$base.llx_accountingaccount 
+    --ignore-table=$base.llx_accountingsystem 
     --ignore-table=$base.llx_advanced_extrafields 
     --ignore-table=$base.llx_advanced_extrafields_options 
     --ignore-table=$base.llx_advanced_extrafields_values

+ 5 - 4
htdocs/accountancy/admin/card.php

@@ -1,7 +1,7 @@
 <?php
-/* Copyright (C) 2013-2014 Olivier Geffroy      <jeff@jeffinfo.com>
- * Copyright (C) 2013-2017 Alexandre Spangaro   <aspangaro@zendsi.com>
- * Copyright (C) 2014      Florian Henry        <florian.henry@open-concept.pro>
+/* Copyright (C) 2013-2014  Olivier Geffroy     <jeff@jeffinfo.com>
+ * Copyright (C) 2013-2018  Alexandre Spangaro  <aspangaro@zendsi.com>
+ * Copyright (C) 2014       Florian Henry       <florian.henry@open-concept.pro>
  *
  * 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
@@ -41,6 +41,7 @@ $id = GETPOST('id', 'int');
 $ref = GETPOST('ref', 'alpha');
 $rowid = GETPOST('rowid', 'int');
 $cancel = GETPOST('cancel','alpha');
+$accountingaccount = GETPOST('accountingaccount','alpha');
 
 // Security check
 
@@ -229,7 +230,7 @@ if ($action == 'create') {
 
 	// Account number
 	print '<tr><td class="titlefieldcreate"><span class="fieldrequired">' . $langs->trans("AccountNumber") . '</span></td>';
-	print '<td><input name="account_number" size="30" value="' . $object->account_number . '"></td></tr>';
+	print '<td><input name="account_number" size="30" value="' . $accountingaccount . '"></td></tr>';
 
 	// Label
 	print '<tr><td><span class="fieldrequired">' . $langs->trans("Label") . '</span></td>';

+ 3 - 4
htdocs/accountancy/bookkeeping/balance.php

@@ -58,7 +58,7 @@ $pagenext = $page + 1;
 
 
 $search_date_start = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int'));
-$search_date_end = dol_mktime(0, 0, 0, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
+$search_date_end = dol_mktime(23, 59, 59, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int'));
 
 $search_accountancy_code_start = GETPOST('search_accountancy_code_start', 'alpha');
 if ($search_accountancy_code_start == - 1) {
@@ -127,7 +127,6 @@ if (! empty($search_accountancy_code_end)) {
 	$param .= '&amp;search_accountancy_code_end=' . $search_accountancy_code_end;
 }
 
-
 /*
  * Action
  */
@@ -154,7 +153,7 @@ if ($action == 'export_csv')
 	$type_export = 'balance';
 	include DOL_DOCUMENT_ROOT . '/accountancy/tpl/export_journal.tpl.php';
 
-	$result = $object->fetchAllBalance($sortorder, $sortfield, 0, 0, $filter);
+	$result = $object->fetchAllBalance($sortorder, $sortfield, $limit, 0, $filter);
 	if ($result < 0) {
 		setEventMessages($object->error, $object->errors, 'errors');
 	}
@@ -266,7 +265,7 @@ if ($action != 'export_csv')
 		$description = $object->get_compte_desc($line->numero_compte); // Search description of the account
 		$root_account_description = $object->get_compte_racine($line->numero_compte);
 		if (empty($description)) {
-			$link = '<a href="../admin/card.php?action=create&compte=' . length_accountg($line->numero_compte) . '">' . img_edit_add() . '</a>';
+			$link = '<a href="../admin/card.php?action=create&accountingaccount=' . length_accountg($line->numero_compte) . '">' . img_edit_add() . '</a>';
 		}
 		print '<tr class="oddeven">';
 

+ 71 - 38
htdocs/accountancy/class/accountancycategory.class.php

@@ -78,7 +78,7 @@ class AccountancyCategory // extends CommonObject
 	public $range_account;
 
 	/**
-	 * @var mixed Sample property 1
+	 * @var int Sens of the account:  0: credit - debit, 1: debit - credit
 	 */
 	public $sens;
 
@@ -163,16 +163,17 @@ class AccountancyCategory // extends CommonObject
 
 		// Insert request
 		$sql = "INSERT INTO ".MAIN_DB_PREFIX."c_accounting_category(";
-		if ($this->rowid > 0) $sql.= "rowid,";
-		$sql.= "code,";
-		$sql.= "label,";
-		$sql.= "range_account,";
-		$sql.= "sens,";
-		$sql.= "category_type,";
-		$sql.= "formula,";
-		$sql.= "position,";
-		$sql.= "fk_country,";
-		$sql.= "active";
+		if ($this->rowid > 0) $sql.= "rowid, ";
+		$sql.= "code, ";
+		$sql.= "label, ";
+		$sql.= "range_account, ";
+		$sql.= "sens, ";
+		$sql.= "category_type, ";
+		$sql.= "formula, ";
+		$sql.= "position, ";
+		$sql.= "fk_country, ";
+		$sql.= "active, ";
+		$sql.= "entity";
 		$sql.= ") VALUES (";
 		if ($this->rowid > 0) $sql.= " ".$this->rowid.",";
 		$sql.= " ".(! isset($this->code)?'NULL':"'".$this->db->escape($this->code)."'").",";
@@ -184,6 +185,7 @@ class AccountancyCategory // extends CommonObject
 		$sql.= " ".(! isset($this->position)?'NULL':$this->db->escape($this->position)).",";
 		$sql.= " ".(! isset($this->fk_country)?'NULL':$this->db->escape($this->fk_country)).",";
 		$sql.= " ".(! isset($this->active)?'NULL':$this->db->escape($this->active));
+		$sql.= ", ".$conf->entity;
 		$sql.= ")";
 
 		$this->db->begin();
@@ -237,9 +239,8 @@ class AccountancyCategory // extends CommonObject
 	 *  @param		string	$label	Label
 	 *  @return     int          	<0 if KO, >0 if OK
 	 */
-	function fetch($id,$code='',$label='')
+	function fetch($id, $code='', $label='')
 	{
-		global $langs;
 		$sql = "SELECT";
 		$sql.= " t.rowid,";
 		$sql.= " t.code,";
@@ -253,8 +254,12 @@ class AccountancyCategory // extends CommonObject
 		$sql.= " t.active";
 		$sql.= " FROM ".MAIN_DB_PREFIX."c_accounting_category as t";
 		if ($id)   $sql.= " WHERE t.rowid = ".$id;
-		elseif ($code) $sql.= " WHERE t.code = '".$this->db->escape($code)."'";
-		elseif ($label) $sql.= " WHERE t.label = '".$this->db->escape($label)."'";
+		else
+		{
+			$sql.= " WHERE t.entity IN (".getEntity('c_accounting_category').")"; // Dont't use entity if you use rowid
+			if ($code) $sql.= " AND t.code = '".$this->db->escape($code)."'";
+			elseif ($label) $sql.= " AND t.label = '".$this->db->escape($label)."'";
+		}
 
 		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
 		$resql=$this->db->query($sql);
@@ -480,7 +485,7 @@ class AccountancyCategory // extends CommonObject
 		$sql .= " INNER JOIN " . MAIN_DB_PREFIX . "accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version";
 		$sql .= " AND asy.rowid = " . $conf->global->CHARTOFACCOUNTS;
 		$sql .= " AND aa.active = 1";
-		$sql .= " AND aa.entity = = " . $conf->entity . ")";
+		$sql .= " AND aa.entity = " . $conf->entity . ")";
 		$sql .= " GROUP BY t.numero_compte, t.label_operation, t.doc_ref";
 		$sql .= " ORDER BY t.numero_compte";
 
@@ -712,49 +717,76 @@ class AccountancyCategory // extends CommonObject
 	/**
 	 * Function to show result of an accounting account from the ledger with a direction and a period
 	 *
-	 * @param int 		$cpt 				Id accounting account
-	 * @param string 	$month 				Specifig month - Can be empty
+	 * @param int|array	$cpt 				Accounting account or array of accounting account
 	 * @param string 	$date_start			Date start
 	 * @param string 	$date_end			Date end
 	 * @param int 		$sens 				Sens of the account:  0: credit - debit, 1: debit - credit
 	 * @param string	$thirdparty_code	Thirdparty code
-	 * @return integer 						Result in table
+	 * @param int       $month 				Specifig month - Can be empty
+	 * @param int       $year 				Specifig year - Can be empty
+	 * @return integer 						<0 if KO, >= 0 if OK
 	 */
-	public function getResult($cpt, $month, $date_start, $date_end, $sens, $thirdparty_code='nofilter')
+	public function getSumDebitCredit($cpt, $date_start, $date_end, $sens, $thirdparty_code='nofilter', $month=0, $year=0)
 	{
+		global $conf;
+
+		$this->sdc = 0;
+		$this->sdcpermonth = array();
+
 		$sql = "SELECT SUM(t.debit) as debit, SUM(t.credit) as credit";
+		if (is_array($cpt)) $sql.=", t.numero_compte as accountancy_account";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_bookkeeping as t";
-		$sql .= " WHERE t.numero_compte = '" . $cpt."'";
-		if (! empty($date_start) && ! empty($date_end))
-			$sql.= " AND t.doc_date >= '".$this->db->idate($date_start)."' AND t.doc_date <= '".$this->db->idate($date_end)."'";
-		if (! empty($month)) {
-			$sql .= " AND MONTH(t.doc_date) = " . $month;
+		//if (in_array($this->db->type, array('mysql', 'mysqli'))) $sql.=' USE INDEX idx_accounting_bookkeeping_doc_date';
+		$sql .= " WHERE t.entity = ".$conf->entity;
+		if (is_array($cpt))
+		{
+			$listofaccount='';
+			foreach($cpt as $cptcursor)
+			{
+				if ($listofaccount) $listofaccount.=",";
+				$listofaccount.="'".$cptcursor."'";
+			}
+			$sql .= " AND t.numero_compte IN (" .$listofaccount. ")";
+		}
+		else
+		{
+			$sql .= " AND t.numero_compte = '" . $this->db->escape($cpt) . "'";
+		}
+		if (! empty($date_start) && ! empty($date_end) && (empty($month) || empty($year)))	// If month/year provided, it is stronger than filter date_start/date_end
+			$sql .= " AND (t.doc_date BETWEEN '".$this->db->idate($date_start)."' AND '".$this->db->idate($date_end)."')";
+		if (! empty($month) && ! empty($year)) {
+			$sql .= " AND (t.doc_date BETWEEN '".$this->db->idate(dol_get_first_day($year, $month))."' AND '".$this->db->idate(dol_get_last_day($year, $month))."')";
 		}
 		if ($thirdparty_code != 'nofilter')
 		{
-			$sql .= " AND thirdparty_code = '".$this->db->escape($thirdparty_code)."'";
+			$sql .= " AND t.thirdparty_code = '".$this->db->escape($thirdparty_code)."'";
 		}
+		if (is_array($cpt)) $sql.=" GROUP BY t.numero_compte";
+		//print $sql;
 
-		dol_syslog(__METHOD__ . " sql=" . $sql, LOG_DEBUG);
 		$resql = $this->db->query($sql);
-
-		if ($resql) {
+		if ($resql)
+		{
 			$num = $this->db->num_rows($resql);
-			$this->sdc = 0;
-			if ($num) {
+			if ($num)
+			{
 				$obj = $this->db->fetch_object($resql);
 				if ($sens == 1) {
 					$this->sdc = $obj->debit - $obj->credit;
 				} else {
 					$this->sdc = $obj->credit - $obj->debit;
 				}
+				if (is_array($cpt))
+				{
+					$this->sdcperaccount[$obj->accountancy_account] = $this->sdc;
+				}
 			}
 			return $num;
 		} else {
 			$this->error = "Error " . $this->db->lasterror();
+			$this->errors[] = $this->error;
 			dol_syslog(__METHOD__ . " " . $this->error, LOG_ERR);
-
-			return - 1;
+			return -1;
 		}
 	}
 
@@ -766,7 +798,7 @@ class AccountancyCategory // extends CommonObject
 	 */
 	public function getCats($categorytype=-1)
 	{
-		global $db, $langs, $user, $mysoc, $conf;
+		global $conf, $mysoc;
 
 		if (empty($mysoc->country_id)) {
 			dol_print_error('', 'Call to select_accounting_account with mysoc country not yet defined');
@@ -775,7 +807,7 @@ class AccountancyCategory // extends CommonObject
 
 		$sql = "SELECT c.rowid, c.code, c.label, c.formula, c.position, c.category_type";
 		$sql .= " FROM " . MAIN_DB_PREFIX . "c_accounting_category as c";
-		$sql .= " WHERE c.active = 1 ";
+		$sql .= " WHERE c.active = 1";
 		$sql .= " AND c.entity = " . $conf->entity;
 		if ($categorytype >= 0) $sql.=" AND c.category_type = 1";
 		$sql .= " AND (c.fk_country = ".$mysoc->country_id." OR c.fk_country = 0)";
@@ -823,7 +855,7 @@ class AccountancyCategory // extends CommonObject
 	 */
 	public function getCptsCat($cat_id, $predefinedgroupwhere='')
 	{
-		global $mysoc;
+		global $conf, $mysoc;
 		$sql = '';
 
 		if (empty($mysoc->country_id) && empty($mysoc->country_code)) {
@@ -836,6 +868,7 @@ class AccountancyCategory // extends CommonObject
 			$sql = "SELECT t.rowid, t.account_number, t.label as account_label";
 			$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t";
 			$sql .= " WHERE t.fk_accounting_category = ".$cat_id;
+			$sql .= " AND t.entity = " . $conf->entity;
 			$sql .= " ORDER BY t.account_number";
 		}
 		else
@@ -843,6 +876,7 @@ class AccountancyCategory // extends CommonObject
 			$sql = "SELECT t.rowid, t.account_number, t.label as account_label";
 			$sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as t";
 			$sql .= " WHERE ".$predefinedgroupwhere;
+			$sql .= " AND t.entity = " . $conf->entity;
 			$sql .= " ORDER BY t.account_number";
 		}
 		//echo $sql;
@@ -856,13 +890,12 @@ class AccountancyCategory // extends CommonObject
 			if ($num) {
 				while ($obj = $this->db->fetch_object($resql))
 				{
-					$name_cat = $obj->name_cat;
 					$data[] = array (
 							'id' => $obj->rowid,
 							'account_number' => $obj->account_number,
 							'account_label' => $obj->account_label,
 					);
-					$i ++;
+					$i++;
 				}
 			}
 			return $data;

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

@@ -817,7 +817,7 @@ class BookKeeping extends CommonObject
 			$num = $this->db->num_rows($resql);
 
 			$i = 0;
-			while ($obj = $this->db->fetch_object($resql) && (empty($limit) || $i < min($limit, $num))) {
+			while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num))) {
 				$line = new BookKeepingLine();
 
 				$line->id = $obj->rowid;
@@ -866,14 +866,13 @@ class BookKeeping extends CommonObject
 	/**
 	 * Load object in memory from the database
 	 *
-	 * @param string $sortorder Sort Order
-	 * @param string $sortfield Sort field
-	 * @param int $limit offset limit
-	 * @param int $offset offset limit
-	 * @param array $filter filter array
-	 * @param string $filtermode filter mode (AND or OR)
-	 *
-	 * @return int <0 if KO, >0 if OK
+	 * @param string 		$sortorder 		Sort Order
+	 * @param string 		$sortfield 		Sort field
+	 * @param int 			$limit 			Offset limit
+	 * @param int 			$offset 		Offset limit
+	 * @param array 		$filter 		Filter array
+	 * @param string 		$filtermode 	Filter mode (AND or OR)
+	 * @return int 							<0 if KO, >0 if OK
 	 */
     public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, array $filter = array(), $filtermode = 'AND')
     {
@@ -932,7 +931,7 @@ class BookKeeping extends CommonObject
 				}
 			}
 		}
-		$sql.= ' WHERE entity IN (' . getEntity('accountancy') . ')';
+		$sql.= ' WHERE t.entity IN (' . getEntity('accountancy') . ')';
 		if (count($sqlwhere) > 0) {
 			$sql .= ' AND ' . implode(' ' . $filtermode . ' ', $sqlwhere);
 		}
@@ -950,7 +949,8 @@ class BookKeeping extends CommonObject
 			$num = $this->db->num_rows($resql);
 
 			$i = 0;
-			while ($obj = $this->db->fetch_object($resql) && (empty($limit) || $i < min($limit, $num))) {
+			while (($obj = $this->db->fetch_object($resql)) && (empty($limit) || $i < min($limit, $num)))
+			{
 				$line = new BookKeepingLine();
 
 				$line->id = $obj->rowid;
@@ -989,8 +989,7 @@ class BookKeeping extends CommonObject
 		} else {
 			$this->errors[] = 'Error ' . $this->db->lasterror();
 			dol_syslog(__METHOD__ . ' ' . join(',', $this->errors), LOG_ERR);
-
-			return - 1;
+			return -1;
 		}
 	}
 
@@ -1067,6 +1066,7 @@ class BookKeeping extends CommonObject
 				$line->numero_compte = $obj->numero_compte;
 				$line->debit = $obj->debit;
 				$line->credit = $obj->credit;
+
 				$this->lines[] = $line;
 
 				$i++;
@@ -1577,7 +1577,7 @@ class BookKeeping extends CommonObject
 		$result = $this->db->query($sql);
 		if ($result) {
 
-			while ( $obj = $this->db->fetch_object($result) ) {
+			while ($obj = $this->db->fetch_object($result)) {
 
 				$line = new BookKeepingLine();
 
@@ -1641,7 +1641,7 @@ class BookKeeping extends CommonObject
 			$this->linesexport = array ();
 
 			$num = $this->db->num_rows($resql);
-			while ( $obj = $this->db->fetch_object($resql) ) {
+			while ($obj = $this->db->fetch_object($resql)) {
 				$line = new BookKeepingLine();
 
 				$line->id = $obj->rowid;

+ 1 - 1
htdocs/accountancy/class/lettering.class.php

@@ -211,7 +211,7 @@ class Lettering extends BookKeeping
 				}
 
 				if (count($ids) > 1) {
-					$result = $this->updatelettrage($ids);
+					$result = $this->updateLettering($ids);
 				}
 			}
 		}

+ 4 - 3
htdocs/accountancy/journal/bankjournal.php

@@ -1142,7 +1142,7 @@ $db->close();
  *
  * @param 	string 	$val			Array of val
  * @param 	string	$typerecord		Type of record ('payment', 'payment_supplier', 'payment_expensereport', 'payment_vat', ...)
- * @return string|unknown
+ * @return 	string					A string label to describe a record into llx_bank_url
  */
 function getSourceDocRef($val, $typerecord)
 {
@@ -1250,7 +1250,8 @@ function getSourceDocRef($val, $typerecord)
 	{
 		dol_syslog("accountancy/journal/bankjournal.php::sqlmid=" . $sqlmid, LOG_DEBUG);
 		$resultmid = $db->query($sqlmid);
-		if ($resultmid) {
+		if ($resultmid)
+		{
 			while ($objmid = $db->fetch_object($resultmid))
 			{
 				$ref.=' '.$objmid->ref;
@@ -1259,6 +1260,6 @@ function getSourceDocRef($val, $typerecord)
 		else dol_print_error($db);
 	}
 
-	$ref = dol_trunc($langs->trans("BankId").' '.$val['fk_bank'].' - '.$ref, 295);	// 295 + 3 ... i< < than max size of 300
+	$ref = dol_trunc($langs->trans("BankId").' '.$val['fk_bank'].' - '.$ref, 295);	// 295 + 3 dots (...) is < than max size of 300
 	return $ref;
 }

+ 5 - 2
htdocs/adherents/card.php

@@ -1286,8 +1286,11 @@ else
 			$cate_arbo = $form->select_all_categories(Categorie::TYPE_MEMBER, null, null, null, null, 1);
 			$c = new Categorie($db);
 			$cats = $c->containing($object->id, Categorie::TYPE_MEMBER);
-			foreach ($cats as $cat) {
-				$arrayselected[] = $cat->id;
+			$arrayselected = array();
+			if (is_array($cats)) {
+				foreach ($cats as $cat) {
+					$arrayselected[] = $cat->id;
+				}
 			}
 			print $form->multiselectarray('memcats', $cate_arbo, $arrayselected, '', 0, '', 0, '100%');
 			print "</td></tr>";

+ 79 - 29
htdocs/adherents/class/adherent.class.php

@@ -59,6 +59,9 @@ class Adherent extends CommonObject
 
 	public $mesgs;
 
+    /**
+     * @var string login of member
+     */
 	public $login;
 
 	//! Clear password in memory
@@ -68,29 +71,70 @@ class Adherent extends CommonObject
 	//! Encrypted password in database (always defined)
 	public $pass_indatabase_crypted;
 
+    /**
+     * @var string company name
+     * @deprecated
+     */
 	public $societe;
 
 	/**
-	 * @var Societe $company {@type Societe}
+	 * @var string company name
 	 */
 	public $company;
 
+	/**
+	 * @var int Thirdparty ID
+	 */
+    public $fk_soc;
+
 	/**
 	 * @var string Address
 	 */
 	public $address;
 
-	public $zip;
+    /**
+     * @var string zipcode
+     */
+    public $zip;
+
+    /**
+     * @var string town
+     */
 	public $town;
 
-	public $state_id;              // Id of department
-	public $state_code;            // Code of department
-	public $state;                 // Label of department
+    /**
+     * @var int Id of state
+     */
+    public $state_id;
+
+    /**
+     * @var string Code of state
+     */
+    public $state_code;
+
+    /**
+     * @var string Label of state
+     */
+	public $state;
 
+    /**
+     * @var string email
+     */
 	public $email;
 
-	public $skype;
-	public $twitter;
+    /**
+     * @var string skype account
+     */
+    public $skype;
+
+    /**
+     * @var string twitter account
+     */
+    public $twitter;
+
+    /**
+     * @var string facebook account
+     */
 	public $facebook;
 
     /**
@@ -120,8 +164,12 @@ class Adherent extends CommonObject
 
 	public $morphy;
 	public $public;
-	public $statut;			// -1:brouillon, 0:resilie, >=1:valide,paye
-	public $photo;
+
+    // -1:brouillon, 0:resilie, >=1:valide,paye
+    // def in common object
+    //public $statut;
+
+    public $photo;
 
 	public $datec;
 	public $datem;
@@ -129,21 +177,20 @@ class Adherent extends CommonObject
 
 	public $birth;
 
-	public $note_public;
-	public $note_private;
+    /**
+     * @var int id type member
+     */
+	public $typeid;
 
-	public $typeid;			// Id type adherent
-	public $type;				// Libelle type adherent
+    /**
+     * @var string label type member
+     */
+	public $type;
 	public $need_subscription;
 
 	public $user_id;
 	public $user_login;
 
-	/**
-	 * @var int Thirdparty ID
-	 */
-    public $fk_soc;
-
 	public $datefin;	// From member table
 
 	// Fields loaded by fetch_subscriptions()
@@ -155,7 +202,10 @@ class Adherent extends CommonObject
 	public $last_subscription_amount;
 	public $subscriptions=array();
 
-	public $oldcopy;		// To contains a clone of this when we need to save old properties of object
+    /**
+     * @var Adherent To contains a clone of this when we need to save old properties of object
+     */
+	public $oldcopy;
 
 	/**
 	 * @var int Entity
@@ -593,11 +643,11 @@ class Adherent extends CommonObject
 						$luser->societe_id=$this->societe;
 
 						$luser->birth=$this->birth;
-                                                $luser->address=$this->address;
-                                                $luser->zip=$this->zip;
-                                                $luser->town=$this->town;
-                                                $luser->country_id=$this->country_id;
-                                                $luser->state_id=$this->state_id;
+                        $luser->address=$this->address;
+                        $luser->zip=$this->zip;
+                        $luser->town=$this->town;
+                        $luser->country_id=$this->country_id;
+                        $luser->state_id=$this->state_id;
 
 						$luser->email=$this->email;
 						$luser->skype=$this->skype;
@@ -2656,7 +2706,7 @@ class Adherent extends CommonObject
 			$this->output = $langs->trans('EventRemindersByEmailNotEnabled', $langs->transnoentitiesnoconv("Adherent"));
 			return 0;
 		}
-		
+
 		$now = dol_now();
 		$nbok = 0;
 		$nbko = 0;
@@ -2760,9 +2810,9 @@ class Adherent extends CommonObject
 									$actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('TextUsedInTheMessageBody') . ":");
 									$actionmsg = dol_concatdesc($actionmsg, $message);
 								}
-								
+
 								require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
-								
+
 	    						// Insert record of emails sent
 	    						$actioncomm = new ActionComm($this->db);
 
@@ -2787,10 +2837,10 @@ class Adherent extends CommonObject
 	    						$actioncomm->email_tobcc = $sendtobcc;
 	    						$actioncomm->email_subject = $subject;
 	    						$actioncomm->errors_to   = '';
-	    						
+
 	    						$actioncomm->fk_element  = $adherent->id;
 	    						$actioncomm->elementtype = $adherent->element;
-	    						
+
 	    						$actioncomm->extraparams = $extraparams;
 
 	    						$actioncomm->create($user);

+ 3 - 2
htdocs/admin/defaultvalues.php

@@ -250,7 +250,7 @@ print '<tr class="liste_titre">';
 // Page
 $texthelp=$langs->trans("PageUrlForDefaultValues");
 if ($mode == 'createform') $texthelp.=$langs->trans("PageUrlForDefaultValuesCreate", 'societe/card.php', 'societe/card.php?abc=val1&def=val2');
-else $texthelp.=$langs->trans("PageUrlForDefaultValuesList", 'societe/list.php', 'societe/card.php?abc=val1&def=val2');
+else $texthelp.=$langs->trans("PageUrlForDefaultValuesList", 'societe/list.php', 'societe/list.php?abc=val1&def=val2');
 $texturl=$form->textwithpicto($langs->trans("Url"), $texthelp);
 print_liste_field_titre($texturl,$_SERVER["PHP_SELF"],'page,param','',$param,'',$sortfield,$sortorder);
 // Field
@@ -288,8 +288,9 @@ if ($mode != 'focus' && $mode != 'mandatory')
 }
 // Entity
 if (! empty($conf->multicompany->enabled) && !$user->entity) print_liste_field_titre("Entity",$_SERVER["PHP_SELF"],'entity,page','',$param,'',$sortfield,$sortorder);
+else print_liste_field_titre("",$_SERVER["PHP_SELF"],'','',$param,'',$sortfield,$sortorder);
 // Actions
-print '<td align="center"></td>';
+print_liste_field_titre("",$_SERVER["PHP_SELF"],'','',$param,'',$sortfield,$sortorder);
 print "</tr>\n";
 
 

+ 2 - 0
htdocs/admin/emailcollector_card.php

@@ -144,6 +144,8 @@ if (GETPOST('addoperation','alpha'))
 	$emailcollectoroperation->actionparam = GETPOST('operationparam', 'none');
 	$emailcollectoroperation->fk_emailcollector = $object->id;
 	$emailcollectoroperation->status = 1;
+	$emailcollectoroperation->position = 50;
+
 	$result = $emailcollectoroperation->create($user);
 
 	if ($result > 0)

+ 20 - 0
htdocs/admin/geoipmaxmind.php

@@ -24,6 +24,7 @@
 
 require '../main.inc.php';
 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
+require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
 
 // Security check
@@ -150,6 +151,25 @@ if ($geoip)
 	if ($result) print $result;
 	else print $langs->trans("Error");
 	*/
+	//var_dump($_SERVER);
+	$ip = getUserRemoteIP();
+	//$ip='91.161.249.43';
+	$isip=is_ip($ip);
+	if ($isip == 1)
+	{
+		print '<br>'.$ip.' -> ';
+		$result=dol_print_ip($ip,1);
+		if ($result) print $result;
+		else print $langs->trans("Error");
+	}
+	else
+	{
+		print '<br>'.$ip.' -> ';
+		$result=dol_print_ip($ip,1);
+		if ($result) print $result;
+		else print $langs->trans("NotAPublicIp");
+	}
+
 	$geoip->close();
 }
 

+ 9 - 4
htdocs/admin/mails_templates.php

@@ -11,6 +11,7 @@
  * Copyright (C) 2011-2016  Alexandre Spangaro      <aspangaro.dolibarr@gmail.com>
  * Copyright (C) 2015       Ferran Marcet           <fmarcet@2byte.es>
  * Copyright (C) 2016       Raphaël Doursenaud      <rdoursenaud@gpcsolutions.fr>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -421,7 +422,7 @@ if ($action == 'delete')
 //var_dump($elementList);
 
 
-$sql="SELECT rowid as rowid, label, type_template, lang, fk_user, private, position, topic, joinfiles, content_lines, content, active";
+$sql="SELECT rowid as rowid, label, type_template, lang, fk_user, private, position, topic, joinfiles, content_lines, content, enabled, active";
 $sql.=" FROM ".MAIN_DB_PREFIX."c_email_templates";
 $sql.=" WHERE entity IN (".getEntity('email_template').")";
 if (! $user->admin)
@@ -787,8 +788,12 @@ if ($resql)
             		$i++;
             		continue;		// It means this is a type of template not into elementList (may be because enabled condition of this type is false because module is not enabled)
             	}
-				// TODO Test on 'enabled'
-
+				// Test on 'enabled'
+				if (! dol_eval($obj->enabled, 1))
+				{
+					$i++;
+					continue;		// Email template not qualified
+				}
 
             	print '<tr class="oddeven" id="rowid-'.$obj->rowid.'">';
 
@@ -991,7 +996,7 @@ function fieldList($fieldlist, $obj='', $tabname='', $context='')
 			print '<td>';
 			if (! empty($conf->global->MAIN_MULTILANGS))
 			{
-				$selectedlang = GETPOSTISSET('langcode','aZ09')?GETPOST('langcode','aZ09'):$langs->defaultlang;
+				$selectedlang = GETPOSTISSET('langcode')?GETPOST('langcode', 'aZ09'):$langs->defaultlang;
 				if ($context == 'edit') $selectedlang = $obj->{$fieldlist[$field]};
 				print $formadmin->select_language($selectedlang, 'langcode', 0, null, 1, 0, 0, 'maxwidth150');
 			}

+ 4 - 1
htdocs/admin/modules.php

@@ -701,7 +701,10 @@ if ($mode == 'common')
         	else if (! empty($objMod->always_enabled) || ((! empty($conf->multicompany->enabled) && $objMod->core_enabled) && ($user->entity || $conf->entity!=1)))
         	{
         		if (method_exists($objMod, 'alreadyUsed') && $objMod->alreadyUsed()) print $langs->trans("Used");
-        		else print $langs->trans("Required");
+        		else {
+        			print img_picto($langs->trans("Required"),'switch_on');
+        			print $langs->trans("Required");
+        		}
         		if (! empty($conf->multicompany->enabled) && $user->entity) $disableSetup++;
         	}
         	else

+ 1 - 1
htdocs/admin/salaries.php

@@ -129,4 +129,4 @@ print '</form>';
 
 // End of page
 llxFooter();
-$db->close();;
+$db->close();

+ 2 - 2
htdocs/blockedlog/admin/blockedlog_list.php

@@ -304,7 +304,7 @@ if (GETPOST('withtab','alpha'))
 	dol_fiche_head($head, 'fingerprints', '', -1);
 }
 
-print '<span class="opacitymedium">'.$langs->trans("FingerprintsDesc")."</span><br>\n";
+print '<span class="opacitymedium hideonsmartphone">'.$langs->trans("FingerprintsDesc")."<br></span>\n";
 
 print '<br>';
 
@@ -342,7 +342,7 @@ for ($month = 1 ; $month <= 12 ; $month++)
 }
 $retstring.="</select>";
 print $retstring;
-print '<input type="text" name="yeartoexport" class="valignmiddle maxwidth75" value="'.GETPOST('yeartoexport','int').'">';
+print '<input type="text" name="yeartoexport" class="valignmiddle maxwidth50imp" value="'.GETPOST('yeartoexport','int').'">';
 print '<input type="hidden" name="withtab" value="'.GETPOST('withtab','alpha').'">';
 print '<input type="submit" name="downloadcsv" class="button" value="'.$langs->trans('DownloadLogCSV').'">';
 if (!empty($conf->global->BLOCKEDLOG_USE_REMOTE_AUTHORITY)) print ' | <a href="?action=downloadblockchain'.(GETPOST('withtab','alpha')?'&withtab='.GETPOST('withtab','alpha'):'').'">'.$langs->trans('DownloadBlockChain').'</a>';

+ 17 - 1
htdocs/categories/photos.php

@@ -69,7 +69,23 @@ if ($id > 0)
 if (isset($_FILES['userfile']) && $_FILES['userfile']['size'] > 0 && $_POST["sendit"] && ! empty($conf->global->MAIN_UPLOAD_DOC))
 {
     if ($object->id) {
-	    $object->add_photo($upload_dir, $_FILES['userfile']);
+
+        $file = $_FILES['userfile'];
+        if (is_array($file['name']) && count($file['name']) > 0)
+        {
+            foreach ($file['name'] as $i => $name)
+            {
+                if(empty($file['tmp_name'][$i]) || intval($conf->global->MAIN_UPLOAD_DOC) * 1000 <= filesize($file['tmp_name'][$i]) )
+                {
+                    setEventMessage($file['name'][$i] .' : '. $langs->trans(empty($file['tmp_name'][$i])? 'ErrorFailedToSaveFile' : 'MaxSizeForUploadedFiles' ) );
+                    unset($file['name'][$i],$file['type'][$i],$file['tmp_name'][$i],$file['error'][$i],$file['size'][$i]);
+                }
+            }
+        }
+
+        if(!empty($file['tmp_name'])) {
+            $object->add_photo($upload_dir, $file);
+        }
     }
 }
 

+ 3 - 3
htdocs/comm/action/card.php

@@ -1302,7 +1302,6 @@ if ($id > 0)
 		print '<tr><td class="titlefieldcreate nowrap">'.$langs->trans("Priority").'</td><td>';
 		print '<input type="text" name="priority" value="'.($object->priority?$object->priority:'').'" size="5">';
 		print '</td></tr>';
-
 		// Object linked
 		if (! empty($object->fk_element) && ! empty($object->elementtype))
 		{
@@ -1610,8 +1609,9 @@ if ($id > 0)
 		print ($object->priority?$object->priority:'');
 		print '</td></tr>';
 
-		// Object linked
-		if (! empty($object->fk_element) && ! empty($object->elementtype))
+		// Object linked (if link is for thirdparty, contact, project it is a recording error. We should not have links in link table
+		// for such objects because there is already a dedicated field into table llx_actioncomm.
+		if (! empty($object->fk_element) && ! empty($object->elementtype) && ! in_array($object->elementtype, array('societe','contact','project')))
 		{
 			include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
 			print '<tr><td>'.$langs->trans("LinkedObject").'</td>';

+ 25 - 7
htdocs/comm/action/class/actioncomm.class.php

@@ -334,7 +334,16 @@ class ActionComm extends CommonObject
         $sql.= "fk_element,";
         $sql.= "elementtype,";
         $sql.= "entity,";
-        $sql.= "extraparams";
+        $sql.= "extraparams,";
+		// Fields emails
+        $sql.= "email_msgid,";
+        $sql.= "email_from,";
+        $sql.= "email_sender,";
+        $sql.= "email_to,";
+        $sql.= "email_tocc,";
+        $sql.= "email_tobcc,";
+        $sql.= "email_subject,";
+        $sql.= "errors_to";
         $sql.= ") VALUES (";
         $sql.= "'".$this->db->idate($now)."', ";
         $sql.= (strval($this->datep)!=''?"'".$this->db->idate($this->datep)."'":"null").", ";
@@ -354,7 +363,16 @@ class ActionComm extends CommonObject
         $sql.= (! empty($this->fk_element)?$this->fk_element:"null").", ";
         $sql.= (! empty($this->elementtype)?"'".$this->db->escape($this->elementtype)."'":"null").", ";
         $sql.= $conf->entity.",";
-        $sql.= (! empty($this->extraparams)?"'".$this->db->escape($this->extraparams)."'":"null");
+        $sql.= (! empty($this->extraparams)?"'".$this->db->escape($this->extraparams)."'":"null").", ";
+        // Fields emails
+        $sql.= (! empty($this->email_msgid)?"'".$this->db->escape($this->email_msgid)."'":"null").", ";
+        $sql.= (! empty($this->email_from)?"'".$this->db->escape($this->email_from)."'":"null").", ";
+        $sql.= (! empty($this->email_sender)?"'".$this->db->escape($this->email_sender)."'":"null").", ";
+        $sql.= (! empty($this->email_to)?"'".$this->db->escape($this->email_to)."'":"null").", ";
+        $sql.= (! empty($this->email_tocc)?"'".$this->db->escape($this->email_tocc)."'":"null").", ";
+        $sql.= (! empty($this->email_tobcc)?"'".$this->db->escape($this->email_tobcc)."'":"null").", ";
+        $sql.= (! empty($this->email_subject)?"'".$this->db->escape($this->email_subject)."'":"null").", ";
+        $sql.= (! empty($this->errors_to)?"'".$this->db->escape($this->errors_to)."'":"null");
         $sql.= ")";
 
         dol_syslog(get_class($this)."::add", LOG_DEBUG);
@@ -1315,10 +1333,10 @@ class ActionComm extends CommonObject
 		$linkstart.=$linkclose.'>';
 		$linkend='</a>';
 
-                if ($option == 'nolink') {
-                    $linkstart = '';
-                    $linkend = '';
-                }
+		if ($option == 'nolink') {
+			$linkstart = '';
+			$linkend = '';
+		}
 		//print 'rrr'.$this->libelle.'rrr'.$this->label.'rrr'.$withpicto;
 
         if ($withpicto == 2)
@@ -1691,7 +1709,7 @@ class ActionComm extends CommonObject
     		$this->output = $langs->trans('EventRemindersByEmailNotEnabled', $langs->transnoentitiesnoconv("Agenda"));
     		return 0;
     	}
-		
+
     	$now = dol_now();
 
     	dol_syslog(__METHOD__, LOG_DEBUG);

+ 30 - 27
htdocs/comm/action/index.php

@@ -7,6 +7,7 @@
  * Copyright (C) 2014      Cedric GROSS         <c.gross@kreiz-it.fr>
  * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
  * Copyright (C) 2017      Open-DSI             <support@open-dsi.fr>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -44,9 +45,9 @@ if (! isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MA
 if (empty($conf->global->AGENDA_EXT_NB)) $conf->global->AGENDA_EXT_NB=5;
 $MAXAGENDA=$conf->global->AGENDA_EXT_NB;
 
-$filter = GETPOST("filter",'alpha',3);
-$filtert = GETPOST("filtert","int",3);
-$usergroup = GETPOST("usergroup","int",3);
+$filter = GETPOST("search_filter",'alpha',3)?GETPOST("search_filter",'alpha',3):GETPOST("filter",'alpha',3);
+$filtert = GETPOST("search_filtert","int",3)?GETPOST("search_filtert","int",3):GETPOST("filtert","int",3);
+$usergroup = GETPOST("search_usergroup","int",3)?GETPOST("search_usergroup","int",3):GETPOST("usergroup","int",3);
 $showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
 
 // If not choice done on calendar owner (like on left menu link "Agenda"), we filter on user.
@@ -65,7 +66,7 @@ if (! $sortorder) $sortorder="ASC";
 if (! $sortfield) $sortfield="a.datec";
 
 // Security check
-$socid = GETPOST("socid","int");
+$socid = GETPOST("search_socid","int")?GETPOST("search_socid","int"):GETPOST("socid","int");
 if ($user->societe_id) $socid=$user->societe_id;
 $result = restrictedArea($user, 'agenda', 0, '', 'myactions');
 if ($socid < 0) $socid='';
@@ -79,32 +80,32 @@ if (! $user->rights->agenda->allactions->read || $filter =='mine')  // If no per
 }
 
 $action=GETPOST('action','alpha');
-$resourceid=GETPOST("resourceid","int");
+$resourceid=GETPOST("search_resourceid","int");
 $year=GETPOST("year","int")?GETPOST("year","int"):date("Y");
 $month=GETPOST("month","int")?GETPOST("month","int"):date("m");
 $week=GETPOST("week","int")?GETPOST("week","int"):date("W");
 $day=GETPOST("day","int")?GETPOST("day","int"):date("d");
-$pid=GETPOST("projectid","int",3);
-$status=GETPOST("status",'aZ09');		// status may be 0, 50, 100, 'todo'
-$type=GETPOST("type",'az09');
+$pid=GETPOST("search_projectid","int",3)?GETPOST("search_projectid","int",3):GETPOST("projectid","int",3);
+$status=GETPOST("search_status",'aZ09')?GETPOST("search_status",'aZ09'):GETPOST("status",'aZ09');		// status may be 0, 50, 100, 'todo'
+$type=GETPOST("search_type",'az09')?GETPOST("search_type",'az09'):GETPOST("type",'az09');
 $maxprint=(isset($_GET["maxprint"])?GETPOST("maxprint"):$conf->global->AGENDA_MAX_EVENTS_DAY_VIEW);
 // Set actioncode (this code must be same for setting actioncode into peruser, listacton and index)
-if (GETPOST('actioncode','array'))
+if (GETPOST('search_actioncode','array'))
 {
-    $actioncode=GETPOST('actioncode','array',3);
+    $actioncode=GETPOST('search_actioncode','array',3);
     if (! count($actioncode)) $actioncode='0';
 }
 else
 {
-    $actioncode=GETPOST("actioncode","alpha",3)?GETPOST("actioncode","alpha",3):(GETPOST("actioncode")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
+    $actioncode=GETPOST("search_actioncode","alpha",3)?GETPOST("search_actioncode","alpha",3):(GETPOST("search_actioncode")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
 }
 if ($actioncode == '' && empty($actioncodearray)) $actioncode=(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE);
 
-if ($status == ''   && ! isset($_GET['status']) && ! isset($_POST['status'])) $status=(empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS)?'':$conf->global->AGENDA_DEFAULT_FILTER_STATUS);
+if ($status == '' && ! GETPOSTISSET('search_status')) $status=(empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS)?'':$conf->global->AGENDA_DEFAULT_FILTER_STATUS);
 
 $defaultview = (empty($conf->global->AGENDA_DEFAULT_VIEW) ? 'show_month' : $conf->global->AGENDA_DEFAULT_VIEW);
 $defaultview = (empty($user->conf->AGENDA_DEFAULT_VIEW) ? $defaultview : $user->conf->AGENDA_DEFAULT_VIEW);
-if (empty($action) && ! isset($_GET['action']) && ! isset($_POST['action'])) $action=$defaultview;
+if (empty($action) && ! GETPOSTISSET('action')) $action=$defaultview;
 if ($action == 'default')	// When action is default, we want a calendar view and not the list
 {
 	$action = (($defaultview != 'show_list') ? $defaultview : 'show_month');
@@ -301,21 +302,22 @@ if ($status == 'done') $title=$langs->trans("DoneActions");
 if ($status == 'todo') $title=$langs->trans("ToDoActions");
 
 $param='';
-if ($actioncode || isset($_GET['actioncode']) || isset($_POST['actioncode'])) {
+if ($actioncode || isset($_GET['search_actioncode']) || isset($_POST['search_actioncode'])) {
 	if(is_array($actioncode)) {
-		foreach($actioncode as $str_action) $param.="&actioncode[]=".$str_action;
-	} else $param.="&actioncode=".$actioncode;
+		foreach($actioncode as $str_action) $param.="&search_actioncode[]=".urlencode($str_action);
+	} else $param.="&search_actioncode=".urlencode($actioncode);
 }
-if ($resourceid > 0)  $param.="&resourceid=".$resourceid;
-if ($status || isset($_GET['status']) || isset($_POST['status'])) $param.="&status=".$status;
-if ($filter)  $param.="&filter=".$filter;
-if ($filtert) $param.="&filtert=".$filtert;
-if ($socid)   $param.="&socid=".$socid;
-if ($showbirthday) $param.="&showbirthday=1";
-if ($pid)     $param.="&projectid=".$pid;
-if ($type)   $param.="&type=".$type;
-if ($action == 'show_day' || $action == 'show_week' || $action == 'show_month') $param.='&action='.$action;
-$param.="&maxprint=".$maxprint;
+if ($resourceid > 0)  $param.="&search_resourceid=".urlencode($resourceid);
+if ($status || isset($_GET['status']) || isset($_POST['status'])) $param.="&search_status=".urlencode($status);
+if ($filter)       $param.="&search_filter=".urlencode($filter);
+if ($filtert)      $param.="&search_filtert=".urlencode($filtert);
+if ($usergroup)    $param.="&search_usergroup=".urlencode($usergroup);
+if ($socid)        $param.="&search_socid=".urlencode($socid);
+if ($showbirthday) $param.="&search_showbirthday=1";
+if ($pid)          $param.="&search_projectid=".urlencode($pid);
+if ($type)         $param.="&search_type=".urlencode($type);
+if ($action == 'show_day' || $action == 'show_week' || $action == 'show_month') $param.='&action='.urlencode($action);
+$param.="&maxprint=".urlencode($maxprint);
 
 // Show navigation bar
 if (empty($action) || $action=='show_month')
@@ -1278,7 +1280,7 @@ $db->close();
 function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventarray, $maxprint=0, $maxnbofchar=16, $newparam='', $showinfo=0, $minheight=60, $nonew=0)
 {
     global $user, $conf, $langs;
-    global $action, $filter, $filtert, $status, $actioncode;	// Filters used into search form
+    global $action, $filter, $filtert, $status, $actioncode, $usergroup;	// Filters used into search form
     global $theme_datacolor;
     global $cachethirdparties, $cachecontacts, $cacheusers, $colorindexused;
 
@@ -1637,6 +1639,7 @@ function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventa
                 	print '<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action='.$action.'&maxprint=0&month='.$monthshown.'&year='.$year;
                     print ($status?'&status='.$status:'').($filter?'&filter='.$filter:'');
                     print ($filtert?'&filtert='.$filtert:'');
+                    print ($usergroup?'&usergroup='.$usergroup:'');
                     print ($actioncode!=''?'&actioncode='.$actioncode:'');
                     print '">'.img_picto("all","1downarrow_selected.png").' ...';
                     print ' +'.(count($eventarray[$daykey])-$maxprint);

+ 51 - 34
htdocs/comm/action/list.php

@@ -41,23 +41,23 @@ $langs->loadLangs(array("users","companies","agenda","commercial"));
 
 $action=GETPOST('action','alpha');
 $contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'actioncommlist';   // To manage different context of search
-$resourceid=GETPOST("resourceid","int");
+$resourceid=GETPOST("search_resourceid","int")?GETPOST("search_resourceid","int"):GETPOST("resourceid","int");
+$pid=GETPOST("search_projectid",'int',3)?GETPOST("search_projectid",'int',3):GETPOST("projectid",'int',3);
+$status=GETPOST("search_status",'alpha')?GETPOST("search_status",'alpha'):GETPOST("status",'alpha');
+$type=GETPOST('search_type','alphanohtml')?GETPOST('search_type','alphanohtml'):GETPOST('type','alphanohtml');
+$optioncss = GETPOST('optioncss','alpha');
 $year=GETPOST("year",'int');
 $month=GETPOST("month",'int');
 $day=GETPOST("day",'int');
-$pid=GETPOST("projectid",'int',3);
-$status=GETPOST("status",'alpha');
-$type=GETPOST('type','alphanohtml');
-$optioncss = GETPOST('optioncss','alpha');
 // Set actioncode (this code must be same for setting actioncode into peruser, listacton and index)
-if (GETPOST('actioncode','array'))
+if (GETPOST('search_actioncode','array'))
 {
-    $actioncode=GETPOST('actioncode','array',3);
+    $actioncode=GETPOST('search_actioncode','array',3);
     if (! count($actioncode)) $actioncode='0';
 }
 else
 {
-    $actioncode=GETPOST("actioncode","alpha",3)?GETPOST("actioncode","alpha",3):(GETPOST("actioncode")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
+    $actioncode=GETPOST("search_actioncode","alpha",3)?GETPOST("search_actioncode","alpha",3):(GETPOST("search_actioncode")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
 }
 if ($actioncode == '' && empty($actioncodearray)) $actioncode=(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE);
 $search_id=GETPOST('search_id','alpha');
@@ -69,10 +69,10 @@ $dateend=dol_mktime(0, 0, 0, GETPOST('dateendmonth','int'), GETPOST('dateendday'
 if ($status == ''   && ! isset($_GET['status']) && ! isset($_POST['status'])) $status=(empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS)?'':$conf->global->AGENDA_DEFAULT_FILTER_STATUS);
 if (empty($action) && ! isset($_GET['action']) && ! isset($_POST['action'])) $action=(empty($conf->global->AGENDA_DEFAULT_VIEW)?'show_month':$conf->global->AGENDA_DEFAULT_VIEW);
 
-$filter = GETPOST("filter",'alpha',3);
-$filtert = GETPOST("filtert","int",3);
-$usergroup = GETPOST("usergroup","int",3);
-$showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
+$filter = GETPOST("search_filter",'alpha',3)?GETPOST("search_filter",'alpha',3):GETPOST("filter",'alpha',3);
+$filtert = GETPOST("search_filtert","int",3)?GETPOST("search_filtert","int",3):GETPOST("filtert","int",3);
+$usergroup = GETPOST("search_usergroup","int",3)?GETPOST("search_usergroup","int",3):GETPOST("usergroup","int",3);
+$showbirthday = empty($conf->use_javascript_ajax)?(GETPOST("search_showbirthday","int")?GETPOST("search_showbirthday","int"):GETPOST("showbirthday","int")):1;
 
 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
 $object = new ActionComm($db);
@@ -108,7 +108,7 @@ if (! $sortfield)
 }
 
 // Security check
-$socid = GETPOST("socid",'int');
+$socid = GETPOST("search_socid",'int')?GETPOST("search_socid",'int'):GETPOST("socid",'int');
 if ($user->societe_id) $socid=$user->societe_id;
 $result = restrictedArea($user, 'agenda', 0, '', 'myactions');
 if ($socid < 0) $socid='';
@@ -132,14 +132,15 @@ $arrayfields=array(
 	'a.fk_contact'=>array('label'=>"Contact", 'checked'=>1),
 	'a.fk_element'=>array('label'=>"LinkedObject", 'checked'=>0, 'enabled'=>(! empty($conf->global->AGENDA_SHOW_LINKED_OBJECT))),
 	'a.percent'=>array('label'=>"Status", 'checked'=>1, 'position'=>1000),
-
+	'a.datec'=>array('label'=>'DateCreation', 'checked'=>0),
+	'a.tms'=>array('label'=>'DateModification', 'checked'=>0)
 );
 // Extra fields
 if (is_array($extrafields->attribute_label) && count($extrafields->attribute_label))
 {
    foreach($extrafields->attribute_label as $key => $val)
    {
-		 $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>$extrafields->attribute_perms[$key]);
+		if (! empty($extrafields->attribute_list[$key])) $arrayfields["ef.".$key]=array('label'=>$extrafields->attribute_label[$key], 'checked'=>$extrafields->attribute_list[$key], 'position'=>$extrafields->attribute_pos[$key], 'enabled'=>$extrafields->attribute_perms[$key]);
    }
 }
 
@@ -207,19 +208,18 @@ if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&con
 if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
 if ($actioncode != '') {
 	if(is_array($actioncode)) {
-		foreach($actioncode as $str_action) $param.="&actioncode[]=".urlencode($str_action);
-	} else $param.="&actioncode=".urlencode($actioncode);
+		foreach($actioncode as $str_action) $param.="&search_actioncode[]=".urlencode($str_action);
+	} else $param.="&search_actioncode=".urlencode($actioncode);
 }
-if ($resourceid > 0) $param.="&resourceid=".urlencode($resourceid);
-if ($status != '' && $status > -1) $param.="&status=".urlencode($status);
-if ($filter) $param.="&filter=".urlencode($filter);
-if ($filtert) $param.="&filtert=".urlencode($filtert);
-if ($socid) $param.="&socid=".urlencode($socid);
-if ($showbirthday) $param.="&showbirthday=1";
-if ($pid) $param.="&projectid=".urlencode($pid);
-if ($type) $param.="&type=".urlencode($type);
-if ($usergroup) $param.="&usergroup=".urlencode($usergroup);
-if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
+if ($resourceid > 0) $param.="&search_resourceid=".urlencode($resourceid);
+if ($status != '' && $status > -1) $param.="&search_status=".urlencode($status);
+if ($filter) $param.="&search_filter=".urlencode($filter);
+if ($filtert) $param.="&search_filtert=".urlencode($filtert);
+if ($socid) $param.="&search_socid=".urlencode($socid);
+if ($showbirthday) $param.="&search_showbirthday=1";
+if ($pid) $param.="&search_projectid=".urlencode($pid);
+if ($type) $param.="&search_type=".urlencode($type);
+if ($usergroup) $param.="&search_usergroup=".urlencode($usergroup);
 if ($search_id != '') $param.='&search_title='.urlencode($search_id);
 if ($search_title != '') $param.='&search_title='.urlencode($search_title);
 if (GETPOST('datestartday','int')) $param.='&datestartday='.GETPOST('datestartday','int');
@@ -228,16 +228,17 @@ if (GETPOST('datestartyear','int')) $param.='&datestartyear='.GETPOST('datestart
 if (GETPOST('dateendday','int')) $param.='&dateendday='.GETPOST('dateendday','int');
 if (GETPOST('dateendmonth','int')) $param.='&dateendmonth='.GETPOST('dateendmonth','int');
 if (GETPOST('dateendyear','int')) $param.='&dateendyear='.GETPOST('dateendyear','int');
+if ($optioncss != '') $param.='&optioncss='.urlencode($optioncss);
 // Add $param from extra fields
 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
 
 $sql = "SELECT";
 if ($usergroup > 0) $sql.=" DISTINCT";
-$sql.= " s.nom as societe, s.rowid as socid, s.client,";
+$sql.= " s.nom as societe, s.rowid as socid, s.client, s.email as socemail,";
 $sql.= " a.id, a.label, a.datep as dp, a.datep2 as dp2,";
 $sql.= ' a.fk_user_author,a.fk_user_action,';
 $sql.= " a.fk_contact, a.note, a.percent as percent,";
-$sql.= " a.fk_element, a.elementtype,";
+$sql.= " a.fk_element, a.elementtype, a.datec, a.tms as datem,";
 $sql.= " c.code as type_code, c.libelle as type_label,";
 $sql.= " sp.lastname, sp.firstname, sp.email, sp.phone, sp.address, sp.phone as phone_pro, sp.phone_mobile, sp.phone_perso, sp.fk_pays as country_id";
 // Add fields from extrafields
@@ -364,10 +365,10 @@ if ($resql)
 
 	//if ($actioncode)    $nav.='<input type="hidden" name="actioncode" value="'.$actioncode.'">';
 	//if ($resourceid)      $nav.='<input type="hidden" name="resourceid" value="'.$resourceid.'">';
-	if ($filter)          $nav.='<input type="hidden" name="filter" value="'.$filter.'">';
+	if ($filter)          $nav.='<input type="hidden" name="search_filter" value="'.$filter.'">';
 	//if ($filtert)         $nav.='<input type="hidden" name="filtert" value="'.$filtert.'">';
 	//if ($socid)           $nav.='<input type="hidden" name="socid" value="'.$socid.'">';
-	if ($showbirthday)    $nav.='<input type="hidden" name="showbirthday" value="1">';
+	if ($showbirthday)    $nav.='<input type="hidden" name="search_showbirthday" value="1">';
 	//if ($pid)             $nav.='<input type="hidden" name="projectid" value="'.$pid.'">';
 	//if ($usergroup)       $nav.='<input type="hidden" name="usergroup" value="'.$usergroup.'">';
 	print $nav;
@@ -461,8 +462,9 @@ if ($resql)
 	$reshook=$hookmanager->executeHooks('printFieldListOption',$parameters);    // Note that $action and $object may have been modified by hook
 	print $hookmanager->resPrint;
 
-
-    if (! empty($arrayfields['a.percent']['checked']))	{
+	if (! empty($arrayfields['a.datec']['checked']))	print '<td class="liste_titre"></td>';
+	if (! empty($arrayfields['a.tms']['checked']))		print '<td class="liste_titre"></td>';
+	if (! empty($arrayfields['a.percent']['checked']))	{
 		print '<td class="liste_titre center">';
     	print $formactions->form_select_status_action('formaction',$status,1,'status',1,2);
     	print ajax_combobox('selectstatus');
@@ -494,6 +496,10 @@ if ($resql)
 	$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['a.datec']['checked'])) print_liste_field_titre($arrayfields['a.datec']['label'], $_SERVER["PHP_SELF"],"a.datec,a.id",$param,"",'align="center"',$sortfield,$sortorder);
+	if (! empty($arrayfields['a.tms']['checked'])) print_liste_field_titre($arrayfields['a.tms']['label'], $_SERVER["PHP_SELF"],"a.tms,a.id",$param,"",'align="center"',$sortfield,$sortorder);
+
 	if (! empty($arrayfields['a.percent']['checked']))print_liste_field_titre("Status",$_SERVER["PHP_SELF"],"a.percent",$param,"",'align="center"',$sortfield,$sortorder);
 	print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"],"",'','','align="center"',$sortfield,$sortorder,'maxwidthsearch ');
 	print "</tr>\n";
@@ -599,11 +605,13 @@ if ($resql)
 		// Third party
 		if (! empty($arrayfields['s.nom']['checked'])) {
 			print '<td class="tdoverflowmax100">';
-			if ($obj->socid)
+			if ($obj->socid > 0)
 			{
 				$societestatic->id=$obj->socid;
 				$societestatic->client=$obj->client;
 				$societestatic->name=$obj->societe;
+				$societestatic->email=$obj->socemail;
+
 				print $societestatic->getNomUrl(1,'',28);
 			}
 			else print '&nbsp;';
@@ -652,6 +660,15 @@ if ($resql)
 		$reshook=$hookmanager->executeHooks('printFieldListValue',$parameters);    // Note that $action and $object may have been modified by hook
 		print $hookmanager->resPrint;
 
+		// Date creation
+		if (! empty($arrayfields['a.datec']['checked'])) {
+			// Status/Percent
+			print '<td align="center" class="nowrap">'.dol_print_date($obj->datec, 'dayhour').'</td>';
+		}
+		// Date update
+		if (! empty($arrayfields['a.tms']['checked'])) {
+			print '<td align="center" class="nowrap">'.dol_print_date($obj->datem, 'dayhour').'</td>';
+		}
 		if (! empty($arrayfields['a.percent']['checked'])) {
 			// Status/Percent
 			$datep=$db->jdate($obj->datep);

+ 40 - 26
htdocs/comm/action/peruser.php

@@ -41,9 +41,9 @@ require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
 
 if (! isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW=3;
 
-$filter = GETPOST("filter",'alpha',3);
-$filtert = GETPOST("filtert","int",3);
-$usergroup = GETPOST("usergroup","int",3);
+$filter = GETPOST("search_filter",'alpha',3)?GETPOST("search_filter",'alpha',3):GETPOST("filter",'alpha',3);
+$filtert = GETPOST("search_filtert","int",3)?GETPOST("search_filtert","int",3):GETPOST("filtert","int",3);
+$usergroup = GETPOST("search_usergroup","int",3)?GETPOST("search_usergroup","int",3):GETPOST("usergroup","int",3);
 //if (! ($usergroup > 0) && ! ($filtert > 0)) $filtert = $user->id;
 //$showbirthday = empty($conf->use_javascript_ajax)?GETPOST("showbirthday","int"):1;
 $showbirthday = 0;
@@ -64,7 +64,7 @@ if (! $sortorder) $sortorder="ASC";
 if (! $sortfield) $sortfield="a.datec";
 
 // Security check
-$socid = GETPOST("socid","int");
+$socid = GETPOST("search_socid","int")?GETPOST("search_socid","int"):GETPOST("socid","int");
 if ($user->societe_id) $socid=$user->societe_id;
 $result = restrictedArea($user, 'agenda', 0, '', 'myactions');
 if ($socid < 0) $socid='';
@@ -79,24 +79,24 @@ if (! $user->rights->agenda->allactions->read || $filter =='mine')  // If no per
 
 //$action=GETPOST('action','alpha');
 $action='show_peruser'; //We use 'show_week' mode
-$resourceid=GETPOST("resourceid","int");
+$resourceid=GETPOST("search_resourceid","int")?GETPOST("search_resourceid","int"):GETPOST("resourceid","int");
 $year=GETPOST("year","int")?GETPOST("year","int"):date("Y");
 $month=GETPOST("month","int")?GETPOST("month","int"):date("m");
 $week=GETPOST("week","int")?GETPOST("week","int"):date("W");
 $day=GETPOST("day","int")?GETPOST("day","int"):date("d");
-$pid=GETPOST("projectid","int",3);
-$status=GETPOST("status",'alpha');
-$type=GETPOST("type",'alpha');
+$pid=GETPOST("search_projectid","int",3)?GETPOST("search_projectid","int",3):GETPOST("projectid","int",3);
+$status=GETPOST("search_status",'alpha')?GETPOST("search_status",'alpha'):GETPOST("status",'alpha');
+$type=GETPOST("search_type",'alpha')?GETPOST("search_type",'alpha'):GETPOST("type",'alpha');
 $maxprint=((GETPOST("maxprint",'int')!='')?GETPOST("maxprint",'int'):$conf->global->AGENDA_MAX_EVENTS_DAY_VIEW);
 // Set actioncode (this code must be same for setting actioncode into peruser, listacton and index)
-if (GETPOST('actioncode','array'))
+if (GETPOST('search_actioncode','array'))
 {
-    $actioncode=GETPOST('actioncode','array',3);
+    $actioncode=GETPOST('search_actioncode','array',3);
     if (! count($actioncode)) $actioncode='0';
 }
 else
 {
-    $actioncode=GETPOST("actioncode","alpha",3)?GETPOST("actioncode","alpha",3):(GETPOST("actioncode","alpha")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
+    $actioncode=GETPOST("search_actioncode","alpha",3)?GETPOST("search_actioncode","alpha",3):(GETPOST("search_actioncode","alpha")=='0'?'0':(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE));
 }
 if ($actioncode == '' && empty($actioncodearray)) $actioncode=(empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE)?'':$conf->global->AGENDA_DEFAULT_FILTER_TYPE);
 
@@ -201,25 +201,25 @@ if ($status == 'done') $title=$langs->trans("DoneActions");
 if ($status == 'todo') $title=$langs->trans("ToDoActions");
 
 $param='';
-if ($actioncode || isset($_GET['actioncode']) || isset($_POST['actioncode'])) {
+if ($actioncode || isset($_GET['search_actioncode']) || isset($_POST['search_actioncode'])) {
 	if(is_array($actioncode)) {
-		foreach($actioncode as $str_action) $param.="&actioncode[]=".urlencode($str_action);
-	} else $param.="&actioncode=".urlencode($actioncode);
+		foreach($actioncode as $str_action) $param.="&search_actioncode[]=".urlencode($str_action);
+	} else $param.="&search_actioncode=".urlencode($actioncode);
 }
-if ($resourceid > 0) $param.="&resourceid=".urlencode($resourceid);
-if ($status || isset($_GET['status']) || isset($_POST['status'])) $param.="&status=".urlencode($status);
-if ($filter)  $param.="&filter=".urlencode($filter);
-if ($filtert) $param.="&filtert=".urlencode($filtert);
-if ($usergroup) $param.="&usergroup=".urlencode($usergroup);
-if ($socid)   $param.="&socid=".urlencode($socid);
-if ($showbirthday) $param.="&showbirthday=1";
-if ($pid)     $param.="&projectid=".urlencode($pid);
-if ($type)   $param.="&type=".urlencode($type);
+if ($resourceid > 0) $param.="&search_resourceid=".urlencode($resourceid);
+if ($status || isset($_GET['status']) || isset($_POST['status'])) $param.="&search_status=".urlencode($status);
+if ($filter)        $param.="&search_filter=".urlencode($filter);
+if ($filtert)       $param.="&search_filtert=".urlencode($filtert);
+if ($usergroup)     $param.="&search_usergroup=".urlencode($usergroup);
+if ($socid)         $param.="&search_socid=".urlencode($socid);
+if ($showbirthday)  $param.="&search_showbirthday=1";
+if ($pid)           $param.="&search_projectid=".urlencode($pid);
+if ($type)          $param.="&search_type=".urlencode($type);
 if ($action == 'show_day' || $action == 'show_week' || $action == 'show_month' || $action != 'show_peruser') $param.='&action='.urlencode($action);
 if ($begin_h != '') $param.='&begin_h='.urlencode($begin_h);
-if ($end_h != '') $param.='&end_h='.urlencode($end_h);
+if ($end_h != '')   $param.='&end_h='.urlencode($end_h);
 if ($begin_d != '') $param.='&begin_d='.urlencode($begin_d);
-if ($end_d != '') $param.='&end_d='.urlencode($end_d);
+if ($end_d != '')   $param.='&end_d='.urlencode($end_d);
 $param.="&maxprint=".urlencode($maxprint);
 
 
@@ -358,9 +358,23 @@ if ($conf->use_javascript_ajax)
 }
 
 
+$newcardbutton='';
+if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
+{
+	$tmpforcreatebutton=dol_getdate(dol_now(), true);
+
+	$newparam.='&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$tmpforcreatebutton['year'];
+
+	//$param='month='.$monthshown.'&year='.$year;
+	$hourminsec='100000';
+	$newcardbutton = '<a class="butActionNew" href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.sprintf("%04d%02d%02d",$tmpforcreatebutton['year'],$tmpforcreatebutton['mon'],$tmpforcreatebutton['mday']).$hourminsec.'&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam?'?'.$newparam:'')).'"><span class="valignmiddle">'.$langs->trans("AddAction").'</span>';
+	$newcardbutton.= '<span class="fa fa-plus-circle valignmiddle"></span>';
+	$newcardbutton.= '</a>';
+}
 
 $link='';
-print load_fiche_titre($s, $link.' &nbsp; &nbsp; '.$nav, '');
+print load_fiche_titre($s, $link.' &nbsp; &nbsp; '.$nav.' '.$newcardbutton, '');
+
 
 
 // Get event in an array

+ 1 - 1
htdocs/comm/card.php

@@ -346,7 +346,7 @@ if ($object->id > 0)
 	print '</td><td>';
 	if ($action == 'editmode')
 	{
-		$form->form_modes_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id,$object->mode_reglement_id,'mode_reglement_id');
+		$form->form_modes_reglement($_SERVER['PHP_SELF'].'?socid='.$object->id,$object->mode_reglement_id,'mode_reglement_id', 'CRDT');
 	}
 	else
 	{

+ 1 - 1
htdocs/comm/propal/card.php

@@ -2105,7 +2105,7 @@ if ($action == 'create')
 	print '</tr></table>';
 	print '</td><td>';
 	if (! empty($object->brouillon) && $action == 'editmode' && $usercancreate) {
-		$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'mode_reglement_id');
+		$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT');
 	} else {
 		$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'none');
 	}

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

@@ -2432,7 +2432,7 @@ class Propal extends CommonObject
 	 *  @param		int		$notrigger	1=Does not execute triggers, 0=Execute triggers
 	 *	@return     int         		<0 if KO, >0 if OK
 	 */
-	function cloture($user, $statut, $note, $notrigger=0)
+	function cloture($user, $statut, $note="", $notrigger=0)
 	{
 		global $langs,$conf;
 

+ 16 - 6
htdocs/comm/propal/list.php

@@ -11,7 +11,7 @@
  * 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      Charlene Benke	 <charlie@patas-monkey.com>
+ * Copyright (C) 2017-2018 Charlene Benke	 <charlie@patas-monkey.com>
  * Copyright (C) 2018	   Nicolas ZABOURI	 <info@inovea-conseil.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -175,9 +175,6 @@ if (is_array($extrafields->attribute_label) && count($extrafields->attribute_lab
 	}
 }
 
-$object = new Propal($db);	// To be passed as parameter of executeHooks that need
-
-
 /*
  * Actions
  */
@@ -258,7 +255,7 @@ $projectstatic=new Project($db);
 $formcompany=new FormCompany($db);
 
 $help_url='EN:Commercial_Proposals|FR:Proposition_commerciale|ES:Presupuestos';
-llxHeader('',$langs->trans('Proposal'),$help_url);
+//llxHeader('',$langs->trans('Proposal'),$help_url);
 
 $sql = 'SELECT';
 if ($sall || $search_product_category > 0) $sql = 'SELECT DISTINCT';
@@ -404,6 +401,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 $sql.= $db->plimit($limit+1, $offset);
 
 $resql=$db->query($sql);
+
 if ($resql)
 {
 	$objectstatic=new Propal($db);
@@ -425,6 +423,18 @@ if ($resql)
 
 	$arrayofselected=is_array($toselect)?$toselect:array();
 
+	if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
+	{
+		$obj = $db->fetch_object($resql);
+
+		$id = $obj->rowid;
+
+		header("Location: ".DOL_URL_ROOT.'/comm/propal/card.php?id='.$id);
+		exit;
+	}
+
+	llxHeader('',$langs->trans('Proposal'),$help_url);
+
 	$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);
@@ -456,7 +466,7 @@ if ($resql)
 		'builddoc'=>$langs->trans("PDFMerge"),
 	);
 	if ($user->rights->propal->supprimer) $arrayofmassactions['predelete']=$langs->trans("Delete");
-	if ($user->rights->propal->cloturer) $arrayofmassactions['closed']=$langs->trans("Closed");
+	if ($user->rights->propal->cloturer) $arrayofmassactions['closed']=$langs->trans("Close");
 	if (in_array($massaction, array('presend','predelete','closed'))) $arrayofmassactions=array();
 	$massactionbutton=$form->selectMassAction('', $arrayofmassactions);
 

+ 1 - 1
htdocs/commande/card.php

@@ -2191,7 +2191,7 @@ if ($action == 'create' && $user->rights->commande->creer)
 		print '</tr></table>';
 		print '</td><td>';
 		if ($action == 'editmode') {
-			$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'mode_reglement_id');
+			$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'mode_reglement_id', 'CRDT');
 		} else {
 			$form->form_modes_reglement($_SERVER['PHP_SELF'] . '?id=' . $object->id, $object->mode_reglement_id, 'none');
 		}

+ 15 - 3
htdocs/commande/list.php

@@ -74,6 +74,7 @@ $socid=GETPOST('socid','int');
 $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_categ_cus=trim(GETPOST("search_categ_cus",'int'));
 $optioncss = GETPOST('optioncss','alpha');
 $billed = GETPOST('billed','int');
@@ -232,7 +233,7 @@ $projectstatic=new Project($db);
 
 $title=$langs->trans("Orders");
 $help_url="EN:Module_Customers_Orders|FR:Module_Commandes_Clients|ES:Módulo_Pedidos_de_clientes";
-llxHeader('',$title,$help_url);
+// llxHeader('',$title,$help_url);
 
 $sql = 'SELECT';
 if ($sall || $search_product_category > 0) $sql = 'SELECT DISTINCT';
@@ -335,6 +336,7 @@ 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_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";
@@ -399,6 +401,16 @@ if ($resql)
 
 	$arrayofselected=is_array($toselect)?$toselect:array();
 
+	if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
+	{
+		$obj = $db->fetch_object($resql);
+		$id = $obj->rowid;
+		header("Location: ".DOL_URL_ROOT.'/commande/card.php?id='.$id);
+		exit;
+	}
+
+	llxHeader('',$title,$help_url);
+
 	$param='';
 
 	if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
@@ -467,8 +479,8 @@ if ($resql)
 	print '<input type="hidden" name="contextpage" value="'.$contextpage.'">';
 	print '<input type="hidden" name="viewstatut" value="'.$viewstatut.'">';
 	print '<input type="hidden" name="socid" value="'.$socid.'">';
-	
-	
+
+
 	print_barre_liste($title, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_commercial.png', 0, $newcardbutton, '', $limit);
 
 	$topicmail="SendOrderRef";

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

@@ -550,7 +550,7 @@ foreach ($accounts as $key=>$type)
     // Balance
     if (! empty($arrayfields['balance']['checked']))
     {
-		print '<td align="right">';
+		print '<td align="right" class="nowraponall">';
 		print '<a href="'.DOL_URL_ROOT.'/compta/bank/bankentries_list.php?id='.$obj->id.'">'.price($solde, 0, $langs, 0, -1, -1, $obj->currency_code).'</a>';
 		print '</td>';
 		if (! $i) $totalarray['nbfield']++;

+ 13 - 2
htdocs/compta/facture/list.php

@@ -354,7 +354,7 @@ $facturestatic=new Facture($db);
 $formcompany=new FormCompany($db);
 $thirdpartystatic=new Societe($db);
 
-llxHeader('',$langs->trans('CustomersInvoices'),'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes');
+// llxHeader('',$langs->trans('CustomersInvoices'),'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes');
 
 $sql = 'SELECT';
 if ($sall || $search_product_category > 0) $sql = 'SELECT DISTINCT';
@@ -532,15 +532,26 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST))
 }
 
 $sql.= $db->plimit($limit+1,$offset);
-//print $sql;
 
 $resql = $db->query($sql);
+
 if ($resql)
 {
 	$num = $db->num_rows($resql);
 
 	$arrayofselected=is_array($toselect)?$toselect:array();
 
+	if ($num == 1 && ! empty($conf->global->MAIN_SEARCH_DIRECT_OPEN_IF_ONLY_ONE) && $sall)
+	{
+		$obj = $db->fetch_object($resql);
+		$id = $obj->id;
+
+		header("Location: ".DOL_URL_ROOT.'/compta/facture/card.php?facid='.$id);
+		exit;
+	}
+
+	llxHeader('',$langs->trans('CustomersInvoices'),'EN:Customers_Invoices|FR:Factures_Clients|ES:Facturas_a_clientes');
+
 	if ($socid)
 	{
 		$soc = new Societe($db);

+ 1 - 1
htdocs/compta/localtax/quadri_detail.php

@@ -589,7 +589,7 @@ else
 
 						// Localtax
 						print '<td class="nowrap" align="right">';
-						$temp_vat=($local==1?$fields['localtax1']:$fields['localtax2'])*$ratiopaymentinvoice;;
+						$temp_vat=($local==1?$fields['localtax1']:$fields['localtax2'])*$ratiopaymentinvoice;
 						print price(price2num($temp_vat,'MT'),1);
 						//print price($fields['vat']);
 						print '</td>';

+ 15 - 12
htdocs/compta/paiement.php

@@ -579,11 +579,13 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
                 print '<td>'.$arraytitle.'</td>';
                 print '<td align="center">'.$langs->trans('Date').'</td>';
                 print '<td align="center">'.$langs->trans('DateMaxPayment').'</td>';
-                if (!empty($conf->multicurrency->enabled)) print '<td>'.$langs->trans('Currency').'</td>';
-                if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('MulticurrencyAmountTTC').'</td>';
-                if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$multicurrencyalreadypayedlabel.'</td>';
-                if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$multicurrencyremaindertopay.'</td>';
-                if (!empty($conf->multicurrency->enabled)) print '<td align="right">'.$langs->trans('MulticurrencyPaymentAmount').'</td>';
+                if (!empty($conf->multicurrency->enabled)) {
+                	print '<td>'.$langs->trans('Currency').'</td>';
+                	print '<td align="right">'.$langs->trans('MulticurrencyAmountTTC').'</td>';
+                	print '<td align="right">'.$multicurrencyalreadypayedlabel.'</td>';
+                	print '<td align="right">'.$multicurrencyremaindertopay.'</td>';
+                	print '<td align="right">'.$langs->trans('MulticurrencyPaymentAmount').'</td>';
+                }
                 print '<td align="right">'.$langs->trans('AmountTTC').'</td>';
                 print '<td align="right">'.$alreadypayedlabel.'</td>';
                 print '<td align="right">'.$remaindertopay.'</td>';
@@ -612,8 +614,7 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
                     $remaintopay=price2num($invoice->total_ttc - $paiement - $creditnotes - $deposits,'MT');
 
 					// Multicurrency Price
-					if (!empty($conf->multicurrency->enabled))
-					{
+					if (!empty($conf->multicurrency->enabled)) {
 						$multicurrency_payment = $invoice->getSommePaiement(1);
 						$multicurrency_creditnotes=$invoice->getSumCreditNotesUsed(1);
 						$multicurrency_deposits=$invoice->getSumDepositsUsed(1);
@@ -760,11 +761,13 @@ if ($action == 'create' || $action == 'confirm_paiement' || $action == 'add_paie
                     // Print total
                     print '<tr class="liste_total">';
                     print '<td colspan="2" align="left">'.$langs->trans('TotalTTC').'</td>';
-					if (!empty($conf->multicurrency->enabled)) print '<td></td>';
-					if (!empty($conf->multicurrency->enabled)) print '<td></td>';
-					if (!empty($conf->multicurrency->enabled)) print '<td></td>';
-					if (!empty($conf->multicurrency->enabled)) print '<td></td>';
-					if (!empty($conf->multicurrency->enabled)) print '<td align="right" id="multicurrency_result" style="font-weight: bold;"></td>';
+                    if (!empty($conf->multicurrency->enabled)) {
+                    	print '<td></td>';
+                    	print '<td></td>';
+                    	print '<td></td>';
+                    	print '<td></td>';
+                    	print '<td align="right" id="multicurrency_result" style="font-weight: bold;"></td>';
+                    }
 					print '<td align="right"><b>'.price($sign * $total_ttc).'</b></td>';
                     print '<td align="right"><b>'.price($sign * $totalrecu);
                     if ($totalrecucreditnote) print '+'.price($totalrecucreditnote);

+ 5 - 9
htdocs/compta/paiement/card.php

@@ -107,7 +107,7 @@ if ($action == 'confirm_valide' && $confirm == 'yes' && $user->rights->facture->
 	$db->begin();
 
     $object->fetch($id);
-	if ($object->valide() > 0)
+	if ($object->valide($user) > 0)
 	{
 		$db->commit();
 
@@ -157,7 +157,7 @@ if ($action == 'setnum_paiement' && ! empty($_POST['num_paiement']))
 if ($action == 'setdatep' && ! empty($_POST['datepday']))
 {
 	$object->fetch($id);
-    $datepaye = dol_mktime(12, 0, 0, $_POST['datepmonth'], $_POST['datepday'], $_POST['datepyear']);
+	$datepaye = dol_mktime(GETPOST('datephour','int'), GETPOST('datepmin','int'), GETPOST('datepsec','int'), GETPOST('datepmonth','int'), GETPOST('datepday','int'), GETPOST('datepyear','int'));
 	$res = $object->update_date($datepaye);
 	if ($res === 0)
 	{
@@ -191,17 +191,13 @@ $head = payment_prepare_head($object);
 
 dol_fiche_head($head, 'payment', $langs->trans("PaymentCustomerInvoice"), -1, 'payment');
 
-/*
- * Confirmation de la suppression du paiement
- */
+// Confirmation de la suppression du paiement
 if ($action == 'delete')
 {
 	print $form->formconfirm($_SERVER['PHP_SELF'].'?id='.$object->id, $langs->trans("DeletePayment"), $langs->trans("ConfirmDeletePayment"), 'confirm_delete','',0,2);
 }
 
-/*
- * Confirmation de la validation du paiement
- */
+// Confirmation de la validation du paiement
 if ($action == 'valide')
 {
 	$facid = $_GET['facid'];
@@ -220,7 +216,7 @@ print '<table class="border centpercent">'."\n";
 
 // Date payment
 print '<tr><td class="titlefield">'.$form->editfieldkey("Date",'datep',$object->date,$object,$user->rights->facture->paiement).'</td><td>';
-print $form->editfieldval("Date",'datep',$object->date,$object,$user->rights->facture->paiement,'datepicker','',null,$langs->trans('PaymentDateUpdateSucceeded'));
+print $form->editfieldval("Date", 'datep', $object->date, $object,$user->rights->facture->paiement, 'datehourpicker', '', null, $langs->trans('PaymentDateUpdateSucceeded'));
 print '</td></tr>';
 
 // Payment type (VIR, LIQ, ...)

+ 6 - 4
htdocs/compta/paiement/class/paiement.class.php

@@ -862,9 +862,10 @@ class Paiement extends CommonObject
 	/**
 	 *    Validate payment
 	 *
-	 *    @return     int     <0 if KO, >0 if OK
+	 *	  @param	User	$user		User making validation
+	 *    @return   int     			<0 if KO, >0 if OK
 	 */
-	function valide()
+	function valide(User $user=null)
 	{
 		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET statut = 1 WHERE rowid = '.$this->id;
 
@@ -885,9 +886,10 @@ class Paiement extends CommonObject
 	/**
 	 *    Reject payment
 	 *
-	 *    @return     int     <0 if KO, >0 if OK
+	 *	  @param	User	$user		User making reject
+	 *    @return   int     			<0 if KO, >0 if OK
 	 */
-	function reject()
+	function reject(User $user=null)
 	{
 		$sql = 'UPDATE '.MAIN_DB_PREFIX.$this->table_element.' SET statut = 2 WHERE rowid = '.$this->id;
 

+ 15 - 8
htdocs/compta/paiement/list.php

@@ -36,7 +36,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php';
 
 // Load translation files required by the page
-$langs->loadLangs(array('bills', 'compta'));
+$langs->loadLangs(array('bills', 'compta', 'companies'));
 
 // Security check
 $facid	= GETPOST('facid','int');
@@ -75,6 +75,8 @@ if (! $sortfield) $sortfield="p.rowid";
 $hookmanager->initHooks(array('paymentlist'));
 $extrafields = new ExtraFields($db);
 
+$arrayfields=array();
+
 
 /*
  * Actions
@@ -131,7 +133,7 @@ else
     $sql.= " p.statut, p.num_paiement,";
     $sql.= " c.code as paiement_code,";
     $sql.= " ba.rowid as bid, ba.ref as bref, ba.label as blabel, ba.number, ba.account_number as account_number, ba.fk_accountancy_journal as accountancy_journal,";
-    $sql.= " s.rowid as socid, s.nom as name";
+    $sql.= " s.rowid as socid, s.nom as name, s.email";
 	// Add fields for extrafields
 	foreach ($extrafields->attribute_list as $key => $val) $sql.=",ef.".$key.' as options_'.$key;
 	// Add fields from hooks
@@ -209,8 +211,8 @@ if ($resql)
     $i = 0;
 
     $param='';
-    if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
-    if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
+    if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage);
+    if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit);
     $param.=(GETPOST("orphelins")?"&orphelins=1":"");
     $param.=($search_ref?"&search_ref=".urlencode($search_ref):"");
     $param.=($search_company?"&search_company=".urlencode($search_company):"");
@@ -296,23 +298,28 @@ if ($resql)
     {
         $objp = $db->fetch_object($resql);
 
+        $paymentstatic->id=$objp->rowid;
+        $paymentstatic->ref=$objp->ref;
+
         print '<tr class="oddeven">';
 
         print '<td>';
-        $paymentstatic->id=$objp->rowid;
-        $paymentstatic->ref=$objp->ref;
         print $paymentstatic->getNomUrl(1);
         print '</td>';
 
         // Date
-        print '<td align="center">'.dol_print_date($db->jdate($objp->dp),'day').'</td>';
+        $dateformatforpayment = 'day';
+        if (! empty($conf->global->INVOICE_USE_HOURS_FOR_PAYMENT)) $dateformatforpayment='dayhour';
+        print '<td align="center">'.dol_print_date($db->jdate($objp->dp), $dateformatforpayment).'</td>';
 
         // Thirdparty
         print '<td>';
-        if ($objp->socid)
+        if ($objp->socid > 0)
         {
             $companystatic->id=$objp->socid;
             $companystatic->name=$objp->name;
+            $companystatic->email=$objp->email;
+
             print $companystatic->getNomUrl(1,'',24);
         }
         else print '&nbsp;';

+ 1 - 1
htdocs/compta/resultat/clientfourn.php

@@ -303,7 +303,7 @@ if ($modecompta == 'BOOKKEEPING')
 
 					foreach($cpts as $i => $cpt)
 					{
-						$return = $AccCat->getResult($cpt['account_number'], 0, $date_start, $date_end, $cpt['dc']);
+						$return = $AccCat->getSumDebitCredit($cpt['account_number'], $date_start, $date_end, $cpt['dc']);
 						if ($return < 0) {
 							setEventMessages(null, $AccCat->errors, 'errors');
 							$resultN=0;

+ 73 - 56
htdocs/compta/resultat/result.php

@@ -78,7 +78,7 @@ if (empty($date_start) || empty($date_end)) // We define date_start and date_end
 	{
 		// We define date_start and date_end
 		$year_end=$year_start + ($nbofyear - 1);
-		$month_start=GETPOST("month")?GETPOST("month"):($conf->global->SOCIETE_FISCAL_MONTH_START?($conf->global->SOCIETE_FISCAL_MONTH_START):1);
+		$month_start=GETPOST("month",'int')?GETPOST("month",'int'):($conf->global->SOCIETE_FISCAL_MONTH_START?($conf->global->SOCIETE_FISCAL_MONTH_START):1);
 		$date_startmonth = $month_start;
 		if (! GETPOST('month'))
 		{
@@ -108,8 +108,10 @@ if (($date_start < dol_time_plus_duree($date_end, -1, 'y')) || ($date_start > $d
 // $date_start and $date_end are defined. We force $start_year and $nbofyear
 $tmps=dol_getdate($date_start);
 $start_year = $tmps['year'];
+$start_month = $tmps['mon'];
 $tmpe=dol_getdate($date_end);
 $year_end = $tmpe['year'];
+$month_end = $tmpe['mon'];
 $nbofyear = ($year_end - $start_year) + 1;
 
 $date_start_previous = dol_time_plus_duree($date_start, -1, 'y');
@@ -231,13 +233,13 @@ print '<th class="liste_titre" align="right">'.$langs->trans("SelectedPeriod").'
 foreach($months as $k => $v){
 	if (($k+1) >= $date_startmonth)
 	{
-		print '<th class="liste_titre width50" align="right" >'.$langs->trans($v).'</th>';
+		print '<th class="liste_titre width50" align="right" >'.$langs->trans('MonthShort'.sprintf("%02s",($k+1))).'</th>';
 	}
 }
 foreach($months as $k => $v){
 	if (($k+1) < $date_startmonth)
 	{
-		print '<th class="liste_titre width50" align="right" >'.$langs->trans($v).'</th>';
+		print '<th class="liste_titre width50" align="right" >'.$langs->trans('MonthShort'.sprintf("%02s",($k+1))).'</th>';
 	}
 }
 print	'</tr>';
@@ -374,13 +376,14 @@ elseif ($modecompta=="BOOKKEEPING")
 				}
 			}
 
-
 			print "</tr>\n";
 
 			//var_dump($sommes);
 		}
 		else			// normal category
 		{
+			$code = $cat['code'];	// Category code we process
+
 			$totCat = array();
 			$totCat['NP'] = 0;
 			$totCat['N'] = 0;
@@ -390,9 +393,73 @@ elseif ($modecompta=="BOOKKEEPING")
 				$totCat['M'][$k] = 0;
 			}
 
-			// Set $cpts of with array of accounts in the category/group
+			// Set $cpts with array of accounts in the category/group
 			$cpts = $AccCat->getCptsCat($cat['rowid']);
 
+			$arrayofaccountforfilter=array();
+			foreach($cpts as $i => $cpt)	// Loop on each account.
+			{
+				$arrayofaccountforfilter[]=$cpt['account_number'];
+			}
+
+			// N-1
+			if (! empty($arrayofaccountforfilter))
+			{
+				$return = $AccCat->getSumDebitCredit($arrayofaccountforfilter, $date_start_previous, $date_end_previous, $cpt['dc']?$cpt['dc']:0);
+
+				if ($return < 0) {
+					setEventMessages(null, $AccCat->errors, 'errors');
+					$resultNP=0;
+				} else {
+					foreach($cpts as $i => $cpt)	// Loop on each account.
+					{
+						$resultNP = empty($AccCat->sdcperaccount[$cpt['account_number']])?0:$AccCat->sdcperaccount[$cpt['account_number']];
+
+						$totCat['NP'] += $resultNP;
+						$sommes[$code]['NP'] += $resultNP;
+						$totPerAccount[$cpt['account_number']]['NP'] = $resultNP;
+					}
+				}
+			}
+
+			// Set value into column N and month M ($totCat)
+			// This make 12 calls for each accountancy account (12 monthes M)
+			foreach($cpts as $i => $cpt)	// Loop on each account.
+			{
+				// We make 1 loop for each account because we may want detail per account.
+				// @TODO Optimize to ask a 'group by' account and a filter with account in (..., ...) in request
+
+				// Each month
+				$resultN = 0;
+				foreach($months as $k => $v)
+				{
+					$monthtoprocess = $k+1;			// ($k+1) is month 1, 2, ..., 12
+					$yeartoprocess = $start_year;
+					if (($k+1) < $start_month) $yeartoprocess++;
+
+					//var_dump($monthtoprocess.'_'.$yeartoprocess);
+					$return = $AccCat->getSumDebitCredit($cpt['account_number'], $date_start, $date_end, $cpt['dc']?$cpt['dc']:0, 'nofilter', $monthtoprocess, $yeartoprocess);
+					if ($return < 0) {
+						setEventMessages(null, $AccCat->errors, 'errors');
+						$resultM=0;
+					} else {
+						$resultM=$AccCat->sdc;
+					}
+					$totCat['M'][$k] += $resultM;
+					$sommes[$code]['M'][$k] += $resultM;
+					$totPerAccount[$cpt['account_number']]['M'][$k] = $resultM;
+
+					$resultN += $resultM;
+				}
+
+				$totCat['N'] += $resultN;
+				$sommes[$code]['N'] += $resultN;
+				$totPerAccount[$cpt['account_number']]['N'] = $resultN;
+			}
+
+
+			// Now output columns for row $code ('VTE', 'MAR', ...)
+
 			print "<tr>";
 
 			// Column group
@@ -426,54 +493,6 @@ elseif ($modecompta=="BOOKKEEPING")
 			}
 			print '</td>';
 
-			$code = $cat['code'];
-
-			// Set value into column NPrevious, N and each month M ($totCat)
-			// This make 14 calls for each detail of account (NP, N and month m)
-			foreach($cpts as $i => $cpt)
-			{
-				// N-1
-				$return = $AccCat->getResult($cpt['account_number'], 0, $date_start_previous, $date_end_previous, $cpt['dc']);
-
-				if ($return < 0) {
-					setEventMessages(null, $AccCat->errors, 'errors');
-					$resultNP=0;
-				} else {
-					$resultNP=$AccCat->sdc;
-				}
-
-				//N
-				$return = $AccCat->getResult($cpt['account_number'], 0, $date_start, $date_end, $cpt['dc']);
-				if ($return < 0) {
-					setEventMessages(null, $AccCat->errors, 'errors');
-					$resultN=0;
-				} else {
-					$resultN=$AccCat->sdc;
-				}
-
-				$totCat['NP'] += $resultNP;
-				$totCat['N'] += $resultN;
-				$sommes[$code]['NP'] += $resultNP;
-				$sommes[$code]['N'] += $resultN;
-				$totPerAccount[$cpt['account_number']]['NP'] = $resultNP;
-				$totPerAccount[$cpt['account_number']]['N'] = $resultN;
-
-				foreach($months as $k => $v)
-				{
-					$return = $AccCat->getResult($cpt['account_number'], $k+1, $date_start, $date_end, $cpt['dc']);
-					if ($return < 0) {
-						setEventMessages(null, $AccCat->errors, 'errors');
-						$resultM=0;
-					} else {
-						$resultM=$AccCat->sdc;
-					}
-					$totCat['M'][$k] += $resultM;
-					$sommes[$code]['M'][$k] += $resultM;
-					$totPerAccount[$cpt['account_number']]['M'][$k] = $resultM;
-				}
-			}
-
-			// Now output columns for row $code ('VTE', 'MAR', ...)
 			print '<td align="right">' . price($totCat['NP'])  . '</td>';
 			print '<td align="right">' . price($totCat['N']) . '</td>';
 
@@ -487,8 +506,7 @@ elseif ($modecompta=="BOOKKEEPING")
 
 			print "</tr>\n";
 
-			// Loop on detail of all accounts
-			// This make 14 calls for each detail of account (NP, N and month m)
+			// Loop on detail of all accounts to output the detail
 			if ($showaccountdetail != 'no')
 			{
 				foreach($cpts as $i => $cpt)
@@ -525,7 +543,6 @@ elseif ($modecompta=="BOOKKEEPING")
 								print '<td align="right">' . price($resultM) . '</td>';
 							}
 						}
-
 						print "</tr>\n";
 					}
 				}

+ 2 - 2
htdocs/compta/salaries/card.php

@@ -63,7 +63,7 @@ $hookmanager->initHooks(array('salarycard','globalcard'));
 
 if ($cancel)
 {
-	header("Location: index.php");
+	header("Location: list.php");
 	exit;
 }
 
@@ -139,7 +139,7 @@ if ($action == 'add' && empty($cancel))
 		if ($ret > 0)
 		{
 			$db->commit();
-			header("Location: index.php");
+			header("Location: list.php");
 			exit;
 		}
 		else

+ 8 - 6
htdocs/compta/salaries/stats/index.php

@@ -187,7 +187,7 @@ $head[$h][1] = $langs->trans("ByMonthYear");
 $head[$h][2] = 'byyear';
 $h++;
 
-complete_head_from_modules($conf,$langs,null,$head,$h,'trip_stats');
+complete_head_from_modules($conf,$langs,null,$head,$h,'salaries_stats');
 
 dol_fiche_head($head, 'byyear', $langs->trans("Statistics"), -1);
 
@@ -197,7 +197,7 @@ print '<div class="fichecenter"><div class="fichethirdleft">';
 
 // Show filter box
 print '<form name="stats" method="POST" action="'.$_SERVER["PHP_SELF"].'">';
-print '<table class="border" width="100%">';
+print '<table class="noborder" width="100%">';
 print '<tr class="liste_titre"><td class="liste_titre" colspan="2">'.$langs->trans("Filter").'</td></tr>';
 // User
 print '<tr><td>'.$langs->trans("User").'</td><td>';
@@ -215,8 +215,8 @@ print '</form>';
 print '<br><br>';
 
 print '<div class="div-table-responsive-no-min">';
-print '<table class="border" width="100%">';
-print '<tr>';
+print '<table class="noborder" width="100%">';
+print '<tr class="liste_titre" height="24">';
 print '<td align="center">'.$langs->trans("Year").'</td>';
 print '<td align="right">'.$langs->trans("Number").'</td>';
 print '<td align="right">'.$langs->trans("AmountTotal").'</td>';
@@ -231,14 +231,16 @@ foreach ($data as $val)
 	{
 		// If we have empty year
 		$oldyear--;
-		print '<tr height="24">';
+
+		print '<tr class="oddeven" height="24">';
 		print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$oldyear.'">'.$oldyear.'</a></td>';
 		print '<td align="right">0</td>';
 		print '<td align="right">0</td>';
 		print '<td align="right">0</td>';
 		print '</tr>';
 	}
-	print '<tr height="24">';
+
+	print '<tr class="oddeven" height="24">';
 	print '<td align="center"><a href="'.$_SERVER["PHP_SELF"].'?year='.$year.'">'.$year.'</a></td>';
 	print '<td align="right">'.$val['nb'].'</td>';
 	print '<td align="right">'.price(price2num($val['total'],'MT'),1).'</td>';

+ 14 - 20
htdocs/contact/agenda.php

@@ -1,6 +1,6 @@
 <?php
 /* Copyright (C) 2004-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
- * Copyright (C) 2004-2015 Laurent Destailleur  <eldy@users.sourceforge.net>
+ * Copyright (C) 2004-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
  * Copyright (C) 2004      Benoit Mortier       <benoit.mortier@opensides.be>
  * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
  * Copyright (C) 2007      Franky Van Liedekerke <franky.van.liedekerke@telenet.be>
@@ -132,16 +132,13 @@ if (empty($reshook))
  *	View
  */
 
+$form = new Form($db);
 
 $title = (! empty($conf->global->SOCIETE_ADDRESSES_MANAGEMENT) ? $langs->trans("Contacts") : $langs->trans("ContactsAddresses"));
 if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/contactnameonly/',$conf->global->MAIN_HTML_TITLE) && $object->lastname) $title=$object->lastname;
 $help_url='EN:Module_Third_Parties|FR:Module_Tiers|ES:Empresas';
 llxHeader('', $title, $help_url);
 
-$form = new Form($db);
-$formcompany = new FormCompany($db);
-
-$countrynotdefined=$langs->trans("ErrorSetACountryFirst").' ('.$langs->trans("SeeAbove").')';
 
 if ($socid > 0)
 {
@@ -259,20 +256,16 @@ else
     	//print '<div class="tabsAction">';
         //print '</div>';
 
-
-    	$morehtmlcenter='';
-        if (! empty($conf->agenda->enabled))
-        {
-        	if (! empty($user->rights->agenda->myactions->create) || ! empty($user->rights->agenda->allactions->create))
-        	{
-            	$morehtmlcenter.= '<a class="butAction" href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create'.$out.'">'.$langs->trans("AddAction").'</a>';
-        	}
-        	else
-        	{
-            	$morehtmlcenter.= '<a class="butActionRefused" href="#">'.$langs->trans("AddAction").'</a>';
-        	}
-        }
-
+    	$newcardbutton='';
+    	if (! empty($conf->agenda->enabled))
+    	{
+    		if (! empty($user->rights->agenda->myactions->create) || ! empty($user->rights->agenda->allactions->create))
+    		{
+    			$newcardbutton.='<a class="butActionNew" href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create'.$out.'"><span class="valignmiddle">'.$langs->trans("AddAction").'</span>';
+    			$newcardbutton.= '<span class="fa fa-plus-circle valignmiddle"></span>';
+    			$newcardbutton.= '</a>';
+    		}
+    	}
 
         if (! empty($conf->agenda->enabled) && (!empty($user->rights->agenda->myactions->read) || !empty($user->rights->agenda->allactions->read) ))
        	{
@@ -282,7 +275,8 @@ else
             if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage;
             if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit;
 
-            print_barre_liste($langs->trans("ActionsOnCompany"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $morehtmlcenter, 0, -1, '', '', '', '', 0, 1, 1);
+            print load_fiche_titre($langs->trans("ActionsOnContact"), $newcardbutton, '');
+            //print_barre_liste($langs->trans("ActionsOnCompany"), 0, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, $morehtmlcenter, 0, -1, '', '', '', '', 0, 1, 1);
 
             // List of all actions
     		$filters=array();

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

@@ -940,8 +940,8 @@ class Contact extends CommonObject
 
 		$error=0;
 
-		$this->old_lastname = $obj->lastname;
-		$this->old_firstname = $obj->firstname;
+		//$this->old_lastname = $obj->lastname;
+		//$this->old_firstname = $obj->firstname;
 
 		$this->db->begin();
 

+ 1 - 0
htdocs/contact/list.php

@@ -322,6 +322,7 @@ if (strlen($search_facebook))       $sql.= natural_search('p.facebook', $search_
 if (strlen($search_email))          $sql.= natural_search('p.email', $search_email);
 if (strlen($search_zip))   			$sql.= natural_search("p.zip",$search_zip);
 if (strlen($search_town))   		$sql.= natural_search("p.town",$search_town);
+
 if ($search_status != '' && $search_status >= 0) $sql.= " AND p.statut = ".$db->escape($search_status);
 if ($search_import_key)             $sql.= natural_search("p.import_key",$search_import_key);
 if ($type == "o")        // filtre sur type

+ 1 - 1
htdocs/core/actions_extrafields.inc.php

@@ -29,7 +29,7 @@ $mesg=array();
 
 $extrasize=GETPOST('size','int');
 $type=GETPOST('type','alpha');
-$param=GETPOST('param','alpha');;
+$param=GETPOST('param','alpha');
 
 if ($type=='double' && strpos($extrasize,',')===false) $extrasize='24,8';
 if ($type=='date')     $extrasize='';

+ 1 - 1
htdocs/core/actions_massactions.inc.php

@@ -217,7 +217,7 @@ if (! $error && $massaction == 'confirm_presend')
 					$resaction.='<div class="error">'.$langs->trans('ErrorOnlyOrderNotDraftCanBeSentInMassAction',$objectobj->ref).'</div><br>';
 					continue;
 				}
-				if ($objectclass == 'Facture' && $objectobj->statut != Facture::STATUS_VALIDATED)
+				if ($objectclass == 'Facture' && $objectobj->statut == Facture::STATUS_DRAFT)
 				{
 					$langs->load("errors");
 					$nbignored++;

+ 5 - 2
htdocs/core/boxes/box_task.php

@@ -1,6 +1,6 @@
 <?php
-/* Copyright (C) 2012-2014 Charles-François BENKE <charles.fr@benke.fr>
- * Copyright (C) 2015      Frederic France        <frederic.france@free.fr>
+/* Copyright (C) 2012-2018 Charlene BENKE 	<charlie@patas-monkey.com>
+ * Copyright (C) 2015      Frederic France      <frederic.france@free.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
@@ -82,6 +82,9 @@ class box_task extends ModeleBoxes
 		$totalMnt = 0;
 		$totalnb = 0;
 		$totalDuree=0;
+		$totalplannedtot=0;
+		$totaldurationtot=0;
+		
 		include_once DOL_DOCUMENT_ROOT."/projet/class/task.class.php";
 		$taskstatic=new Task($db);
 

+ 7 - 5
htdocs/core/class/CMailFile.class.php

@@ -68,8 +68,10 @@ class CMailFile
 	var $smtps;			// Contains SMTPs object (if this method is used)
 	var $phpmailer;		// Contains PHPMailer object (if this method is used)
 
-	//CSS
-	var $css;
+	/**
+	 * @var string CSS
+	 */
+	public $css;
 	//! Defined css style for body background
 	var $styleCSS;
 	//! Defined background directly in body tag
@@ -475,7 +477,7 @@ class CMailFile
 			if (! empty($addr_cc)) $this->message->setCc($this->getArrayAddress($addr_cc));
 			if (! empty($addr_bcc)) $this->message->setBcc($this->getArrayAddress($addr_bcc));
 			//if (! empty($errors_to)) $this->message->setErrorsTo($this->getArrayAddress($errors_to);
-			if (isset($this->deliveryreceipt) && $this->deliveryreceipt == 1) $this->message->setReadReceiptTo($this->getArrayAddress($from));
+			if (isset($deliveryreceipt) && $deliveryreceipt == 1) $this->message->setReadReceiptTo($this->getArrayAddress($from));
 		}
 		else
 		{
@@ -944,7 +946,7 @@ class CMailFile
 	/**
 	 * Build a css style (mode = all) into this->styleCSS and this->bodyCSS
 	 *
-	 * @return css
+	 * @return string
 	 */
 	function buildCSS()
 	{
@@ -1232,7 +1234,7 @@ class CMailFile
 		{
 			foreach ($images_list as $img)
 			{
-				dol_syslog("CMailFile::write_images: i=$i");
+				dol_syslog("CMailFile::write_images: ".$img["name"]);
 
 				$out.= "--" . $this->related_boundary . $this->eol; // always related for an inline image
 				$out.= "Content-Type: " . $img["content_type"] . "; name=\"".$img["name"]."\"".$this->eol;

+ 0 - 1
htdocs/core/class/commondocgenerator.class.php

@@ -1017,7 +1017,6 @@ abstract class CommonDocGenerator
         global $hookmanager;
 
         $parameters=array(
-            'object' => $object,
             'curY' => &$curY,
             'columnText' => $columnText,
             'colKey' => $colKey

+ 35 - 7
htdocs/core/class/commonobject.class.php

@@ -5145,7 +5145,7 @@ abstract class CommonObject
 	 *  @return int                 		-1=error, O=did nothing, 1=OK
 	 *  @see setValueFrom, insertExtraFields
 	 */
-	function updateExtraField($key, $trigger, $userused)
+	function updateExtraField($key, $trigger=null, $userused=null)
 	{
 		global $conf,$langs,$user;
 
@@ -6291,12 +6291,11 @@ abstract class CommonObject
 				// Load language if required
 				if (! empty($extrafields->attributes[$this->table_element]['langfile'][$key])) $langs->load($extrafields->attributes[$this->table_element]['langfile'][$key]);
 
+				$colspan='3';
 				if (is_array($params) && count($params)>0) {
 					if (array_key_exists('colspan',$params)) {
 						$colspan=$params['colspan'];
 					}
-				}else {
-					$colspan='3';
 				}
 
 				switch($mode) {
@@ -7274,16 +7273,45 @@ abstract class CommonObject
 	/**
 	 * Delete object in database
 	 *
-	 * @param User $user       User that deletes
-	 * @param bool $notrigger  false=launch triggers after, true=disable triggers
-	 * @return int             <0 if KO, >0 if OK
+	 * @param 	User 	$user       			User that deletes
+	 * @param 	bool 	$notrigger  			false=launch triggers after, true=disable triggers
+	 * @param	int		$forcechilddeletion		0=no, 1=Force deletion of children
+	 * @return 	int             				<=0 if KO, >0 if OK
 	 */
-	public function deleteCommon(User $user, $notrigger = false)
+	public function deleteCommon(User $user, $notrigger=false, $forcechilddeletion=0)
 	{
 		$error=0;
 
 		$this->db->begin();
 
+		if ($forcechilddeletion)
+		{
+			foreach($this->childtables as $table)
+			{
+				$sql = 'DELETE FROM '.MAIN_DB_PREFIX.$table.' WHERE '.$this->fk_element.' = '.$this->id;
+				$resql = $this->db->query($sql);
+				if (! $resql)
+				{
+					$this->error=$this->db->lasterror();
+					$this->errors[]=$this->error;
+					$this->db->rollback();
+					return -1;
+				}
+			}
+		}
+		elseif (! empty($this->fk_element) && ! empty($this->childtables))	// If object has childs linked with a foreign key field, we check all child tables.
+		{
+			$objectisused = $this->isObjectUsed($this->id);
+			if (! empty($objectisused))
+			{
+				dol_syslog(get_class($this)."::deleteCommon Can't delete record as it has some child", LOG_WARNING);
+				$this->error='ErrorRecordHasChildren';
+				$this->errors[]=$this->error;
+				$this->db->rollback();
+				return 0;
+			}
+		}
+
 		if (! $error) {
 			if (! $notrigger) {
 				// Call triggers

+ 5 - 1
htdocs/core/class/conf.class.php

@@ -238,7 +238,11 @@ class Conf
 		{
 			global $mc;
 			$ret = @dol_include_once('/multicompany/class/actions_multicompany.class.php');
-			if ($ret) $mc = new ActionsMulticompany($db);
+			if ($ret)
+			{
+				$mc = new ActionsMulticompany($db);
+				$this->mc = $mc;
+			}
 		}
 
 		// Clean some variables

+ 1 - 1
htdocs/core/class/dolgraph.class.php

@@ -1108,7 +1108,7 @@ class DolGraph
 			// Background color
 			$color1=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[0],$this->bgcolorgrid[2]);
 			$color2=sprintf("%02x%02x%02x",$this->bgcolorgrid[0],$this->bgcolorgrid[1],$this->bgcolorgrid[2]);
-			$this->stringtoshow.=', grid: { hoverable: true, backgroundColor: { colors: ["#'.$color1.'", "#'.$color2.'"] }, borderWidth: 1, borderColor: \'#eee\', tickColor  : \'#f3f3f3\' }'."\n";
+			$this->stringtoshow.=', grid: { hoverable: true, backgroundColor: { colors: ["#'.$color1.'", "#'.$color2.'"] }, borderWidth: 1, borderColor: \'#e6e6e6\', tickColor  : \'#e6e6e6\' }'."\n";
 			//$this->stringtoshow.=', shadowSize: 20'."\n";    TODO Uncommet this
 			$this->stringtoshow.='});'."\n";
 			$this->stringtoshow.='}'."\n";

+ 3 - 2
htdocs/core/class/events.class.php

@@ -137,6 +137,7 @@ class Events // extends CommonObject
 
 		// Clean parameters
 		$this->description=trim($this->description);
+		if (empty($this->user_agent) && !empty($_SERVER['HTTP_USER_AGENT'])) $this->user_agent=$_SERVER['HTTP_USER_AGENT'];
 
 		// Check parameters
 		if (empty($this->description)) { $this->error='ErrorBadValueForParameterCreateEventDesc'; return -1; }
@@ -153,8 +154,8 @@ class Events // extends CommonObject
 		$sql.= ") VALUES (";
 		$sql.= " '".$this->db->escape($this->type)."',";
 		$sql.= " ".$conf->entity.",";
-		$sql.= " '".$this->db->escape($_SERVER['REMOTE_ADDR'])."',";
-		$sql.= " ".($_SERVER['HTTP_USER_AGENT']?"'".$this->db->escape(dol_trunc($_SERVER['HTTP_USER_AGENT'],250))."'":'NULL').",";
+		$sql.= " '".$this->db->escape(getUserRemoteIP())."',";
+		$sql.= " ".($this->user_agent ? "'".$this->db->escape(dol_trunc($this->user_agent,250))."'" : 'NULL').",";
 		$sql.= " '".$this->db->idate($this->dateevent)."',";
 		$sql.= " ".($user->id?"'".$this->db->escape($user->id)."'":'NULL').",";
 		$sql.= " '".$this->db->escape(dol_trunc($this->description,250))."'";

+ 6 - 4
htdocs/core/class/html.form.class.php

@@ -18,6 +18,7 @@
  * Copyright (C) 2014       Alexandre Spangaro      <aspangaro.dolibarr@gmail.com>
  * Copyright (C) 2018       Ferran Marcet           <fmarcet@2byte.es>
  * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.fr>
+ * Copyright (C) 2018       Nicolas ZABOURI	        <info@inovea-conseil.com>
  *
  * 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
@@ -6739,6 +6740,7 @@ class Form
 		}
 		else if ($object->element == 'member')
 		{
+			$ret.=$object->ref.'<br>';
 			$fullname=$object->getFullName($langs);
 			if ($object->morphy == 'mor' && $object->societe) {
 				$ret.= dol_htmlentities($object->societe) . ((! empty($fullname) && $object->societe != $fullname)?' ('.dol_htmlentities($fullname).')':'');
@@ -6859,10 +6861,10 @@ class Form
 			$dir=$conf->user->dir_output;
 			if (! empty($object->photo))
 			{
-				if ((string) $imagesize == 'mini') $file=get_exdir($id, 2, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_mini');
-				else if ((string) $imagesize == 'small') $file=get_exdir($id, 2, 0, 0, $object, 'user').getImageFileNameForSize($object->photo, '_small');
-				else $file=get_exdir($id, 2, 0, 0, $object, 'user').$object->photo;
-				$originalfile=get_exdir($id, 2, 0, 0, $object, 'user').$object->photo;
+				if ((string) $imagesize == 'mini') $file=get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_mini');
+				else if ((string) $imagesize == 'small') $file=get_exdir(0, 0, 0, 0, $object, 'user').$object->id.'/'.getImageFileNameForSize($object->photo, '_small');
+				else $file=get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
+				$originalfile=get_exdir(0, 0, 0, 0, $object, 'user').'/'.$object->id.'/'.$object->photo;
 			}
 			if (! empty($conf->global->MAIN_OLD_IMAGE_LINKS)) $altfile=$object->id.".jpg";	// For backward compatibility
 			$email=$object->email;

+ 2 - 2
htdocs/core/class/html.formactions.class.php

@@ -332,7 +332,7 @@ class FormActions
         // phpcs:enable
         global $langs,$user,$form,$conf;
 
-        if (! is_object($form)) $form=new Form($db);
+        if (! is_object($form)) $form=new Form($this->db);
 
         require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
         require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
@@ -357,7 +357,7 @@ class FormActions
 		}
 		else
 		{
-			$out.=$form->selectarray($htmlname, $arraylist, $selected, 0, 0, 0, '', 0, 0, 0, '', '', 1);
+			$out.=$form->selectarray($htmlname, $arraylist, $selected, 0, 0, 0, '', 0, 0, 0, '', 'minwidth200', 1);
 		}
 
         if ($user->admin && empty($onlyautoornot) && $hideinfohelp <= 0)

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

@@ -1637,7 +1637,7 @@ class FormFile
 	 */
 	private function _formAjaxFileUpload($object)
 	{
-		global $langs;
+		global $langs, $conf;
 
 		// PHP post_max_size
 		$post_max_size				= ini_get('post_max_size');

+ 1 - 2
htdocs/core/class/html.formmail.class.php

@@ -342,8 +342,7 @@ class FormMail extends Form
 					$model_id=$this->param["models_id"];
 				}
 
-				// we set -1 if model_id empty
-				$arraydefaultmessage = $this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, ($model_id ? $model_id : -1));
+				$arraydefaultmessage=$this->getEMailTemplate($this->db, $this->param["models"], $user, $outputlangs, $model_id);		// If $model_id is empty, preselect the first one
 			}
 
 			// Define list of attached files

+ 12 - 15
htdocs/core/class/translate.class.php

@@ -189,7 +189,7 @@ class Translate
 
 
 		// Load $this->tab_translate[] from database
-		if (empty($loadfromfileonly) && count($this->tab_translate) == 0) $this->loadFromDatabase($db);      // Nothing was loaded yet, so we load database.
+		if (empty($loadfromfileonly) && count($this->tab_translate) == 0) $this->loadFromDatabase($db);      // No translation was never loaded yet, so we load database.
 
 
 		$newdomain = $domain;
@@ -231,7 +231,8 @@ class Translate
 
 			$filelangexists=is_file($file_lang_osencoded);
 
-			//dol_syslog(get_class($this).'::Load Try to read for alt='.$alt.' langofdir='.$langofdir.' newdomain='.$domain.' modulename='.$modulename.' file_lang='.$file_lang." => filelangexists=".$filelangexists);
+			//dol_syslog(get_class($this).'::Load Try to read for alt='.$alt.' langofdir='.$langofdir.' domain='.$domain.' newdomain='.$newdomain.' modulename='.$modulename.' file_lang='.$file_lang." => filelangexists=".$filelangexists);
+			//print 'Try to read for alt='.$alt.' langofdir='.$langofdir.' domain='.$domain.' newdomain='.$newdomain.' modulename='.$modulename.' this->_tab_loaded[newdomain]='.$this->_tab_loaded[$newdomain].' file_lang='.$file_lang." => filelangexists=".$filelangexists."\n";
 
 			if ($filelangexists)
 			{
@@ -354,12 +355,12 @@ class Translate
 			$this->load($domain,$alt+1,$stopafterdirection,$langofdir);
 		}
 
-		// We already are the reference file. No more files to scan to complete.
+		// We are in the pass of the reference file. No more files to scan to complete.
 		if ($alt == 2)
 		{
-			if ($fileread) $this->_tab_loaded[$newdomain]=1;	// Set domain file as loaded
+			if ($fileread) $this->_tab_loaded[$newdomain]=1;								// Set domain file as found so loaded
 
-			if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2;           // Set this file as found
+			if (empty($this->_tab_loaded[$newdomain])) $this->_tab_loaded[$newdomain]=2;	// Set this file as not found
 		}
 
 		// This part is deprecated and replaced with table llx_overwrite_trans
@@ -410,22 +411,18 @@ class Translate
 		//dol_syslog("Translate::Load Start domain=".$domain." alt=".$alt." forcelangdir=".$forcelangdir." this->defaultlang=".$this->defaultlang);
 
 		$newdomain = $domain;
-		$modulename = '';
 
-        // Check cache
-		if (! empty($this->_tab_loaded[$newdomain]))	// File already loaded for this domain
+		// Check cache
+		if (! empty($this->_tab_loaded[$newdomain]))	// File already loaded for this domain 'database'
 		{
 			//dol_syslog("Translate::Load already loaded for newdomain=".$newdomain);
 			return 0;
 		}
 
-		$this->_tab_loaded[$newdomain] = 1;   // We want to be sure this function is called once only.
+		$this->_tab_loaded[$newdomain] = 1;   // We want to be sure this function is called once only for domain 'database'
 
         $fileread=0;
-		$langofdir=(empty($forcelangdir)?$this->defaultlang:$forcelangdir);
-
-		// Redefine alt
-		$alt=2;
+		$langofdir=$this->defaultlang;
 
 		if (empty($langofdir))	// This may occurs when load is called without setting the language and without providing a value for forcelangdir
 		{
@@ -434,14 +431,14 @@ class Translate
 		}
 
 		// TODO Move cache read out of loop on dirs or at least filelangexists
-	    $found=false;
+		$found=false;
 
 		// Enable caching of lang file in memory (not by default)
 		$usecachekey='';
 		// Using a memcached server
 		if (! empty($conf->memcached->enabled) && ! empty($conf->global->MEMCACHED_SERVER))
 		{
-			$usecachekey=$newdomain.'_'.$langofdir.'_'.md5($file_lang);    // Should not contains special chars
+			$usecachekey=$newdomain.'_'.$langofdir;    // Should not contains special chars
 		}
 		// Using cache with shmop. Speed gain: 40ms - Memory overusage: 200ko (Size of session cache file)
 		else if (isset($conf->global->MAIN_OPTIMIZE_SPEED) && ($conf->global->MAIN_OPTIMIZE_SPEED & 0x02))

+ 1 - 1
htdocs/core/class/utils.class.php

@@ -213,7 +213,7 @@ class Utils
 		if ($file == 'auto')
 		{
 			$prefix='dump';
-			$ext='.sql';
+			$ext='sql';
 			if (in_array($type, array('mysql', 'mysqli')))  { $prefix='mysqldump'; $ext='sql'; }
 			//if ($label == 'PostgreSQL') { $prefix='pg_dump'; $ext='dump'; }
 			if (in_array($type, array('pgsql'))) { $prefix='pg_dump'; $ext='sql'; }

+ 25 - 25
htdocs/core/js/lib_head.js.php

@@ -1,5 +1,5 @@
 <?php
-/* Copyright (C) 2005-2014  Laurent Destailleur <eldy@users.sourceforge.net>
+/* Copyright (C) 2005-2018  Laurent Destailleur <eldy@users.sourceforge.net>
  * Copyright (C) 2005-2014  Regis Houssin       <regis.houssin@inodbox.com>
  * Copyright (C) 2015       Raphaël Doursenaud  <rdoursenaud@gpcsolutions.fr>
  *
@@ -46,33 +46,33 @@ else header('Cache-Control: no-cache');
 
 // Define tradMonths javascript array (we define this in datepicker AND in parent page to avoid errors with IE8)
 $tradMonths=array(
-dol_escape_js($langs->transnoentitiesnoconv("January")),
-dol_escape_js($langs->transnoentitiesnoconv("February")),
-dol_escape_js($langs->transnoentitiesnoconv("March")),
-dol_escape_js($langs->transnoentitiesnoconv("April")),
-dol_escape_js($langs->transnoentitiesnoconv("May")),
-dol_escape_js($langs->transnoentitiesnoconv("June")),
-dol_escape_js($langs->transnoentitiesnoconv("July")),
-dol_escape_js($langs->transnoentitiesnoconv("August")),
-dol_escape_js($langs->transnoentitiesnoconv("September")),
-dol_escape_js($langs->transnoentitiesnoconv("October")),
-dol_escape_js($langs->transnoentitiesnoconv("November")),
-dol_escape_js($langs->transnoentitiesnoconv("December"))
+dol_escape_js($langs->transnoentitiesnoconv("Month01")),
+dol_escape_js($langs->transnoentitiesnoconv("Month02")),
+dol_escape_js($langs->transnoentitiesnoconv("Month03")),
+dol_escape_js($langs->transnoentitiesnoconv("Month04")),
+dol_escape_js($langs->transnoentitiesnoconv("Month05")),
+dol_escape_js($langs->transnoentitiesnoconv("Month06")),
+dol_escape_js($langs->transnoentitiesnoconv("Month07")),
+dol_escape_js($langs->transnoentitiesnoconv("Month08")),
+dol_escape_js($langs->transnoentitiesnoconv("Month09")),
+dol_escape_js($langs->transnoentitiesnoconv("Month10")),
+dol_escape_js($langs->transnoentitiesnoconv("Month11")),
+dol_escape_js($langs->transnoentitiesnoconv("Month12"))
 );
 
 $tradMonthsShort=array(
-$langs->trans("JanuaryMin"),
-$langs->trans("FebruaryMin"),
-$langs->trans("MarchMin"),
-$langs->trans("AprilMin"),
-$langs->trans("MayMin"),
-$langs->trans("JuneMin"),
-$langs->trans("JulyMin"),
-$langs->trans("AugustMin"),
-$langs->trans("SeptemberMin"),
-$langs->trans("OctoberMin"),
-$langs->trans("NovemberMin"),
-$langs->trans("DecemberMin")
+$langs->trans("MonthShort01"),
+$langs->trans("MonthShort02"),
+$langs->trans("MonthShort03"),
+$langs->trans("MonthShort04"),
+$langs->trans("MonthShort05"),
+$langs->trans("MonthShort06"),
+$langs->trans("MonthShort07"),
+$langs->trans("MonthShort08"),
+$langs->trans("MonthShort09"),
+$langs->trans("MonthShort10"),
+$langs->trans("MonthShort11"),
+$langs->trans("MonthShort12")
 );
 
 $tradDays=array(

+ 12 - 9
htdocs/core/lib/admin.lib.php

@@ -724,15 +724,18 @@ function defaultvalues_prepare_head()
     $head[$h][2] = 'sortorder';
     $h++;
 
-    $head[$h][0] = DOL_URL_ROOT."/admin/defaultvalues.php?mode=focus";
-    $head[$h][1] = $langs->trans("DefaultFocus");
-    $head[$h][2] = 'focus';
-    $h++;
-
-    $head[$h][0] = DOL_URL_ROOT."/admin/defaultvalues.php?mode=mandatory";
-    $head[$h][1] = $langs->trans("DefaultMandatory");
-    $head[$h][2] = 'mandatory';
-    $h++;
+    if (! empty($conf->use_javascript_ajax))
+    {
+    	$head[$h][0] = DOL_URL_ROOT."/admin/defaultvalues.php?mode=focus";
+	    $head[$h][1] = $langs->trans("DefaultFocus");
+	    $head[$h][2] = 'focus';
+	    $h++;
+
+	    $head[$h][0] = DOL_URL_ROOT."/admin/defaultvalues.php?mode=mandatory";
+	    $head[$h][1] = $langs->trans("DefaultMandatory");
+	    $head[$h][2] = 'mandatory';
+	    $h++;
+    }
 
     /*$head[$h][0] = DOL_URL_ROOT."/admin/translation.php?mode=searchkey";
     $head[$h][1] = $langs->trans("TranslationKeySearch");

+ 7 - 7
htdocs/core/lib/agenda.lib.php

@@ -64,7 +64,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 	print '<input type="hidden" name="month" value="' . $month . '">';
 	print '<input type="hidden" name="day" value="' . $day . '">';
 	print '<input type="hidden" name="action" value="' . $action . '">';
-	print '<input type="hidden" name="showbirthday" value="' . $showbirthday . '">';
+	print '<input type="hidden" name="search_showbirthday" value="' . $showbirthday . '">';
 
 	print '<div class="fichecenter">';
 
@@ -79,7 +79,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 		print '<td class="nowrap" style="padding-bottom: 2px; padding-right: 4px;">';
 		print $langs->trans("ActionsToDoBy").' &nbsp; ';
 		print '</td><td style="padding-bottom: 2px; padding-right: 4px;">';
-		print $form->select_dolusers($filtert, 'filtert', 1, '', ! $canedit, '', '', 0, 0, 0, '', 0, '', 'maxwidth300');
+		print $form->select_dolusers($filtert, 'search_filtert', 1, '', ! $canedit, '', '', 0, 0, 0, '', 0, '', 'maxwidth300');
 		if (empty($conf->dol_optimize_smallscreen)) print ' &nbsp; '.$langs->trans("or") . ' '.$langs->trans("ToUserOfGroup").' &nbsp; ';
 		print $form->select_dolgroups($usergroupid, 'usergroup', 1, '', ! $canedit);
 		print '</td></tr>';
@@ -94,7 +94,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
     		print '<td class="nowrap" style="padding-bottom: 2px; padding-right: 4px;">';
     		print $langs->trans("Resource");
     		print ' &nbsp;</td><td class="nowrap maxwidthonsmartphone" style="padding-bottom: 2px; padding-right: 4px;">';
-            print $formresource->select_resource_list($resourceid, "resourceid", '', 1, 0, 0, null, '', 2);
+            print $formresource->select_resource_list($resourceid, "search_resourceid", '', 1, 0, 0, null, '', 2);
     		print '</td></tr>';
 		}
 
@@ -108,7 +108,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 		{
             $multiselect=(!empty($conf->global->AGENDA_USE_EVENT_TYPE));
 		}
-        print $formactions->select_type_actions($actioncode, "actioncode", $excludetype, (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:-1), 0, $multiselect);
+        print $formactions->select_type_actions($actioncode, "search_actioncode", $excludetype, (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:-1), 0, $multiselect);
 		print '</td></tr>';
 	}
 
@@ -118,7 +118,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 		print '<td class="nowrap" style="padding-bottom: 2px; padding-right: 4px;">';
 		print $langs->trans("ThirdParty").' &nbsp; ';
 		print '</td><td class="nowrap" style="padding-bottom: 2px;">';
-		print $form->select_company($socid, 'socid', '', 'SelectThirdParty', 0, 0, null, 0);
+		print $form->select_company($socid, 'search_socid', '', 'SelectThirdParty', 0, 0, null, 0);
 		print '</td></tr>';
 	}
 
@@ -131,7 +131,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 		print '<td class="nowrap" style="padding-bottom: 2px;">';
 		print $langs->trans("Project").' &nbsp; ';
 		print '</td><td class="nowrap" style="padding-bottom: 2px;">';
-		print $formproject->select_projects($socid?$socid:-1, $pid, 'projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'maxwidth500');
+		print $formproject->select_projects($socid?$socid:-1, $pid, 'search_projectid', 0, 0, 1, 0, 0, 0, 0, '', 1, 0, 'maxwidth500');
 		print '</td></tr>';
 	}
 
@@ -142,7 +142,7 @@ function print_actions_filter($form, $canedit, $status, $year, $month, $day, $sh
 		print '<td class="nowrap" style="padding-bottom: 2px; padding-right: 4px;">';
 		print $langs->trans("Status");
 		print ' &nbsp;</td><td class="nowrap" style="padding-bottom: 2px; padding-right: 4px;">';
-		$formactions->form_select_status_action('formaction', $status, 1, 'status', 1, 2, 'minwidth100');
+		$formactions->form_select_status_action('formaction', $status, 1, 'search_status', 1, 2, 'minwidth100');
 		print '</td></tr>';
 	}
 

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

@@ -377,7 +377,7 @@ function ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $
 
 	// select2 disabled for smartphones with standard browser.
 	// TODO With select2 v4, it seems ok, except that responsive style on table become crazy when scrolling at end of array)
-	if ($conf->browser->layout == 'phone') return '';
+	if (! empty($conf->browser->layout) && $conf->browser->layout == 'phone') return '';
 
 	if (! empty($conf->global->MAIN_DISABLE_AJAX_COMBOX)) return '';
 	if (empty($conf->use_javascript_ajax)) return '';

+ 27 - 7
htdocs/core/lib/company.lib.php

@@ -1317,8 +1317,14 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
     if (! empty($conf->agenda->enabled))
     {
         // Recherche histo sur actioncomm
-        $sql = "SELECT a.id, a.label,";
-        $sql.= " a.datep as dp,";
+ 	if (is_object($objcon) && $objcon->id) {
+		$sql = "SELECT DISTINCT a.id, a.label,";
+	}
+	else
+	{
+		$sql = "SELECT a.id, a.label,";
+	}
+	$sql.= " a.datep as dp,";
         $sql.= " a.datep2 as dp2,";
         $sql.= " a.note, a.percent,";
         $sql.= " a.fk_element, a.elementtype,";
@@ -1332,7 +1338,12 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
         $sql.= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
         $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
         $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
-        if (is_object($filterobj) && get_class($filterobj) == 'Societe')  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
+
+        if (is_object($objcon) && $objcon->id) {
+		    $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
+	    }
+
+	    if (is_object($filterobj) && get_class($filterobj) == 'Societe')  $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
         elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
         	$sql.= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
         	$sql.= " ON er.resource_type = 'dolresource'";
@@ -1344,7 +1355,7 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
         elseif (is_object($filterobj) && get_class($filterobj) == 'Product') $sql.= ", ".MAIN_DB_PREFIX."product as o";
 
         $sql.= " WHERE a.entity IN (".getEntity('agenda').")";
-        if (is_object($filterobj) && get_class($filterobj) == 'Societe'  && $filterobj->id) $sql.= " AND a.fk_soc = ".$filterobj->id;
+        if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) $sql.= " AND a.fk_soc = ".$filterobj->id;
         elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) $sql.= " AND a.fk_project = ".$filterobj->id;
         elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent')
         {
@@ -1361,8 +1372,14 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
         	$sql.= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
         	if ($filterobj->id) $sql.= " AND a.fk_element = ".$filterobj->id;
         }
-        //TODO check how ot work with new table actioncomm_resources and multiple contact affectation
-        if (is_object($objcon) && $objcon->id) $sql.= " AND a.fk_contact = ".$objcon->id;
+
+	    // Work with new table actioncomm_resources and multiple contact affectation.
+	    if (is_object($objcon) && $objcon->id)
+	    {
+		    $sql.= " AND r.element_type = '" . $objcon->table_element . "'" .
+			    " AND r.fk_element = " . $objcon->id;
+	    }
+
         // Condition on actioncode
         if (! empty($actioncode))
         {
@@ -1386,6 +1403,8 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
         if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
         elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
         if (is_array($filters) && $filters['search_agenda_label']) $sql.= natural_search('a.label', $filters['search_agenda_label']);
+	    
+	//TODO Add limit for thirdparty in  contexte very all result
         $sql.= $db->order($sortfield, $sortorder);
         dol_syslog("company.lib::show_actions_done", LOG_DEBUG);
         $resql=$db->query($sql);
@@ -1517,7 +1536,8 @@ function show_actions_done($conf, $langs, $db, $filterobj, $objcon='', $noprint=
         $contactstatic = new Contact($db);
 
         $out.='<form name="listactionsfilter" class="listactionsfilter" action="' . $_SERVER["PHP_SELF"] . '" method="POST">';
-        if ($objcon && get_class($objcon) == 'Contact' && $filterobj && get_class($filterobj) == 'Societe')
+        if ($objcon && get_class($objcon) == 'Contact' &&
+            (is_null($filterobj) || get_class($filterobj) == 'Societe'))
         {
             $out.='<input type="hidden" name="id" value="'.$objcon->id.'" />';
         }

+ 230 - 189
htdocs/core/lib/functions.lib.php

@@ -2665,6 +2665,20 @@ function dol_print_ip($ip,$mode=0)
 	return $ret;
 }
 
+/**
+ * Return the IP of remote user.
+ * Take HTTP_X_FORWARDED_FOR (defined when using proxy)
+ * Then HTTP_CLIENT_IP if defined (rare)
+ * Then REMOTE_ADDR (not way to be modified by user but may be wrong if using proxy)
+ *
+ * @return	string		Ip of remote user.
+ */
+function getUserRemoteIP()
+{
+	$ip = empty($_SERVER['HTTP_X_FORWARDED_FOR'])? (empty($_SERVER['HTTP_CLIENT_IP'])?(empty($_SERVER['REMOTE_ADDR'])?'':$_SERVER['REMOTE_ADDR']):$_SERVER['HTTP_CLIENT_IP']) : $_SERVER['HTTP_X_FORWARDED_FOR'];
+	return $ip;
+}
+
 /**
  * 	Return a country code from IP. Empty string if not found.
  *
@@ -2708,7 +2722,7 @@ function dol_user_country()
 	$ret='';
 	if (! empty($conf->geoipmaxmind->enabled))
 	{
-		$ip=$_SERVER["REMOTE_ADDR"];
+		$ip=getUserRemoteIP();
 		$datafile=$conf->global->GEOIPMAXMIND_COUNTRY_DATAFILE;
 		//$ip='24.24.24.24';
 		//$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
@@ -2890,188 +2904,6 @@ function dol_substr($string, $start, $length, $stringencoding='', $trunconbytes=
 }
 
 
-/**
- *  Show a javascript graph.
- *  Do not use this function anymore. Use DolGraph class instead.
- *
- *  @param		string	$htmlid			Html id name
- *  @param		int		$width			Width in pixel
- *  @param		int		$height			Height in pixel
- *  @param		array	$data			Data array
- *  @param		int		$showlegend		1 to show legend, 0 otherwise
- *  @param		string	$type			Type of graph ('pie', 'barline')
- *  @param		int		$showpercent	Show percent (with type='pie' only)
- *  @param		string	$url			Param to add an url to click values
- *  @param		int		$combineother	0=No combine, 0.05=Combine if lower than 5%
- *  @param      int     $shownographyet Show graph to say there is not enough data
- *  @return		void
- *  @deprecated
- *  @see DolGraph
- */
-function dol_print_graph($htmlid,$width,$height,$data,$showlegend=0,$type='pie',$showpercent=0,$url='',$combineother=0.05,$shownographyet=0)
-{
-	dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING);
-
-	global $conf,$langs;
-	global $theme_datacolor;    // To have var kept when function is called several times
-
-	if ($shownographyet)
-	{
-		print '<div class="nographyet" style="width:'.$width.'px;height:'.$height.'px;"></div>';
-		print '<div class="nographyettext">'.$langs->trans("NotEnoughDataYet").'</div>';
-		return;
-	}
-
-	if (empty($conf->use_javascript_ajax)) return;
-	$jsgraphlib='flot';
-	$datacolor=array();
-
-	// Load colors of theme into $datacolor array
-	$color_file = DOL_DOCUMENT_ROOT."/theme/".$conf->theme."/graph-color.php";
-	if (is_readable($color_file))
-	{
-		include_once $color_file;
-		if (isset($theme_datacolor))
-		{
-			$datacolor=array();
-			foreach($theme_datacolor as $val)
-			{
-				$datacolor[]="#".sprintf("%02x",$val[0]).sprintf("%02x",$val[1]).sprintf("%02x",$val[2]);
-			}
-		}
-	}
-	print '<div id="'.$htmlid.'" style="width:'.$width.'px;height:'.$height.'px;"></div>';
-
-	// We use Flot js lib
-	if ($jsgraphlib == 'flot')
-	{
-		if ($type == 'pie')
-		{
-			// data is   array('series'=>array(serie1,serie2,...),
-			//                 'seriestype'=>array('bar','line',...),
-			//                 'seriescolor'=>array(0=>'#999999',1=>'#999999',...)
-			//                 'xlabel'=>array(0=>labelx1,1=>labelx2,...));
-			// serieX is array('label'=>'label', data=>val)
-			print '
-			<script type="text/javascript">
-			$(function () {
-				var data = '.json_encode($data['series']).';
-
-				function plotWithOptions() {
-					$.plot($("#'.$htmlid.'"), data,
-					{
-						series: {
-							pie: {
-								show: true,
-								radius: 0.8,';
-			if ($combineother)
-			{
-				print '
-								combine: {
-								 	threshold: '.$combineother.'
-								},';
-			}
-			print '
-								label: {
-									show: true,
-									radius: 0.9,
-									formatter: function(label, series) {
-										var percent=Math.round(series.percent);
-										var number=series.data[0][1];
-										return \'';
-										print '<div style="font-size:8pt;text-align:center;padding:2px;color:black;">';
-										if ($url) print '<a style="color: #FFFFFF;" border="0" href="'.$url.'">';
-										print '\'+'.($showlegend?'number':'label+\' \'+number');
-										if (! empty($showpercent)) print '+\'<br/>\'+percent+\'%\'';
-										print '+\'';
-										if ($url) print '</a>';
-										print '</div>\';
-									},
-									background: {
-										opacity: 0.0,
-										color: \'#000000\'
-									},
-								}
-							}
-						},
-						zoom: {
-							interactive: true
-						},
-						pan: {
-							interactive: true
-						},';
-						if (count($datacolor))
-						{
-							print 'colors: '.(! empty($data['seriescolor']) ? json_encode($data['seriescolor']) : json_encode($datacolor)).',';
-						}
-						print 'legend: {show: '.($showlegend?'true':'false').', position: \'ne\' }
-					});
-				}
-				plotWithOptions();
-			});
-			</script>';
-		}
-		else if ($type == 'barline')
-		{
-			// data is   array('series'=>array(serie1,serie2,...),
-			//                 'seriestype'=>array('bar','line',...),
-			//                 'seriescolor'=>array(0=>'#999999',1=>'#999999',...)
-			//                 'xlabel'=>array(0=>labelx1,1=>labelx2,...));
-			// serieX is array('label'=>'label', data=>array(0=>y1,1=>y2,...)) with same nb of value than into xlabel
-			print '
-			<script type="text/javascript">
-			$(function () {
-				var data = [';
-				$i=0; $outputserie=0;
-				foreach($data['series'] as $serie)
-				{
-					if ($data['seriestype'][$i]=='line') { $i++; continue; };
-					if ($outputserie > 0) print ',';
-					print '{ bars: { stack: 0, show: true, barWidth: 0.9, align: \'center\' }, label: \''.dol_escape_js($serie['label']).'\', data: '.json_encode($serie['data']).'}'."\n";
-					$outputserie++; $i++;
-				}
-				if ($outputserie) print ', ';
-				//print '];
-				//var datalines = [';
-				$i=0; $outputserie=0;
-				foreach($data['series'] as $serie)
-				{
-					if (empty($data['seriestype'][$i]) || $data['seriestype'][$i]=='bar') { $i++; continue; };
-					if ($outputserie > 0) print ',';
-					print '{ lines: { show: true }, label: \''.dol_escape_js($serie['label']).'\', data: '.json_encode($serie['data']).'}'."\n";
-					$outputserie++; $i++;
-				}
-				print '];
-				var dataticks = '.json_encode($data['xlabel']).'
-
-				function plotWithOptions() {
-					$.plot(jQuery("#'.$htmlid.'"), data,
-					{
-						series: {
-							stack: 0
-						},
-						zoom: {
-							interactive: true
-						},
-						pan: {
-							interactive: true
-						},';
-						if (count($datacolor))
-						{
-							print 'colors: '.json_encode($datacolor).',';
-						}
-						print 'legend: {show: '.($showlegend?'true':'false').'},
-						xaxis: {ticks: dataticks}
-					});
-				}
-				plotWithOptions();
-			});
-			</script>';
-		}
-		else print 'BadValueForParameterType';
-	}
-}
-
 /**
  *	Truncate a string to a particular length adding '...' if string larger than length.
  * 	If length = max length+1, we do no truncate to avoid having just 1 char replaced with '...'.
@@ -4222,10 +4054,10 @@ function load_fiche_titre($titre, $morehtmlright='', $picto='title_generic.png',
 	if ($picto == 'setup') $picto='title_generic.png';
 
 	$return.= "\n";
-	$return.= '<table '.($id?'id="'.$id.'" ':'').'summary="" class="centpercent notopnoleftnoright'.($morecssontable?' '.$morecssontable:'').'" style="margin-bottom: 2px;"><tr>';
+	$return.= '<table '.($id?'id="'.$id.'" ':'').'summary="" class="centpercent notopnoleftnoright'.($morecssontable?' '.$morecssontable:'').'" style="margin-bottom: 6px;"><tr>';	// maring bottom must be same than into print_barre_list
 	if ($picto) $return.= '<td class="nobordernopadding widthpictotitle opacityhigh" valign="middle">'.img_picto('',$picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
-	$return.= '<td class="nobordernopadding" valign="middle">';
-	$return.= '<div class="titre">'.$titre.'</div>';
+	$return.= '<td class="nobordernopadding valignmiddle">';
+	$return.= '<div class="titre inline-block">'.$titre.'</div>';
 	$return.= '</td>';
 	if (dol_strlen($morehtmlcenter))
 	{
@@ -4284,7 +4116,7 @@ function print_barre_liste($titre, $page, $file, $options='', $sortfield='', $so
 
 	print "\n";
 	print "<!-- Begin title '".$titre."' -->\n";
-	print '<table width="100%" border="0" class="notopnoleftnoright'.($morecss?' '.$morecss:'').'" style="margin-bottom: 6px;"><tr>';
+	print '<table border="0" class="centpercent notopnoleftnoright'.($morecss?' '.$morecss:'').'" style="margin-bottom: 6px;"><tr>';	// maring bottom must be same than into load_fiche_tire
 
 	// Left
 	//if ($picto && $titre) print '<td class="nobordernopadding hideonsmartphone" width="40" align="left" valign="middle">'.img_picto('', $picto, 'id="pictotitle"', $pictoisfullpath).'</td>';
@@ -5913,7 +5745,7 @@ function dol_textishtml($msg,$option=0)
  *
  *  @param	string	$text1		Text 1
  *  @param	string	$text2		Text 2
- *  @param  bool	$forxml     false=Use <br>, true=Use <br />
+ *  @param  bool	$forxml     false=Use <br> instead of \n if html content detected, true=Use <br /> instead of \n if html content detected
  *  @return	string				Text 1 + new line + Text2
  *  @see    dol_textishtml
  */
@@ -5965,7 +5797,7 @@ function getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $ob
 		'__USER_FIRSTNAME__' => (string) $user->firstname,
 		'__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
 		'__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
-		'__USER_REMOTE_IP__' => (string) $_SERVER['REMOTE_ADDR']
+		'__USER_REMOTE_IP__' => (string) getUserRemoteIP()
 		)
 			);
 	}
@@ -6952,6 +6784,215 @@ function picto_from_langcode($codelang, $moreatt = '')
 	return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt);
 }
 
+/**
+ * Return default language from country code
+ *
+ * @param 	string 	$countrycode	Country code like 'US', 'FR', 'CA', ...
+ * @return	string					Value of locale like 'en_US', 'fr_FR', ...
+ */
+function getLanguageCodeFromCountryCode($countrycode)
+{
+	global $mysoc;
+
+	if (strtoupper($countrycode) == 'MQ') return 'fr_CA';
+	if (strtoupper($countrycode) == 'SE') return 'sv_SE';	// se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
+	if (strtoupper($countrycode) == 'CH')
+	{
+		if ($mysoc->country_code == 'FR') return 'fr_CH';
+		if ($mysoc->country_code == 'DE') return 'de_CH';
+	}
+
+	// Locale list taken from:
+	// http://stackoverflow.com/questions/3191664/
+	// list-of-all-locales-and-their-short-codes
+	$locales = array(
+		'af-ZA',
+		'am-ET',
+		'ar-AE',
+		'ar-BH',
+		'ar-DZ',
+		'ar-EG',
+		'ar-IQ',
+		'ar-JO',
+		'ar-KW',
+		'ar-LB',
+		'ar-LY',
+		'ar-MA',
+		'ar-OM',
+		'ar-QA',
+		'ar-SA',
+		'ar-SY',
+		'ar-TN',
+		'ar-YE',
+		'as-IN',
+		'ba-RU',
+		'be-BY',
+		'bg-BG',
+		'bn-BD',
+		'bn-IN',
+		'bo-CN',
+		'br-FR',
+		'ca-ES',
+		'co-FR',
+		'cs-CZ',
+		'cy-GB',
+		'da-DK',
+		'de-AT',
+		'de-CH',
+		'de-DE',
+		'de-LI',
+		'de-LU',
+		'dv-MV',
+		'el-GR',
+		'en-AU',
+		'en-BZ',
+		'en-CA',
+		'en-GB',
+		'en-IE',
+		'en-IN',
+		'en-JM',
+		'en-MY',
+		'en-NZ',
+		'en-PH',
+		'en-SG',
+		'en-TT',
+		'en-US',
+		'en-ZA',
+		'en-ZW',
+		'es-AR',
+		'es-BO',
+		'es-CL',
+		'es-CO',
+		'es-CR',
+		'es-DO',
+		'es-EC',
+		'es-ES',
+		'es-GT',
+		'es-HN',
+		'es-MX',
+		'es-NI',
+		'es-PA',
+		'es-PE',
+		'es-PR',
+		'es-PY',
+		'es-SV',
+		'es-US',
+		'es-UY',
+		'es-VE',
+		'et-EE',
+		'eu-ES',
+		'fa-IR',
+		'fi-FI',
+		'fo-FO',
+		'fr-BE',
+		'fr-CA',
+		'fr-CH',
+		'fr-FR',
+		'fr-LU',
+		'fr-MC',
+		'fy-NL',
+		'ga-IE',
+		'gd-GB',
+		'gl-ES',
+		'gu-IN',
+		'he-IL',
+		'hi-IN',
+		'hr-BA',
+		'hr-HR',
+		'hu-HU',
+		'hy-AM',
+		'id-ID',
+		'ig-NG',
+		'ii-CN',
+		'is-IS',
+		'it-CH',
+		'it-IT',
+		'ja-JP',
+		'ka-GE',
+		'kk-KZ',
+		'kl-GL',
+		'km-KH',
+		'kn-IN',
+		'ko-KR',
+		'ky-KG',
+		'lb-LU',
+		'lo-LA',
+		'lt-LT',
+		'lv-LV',
+		'mi-NZ',
+		'mk-MK',
+		'ml-IN',
+		'mn-MN',
+		'mr-IN',
+		'ms-BN',
+		'ms-MY',
+		'mt-MT',
+		'nb-NO',
+		'ne-NP',
+		'nl-BE',
+		'nl-NL',
+		'nn-NO',
+		'oc-FR',
+		'or-IN',
+		'pa-IN',
+		'pl-PL',
+		'ps-AF',
+		'pt-BR',
+		'pt-PT',
+		'rm-CH',
+		'ro-RO',
+		'ru-RU',
+		'rw-RW',
+		'sa-IN',
+		'se-FI',
+		'se-NO',
+		'se-SE',
+		'si-LK',
+		'sk-SK',
+		'sl-SI',
+		'sq-AL',
+		'sv-FI',
+		'sv-SE',
+		'sw-KE',
+		'ta-IN',
+		'te-IN',
+		'th-TH',
+		'tk-TM',
+		'tn-ZA',
+		'tr-TR',
+		'tt-RU',
+		'ug-CN',
+		'uk-UA',
+		'ur-PK',
+		'vi-VN',
+		'wo-SN',
+		'xh-ZA',
+		'yo-NG',
+		'zh-CN',
+		'zh-HK',
+		'zh-MO',
+		'zh-SG',
+		'zh-TW',
+		'zu-ZA',
+	);
+
+	$buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
+	if (in_array($buildprimarykeytotest, $locales)) return strtolower($countrycode).'_'.strtoupper($countrycode);
+
+	foreach ($locales as $locale)
+	{
+		$locale_language = locale_get_primary_language($locale);
+		$locale_region = locale_get_region($locale);
+		if (strtoupper($countrycode) == $locale_region)
+		{
+			//var_dump($locale.'-'.$locale_language.'-'.$locale_region);
+			return strtolower($locale_language).'_'.strtoupper($locale_region);
+		}
+	}
+
+	return null;
+}
+
 /**
  *  Complete or removed entries into a head array (used to build tabs).
  *  For example, with value added by external modules. Such values are declared into $conf->modules_parts['tab'].

+ 3 - 2
htdocs/core/lib/pdf.lib.php

@@ -757,7 +757,7 @@ function pdf_bank(&$pdf,$outputlangs,$curx,$cury,$account,$onlynumber=0,$default
 					$content = $account->number;
 				} elseif ($val == 'BankAccountNumberKey') {
 					// Key
-					$tmplength = 13;
+					$tmplength = 15;
 					$content = $account->cle_rib;
 				}elseif ($val == 'IBAN' || $val == 'BIC') {
 					// Key
@@ -1514,7 +1514,7 @@ function pdf_getlineref_supplier($object,$i,$outputlangs,$hidedetails=0)
  *  @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
  * 	@return	string
  */
-function pdf_getlinevatrate($object,$i,$outputlangs,$hidedetails=0)
+function pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails=0)
 {
 	global $conf, $hookmanager, $mysoc;
 
@@ -1868,6 +1868,7 @@ function pdf_getlineremisepercent($object,$i,$outputlangs,$hidedetails=0)
 function pdf_getlineprogress($object, $i, $outputlangs, $hidedetails = 0, $hookmanager = null)
 {
 	if (empty($hookmanager)) global $hookmanager;
+	global $conf;
 
 	$reshook=0;
     $result='';

+ 1 - 1
htdocs/core/lib/report.lib.php

@@ -91,7 +91,7 @@ function report_header($reportname,$notused,$period,$periodlink,$description,$bu
 	print '<td>'.$langs->trans("ReportPeriod").'</td>';
 	print '<td>';
 	if ($period) print $period;
-	if ($variante) print '<td>'.$periodlink.'</td>';
+	if ($variante) print '<td class="nowraponall">'.$periodlink.'</td>';
 	print '</td>';
 	print '</tr>';
 

+ 8 - 8
htdocs/core/lib/usergroups.lib.php

@@ -822,22 +822,22 @@ function show_theme($fuser,$edit=0,$foruserprofile=false)
 		//print ' &nbsp; ('.$langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis").')';
 		if ($edit)
 		{
-			if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color='edf4fb';
+			if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color='e6edf0';
 			else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_HOVER,array()),'');
 			print $formother->selectColor($color,'THEME_ELDY_USE_HOVER','formcolor',1).' ';
 		}
 		else
 		{
-			if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color='edf4fb';
+			if ($conf->global->THEME_ELDY_USE_HOVER == '1') $color='e6edf0';
 			else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_HOVER,array()),'');
 			if ($color)
 			{
-				if ($color != 'edf4fb') print '<input type="text" class="colorthumb" disabled="disabled" style="padding: 1px; margin-top: 0; margin-bottom: 0; background-color: #'.$color.'" value="'.$color.'">';
+				if ($color != 'e6edf0') print '<input type="text" class="colorthumb" disabled="disabled" style="padding: 1px; margin-top: 0; margin-bottom: 0; background-color: #'.$color.'" value="'.$color.'">';
 				else print $langs->trans("Default");
 			}
 			else print $langs->trans("None");
 		}
-		print ' &nbsp; <span class="nowraponall">('.$langs->trans("Default").': <strong>edf4fb</strong>) ';
+		print ' &nbsp; <span class="nowraponall">('.$langs->trans("Default").': <strong>e6edf0</strong>) ';
 		print $form->textwithpicto('', $langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis"));
 		print '</span>';
 		print '</td>';
@@ -866,22 +866,22 @@ function show_theme($fuser,$edit=0,$foruserprofile=false)
 		//print ' &nbsp; ('.$langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis").')';
 		if ($edit)
 		{
-			if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color='ffefbb';
+			if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color='e6edf0';
 			else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_CHECKED,array()),'');
 			print $formother->selectColor($color,'THEME_ELDY_USE_CHECKED','formcolor',1).' ';
 		}
 		else
 		{
-			if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color='ffefbb';
+			if ($conf->global->THEME_ELDY_USE_CHECKED == '1') $color='e6edf0';
 			else $color = colorArrayToHex(colorStringToArray($conf->global->THEME_ELDY_USE_CHECKED,array()),'');
 			if ($color)
 			{
-				if ($color != 'ffefbb') print '<input type="text" class="colorthumb" disabled="disabled" style="padding: 1px; margin-top: 0; margin-bottom: 0; background-color: #'.$color.'" value="'.$color.'">';
+				if ($color != 'e6edf0') print '<input type="text" class="colorthumb" disabled="disabled" style="padding: 1px; margin-top: 0; margin-bottom: 0; background-color: #'.$color.'" value="'.$color.'">';
 				else print $langs->trans("Default");
 			}
 			else print $langs->trans("None");
 		}
-		print ' &nbsp; <span class="nowraponall">('.$langs->trans("Default").': <strong>ffefbb</strong>) ';
+		print ' &nbsp; <span class="nowraponall">('.$langs->trans("Default").': <strong>e6edf0</strong>) ';
 		print $form->textwithpicto('', $langs->trans("NotSupportedByAllThemes").', '.$langs->trans("PressF5AfterChangingThis"));
 		print '</span>';
 		print '</td>';

+ 47 - 1
htdocs/core/lib/website.lib.php

@@ -35,6 +35,8 @@
  */
 function dolWebsiteReplacementOfLinks($website, $content, $removephppart=0)
 {
+	$nbrep = 0;
+
 	// Replace php code. Note $content may come from database and does not contains body tags.
 	$replacewith='...php...';
 	if ($removephppart) $replacewith='';
@@ -59,7 +61,12 @@ function dolWebsiteReplacementOfLinks($website, $content, $removephppart=0)
 	//$replacewith='<span class="phptag">...php...</span>';
 	$replacewith='<span class="phptag">...php...</span>';
 	if ($removephppart) $replacewith='';
-	$content = preg_replace('/<\?php((?!\?>).)*\?>\n*/ims', $replacewith, $content);
+	//$content = preg_replace('/<\?php((?!\?toremove>).)*\?toremove>\n*/ims', $replacewith, $content);
+	/*if ($content === null) {
+		if (preg_last_error() == PREG_JIT_STACKLIMIT_ERROR) $content = 'preg_replace error (when removing php tags) PREG_JIT_STACKLIMIT_ERROR';
+	}*/
+	$content = dolStripPhpCode($content, $replacewith);
+	//var_dump($content);
 
 	// Replace relative link / with dolibarr URL
 	$content = preg_replace('/(href=")\/\"/', '\1'.DOL_URL_ROOT.'/website/index.php?website='.$website->ref.'&pageid='.$website->fk_default_home.'"', $content, -1, $nbrep);
@@ -88,6 +95,45 @@ function dolWebsiteReplacementOfLinks($website, $content, $removephppart=0)
 }
 
 
+/**
+ * Remove PHP code part from a string.
+ *
+ * @param 	string	$str			String to clean
+ * @param	string	$replacewith	String to use as replacement
+ * @return 	string					Result string without php code
+ */
+function dolStripPhpCode($str, $replacewith='')
+{
+	$newstr = '';
+
+	//split on each opening tag
+	$parts = explode('<?php',$str);
+	if (!empty($parts))
+	{
+		$i=0;
+		foreach($parts as $part)
+		{
+			if ($i == 0) 	// The first part is never php code
+			{
+				$i++;
+				$newstr .= $part;
+				continue;
+			}
+			//split on closing tag
+			$partlings = explode('?>', $part);
+			if (!empty($partlings))
+			{
+				//remove content before closing tag
+				if (count($partlings) > 1) $partlings[0] = '';
+				//append to out string
+				$newstr .= $replacewith.implode('',$partlings);
+			}
+		}
+	}
+	return $newstr;
+}
+
+
 /**
  * Render a string of an HTML content and output it.
  * Used to ouput the page when viewed from server (Dolibarr or Apache).

+ 5 - 9
htdocs/core/modules/DolibarrModules.class.php

@@ -1352,19 +1352,15 @@ class DolibarrModules // Can not be abstract, because we need to instantiate it
 
                         if (! $err) {
                             $sql = "INSERT INTO ".MAIN_DB_PREFIX."cronjob (module_name, datec, datestart, dateend, label, jobtype, classesname, objectname, methodename, command, params, note,";
-                            if(is_int($frequency)) { $sql.= ' frequency,';
-                            }
-                            if(is_int($unitfrequency)) { $sql.= ' unitfrequency,';
-                            }
-                            if(is_int($priority)) { $sql.= ' priority,';
-                            }
-                            if(is_int($status)) { $sql.= ' status,';
-                            }
+                            if (is_int($frequency)) { $sql.= ' frequency,'; }
+                            if (is_int($unitfrequency)) { $sql.= ' unitfrequency,'; }
+                            if (is_int($priority)) { $sql.= ' priority,'; }
+                            if (is_int($status)) { $sql.= ' status,'; }
                             $sql.= " entity, test)";
                             $sql.= " VALUES (";
                             $sql.= "'".$this->db->escape(empty($this->rights_class)?strtolower($this->name):$this->rights_class)."', ";
                             $sql.= "'".$this->db->idate($now)."', ";
-                            $sql.= ($datestart ? "'".$this->db->idate($datestart)."'" : "NULL").", ";
+                            $sql.= ($datestart ? "'".$this->db->idate($datestart)."'" : "'".$this->db->idate($now)."'").", ";
                             $sql.= ($dateend   ? "'".$this->db->idate($dateend)."'"   : "NULL").", ";
                             $sql.= "'".$this->db->escape($label)."', ";
                             $sql.= "'".$this->db->escape($jobtype)."', ";

+ 66 - 20
htdocs/core/modules/contract/doc/pdf_strato.modules.php

@@ -6,6 +6,7 @@
  * Copyright (C) 2011		Fabrice CHERRIER
  * Copyright (C) 2013-2018  Philippe Grand	            <philippe.grand@atoo-net.com>
  * Copyright (C) 2015       Marcos García               <marcosgdf@gmail.com>
+ * Copyright (C) 2018       Frédéric France             <frederic.france@netlogic.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
@@ -357,10 +358,43 @@ class pdf_strato extends ModelePDFContract
                         $txt.=$outputlangs->transnoentities("DateStartRealShort")." : <strong>".$daters.'</strong>';
 						if ($objectligne->date_cloture) $txt.=" - ".$outputlangs->transnoentities("DateEndRealShort")." : '<strong>'".$datere.'</strong>';
 
+						$pdf->startTransaction();
 						$pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txtpredefinedservice, dol_concatdesc($txt, $desc)), 0, 1, 0);
+						$pageposafter=$pdf->getPage();
+						if ($pageposafter > $pageposbefore)	// There is a pagebreak
+						{
+							$pdf->rollbackTransaction(true);
+							$pageposafter=$pageposbefore;
+							//print $pageposafter.'-'.$pageposbefore;exit;
+							$pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
+							$pdf->writeHTMLCell(0, 0, $curX, $curY, dol_concatdesc($txtpredefinedservice, dol_concatdesc($txt, $desc)), 0, 1, 0);
+							$pageposafter=$pdf->getPage();
+							$posyafter=$pdf->GetY();
+							
+							if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot)))	// There is no space left for total+free text
+							{
+								if ($i == ($nblines-1))	// No more lines, and no space left to show total, so we create a new page
+								{
+									$pdf->AddPage('','',true);
+									if (! empty($tplidx)) $pdf->useTemplate($tplidx);
+									if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
+									$pdf->setPage($pageposafter+1);
+								}
+							}
+							else
+							{
+								// We found a page break
+								$showpricebeforepagebreak=0;
+							}
+						}
+						else	// No pagebreak
+						{
+							$pdf->commitTransaction();
+						}
 
 						$nexY = $pdf->GetY() + 2;
 						$pageposafter=$pdf->getPage();
+						
 						$pdf->setPage($pageposbefore);
 						$pdf->setTopMargin($this->marge_haute);
 						$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
@@ -378,26 +412,27 @@ class pdf_strato extends ModelePDFContract
 							$pdf->setPage($pagenb);
 							if ($pagenb == 1)
 							{
-								$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1);
+								$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext, 0, $outputlangs, 0, 1);
 							}
 							else
 							{
-								$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1);
+								$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter - $heightforfreetext, 0, $outputlangs, 1, 1);
 							}
 							$this->_pagefoot($pdf,$object,$outputlangs,1);
 							$pagenb++;
 							$pdf->setPage($pagenb);
 							$pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
 						}
+						
 						if (isset($object->lines[$i+1]->pagebreak) && $object->lines[$i+1]->pagebreak)
 						{
 							if ($pagenb == 1)
 							{
-								$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter, 0, $outputlangs, 0, 1);
+								$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforfooter - $heightforfreetext, 0, $outputlangs, 0, 1);
 							}
 							else
 							{
-								$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter, 0, $outputlangs, 1, 1);
+								$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforfooter - $heightforfreetext, 0, $outputlangs, 1, 1);
 							}
 							$this->_pagefoot($pdf,$object,$outputlangs,1);
 							// New page
@@ -412,14 +447,16 @@ class pdf_strato extends ModelePDFContract
 				if ($pagenb == 1)
 				{
 					$this->_tableau($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0);
+					$this->_tab_signature($pdf, $tab_top, $this->page_hauteur - $tab_top - $heightforinfotot - $heightforfreetext - $heightforfooter, $outputlangs);
 					$bottomlasttab=$this->page_hauteur - $heightforfooter - $heightforfooter + 1;
 				}
 				else
 				{
-					$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 1, 0);
+					$this->_tableau($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, 0, $outputlangs, 0, 0);
+					$this->tabSignature($pdf, $tab_top_newpage, $this->page_hauteur - $tab_top_newpage - $heightforinfotot - $heightforfreetext - $heightforfooter, $outputlangs);
 					$bottomlasttab=$this->page_hauteur - $heightforfooter - $heightforfooter + 1;
 				}
-
+				
 				$this->_pagefoot($pdf,$object,$outputlangs);
 				if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages();
 
@@ -506,25 +543,34 @@ class pdf_strato extends ModelePDFContract
 */
 
 		// Output Rect
-		$this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height+3, $hidetop, $hidebottom);	// Rect prend une longueur en 3eme param et 4eme param
+		$this->printRect($pdf, $this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height+3);	// Rect prend une longueur en 3eme param et 4eme param
+	}
 
-		if (empty($hidebottom))
-		{
-			$posmiddle = $this->marge_gauche + round(($this->page_largeur - $this->marge_gauche - $this->marge_droite)/2);
-			$posy = $tab_top + $tab_height + 3 + 3;
+    /**
+     * Show footer signature of page
+     * @param   PDF         $pdf            Object PDF
+     * @param   int         $tab_top        tab height position
+     * @param   int         $tab_height     tab height
+     * @param   Translate   $outputlangs    Object language for output
+     * @return void
+     */
+	private function tabSignature(&$pdf, $tab_top, $tab_height, $outputlangs)
+    {
+		$pdf->SetDrawColor(128,128,128);
+		$posmiddle = $this->marge_gauche + round(($this->page_largeur - $this->marge_gauche - $this->marge_droite)/2);
+		$posy = $tab_top + $tab_height + 3 + 3;
 
-			$pdf->SetXY($this->marge_gauche, $posy);
-			$pdf->MultiCell($posmiddle - $this->marge_gauche - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $this->emetteur->name),0,'L',0);
+		$pdf->SetXY($this->marge_gauche, $posy);
+		$pdf->MultiCell($posmiddle - $this->marge_gauche - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $this->emetteur->name),0,'L',0);
 
-			$pdf->SetXY($this->marge_gauche, $posy + 5);
-			$pdf->MultiCell($posmiddle - $this->marge_gauche - 5, 20, '', 1);
+		$pdf->SetXY($this->marge_gauche, $posy + 5);
+		$pdf->MultiCell($posmiddle - $this->marge_gauche - 5, 20, '', 1);
 
-			$pdf->SetXY($posmiddle + 5, $posy);
-			$pdf->MultiCell($this->page_largeur-$this->marge_droite - $posmiddle - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $this->recipient->name),0,'L',0);
+		$pdf->SetXY($posmiddle + 5, $posy);
+		$pdf->MultiCell($this->page_largeur-$this->marge_droite - $posmiddle - 5, 5, $outputlangs->transnoentities("ContactNameAndSignature", $this->recipient->name),0,'L',0);
 
-			$pdf->SetXY($posmiddle + 5, $posy + 5);
-			$pdf->MultiCell($this->page_largeur-$this->marge_droite - $posmiddle - 5, 20, '', 1);
-		}
+		$pdf->SetXY($posmiddle + 5, $posy + 5);
+		$pdf->MultiCell($this->page_largeur-$this->marge_droite - $posmiddle - 5, 20, '', 1);
 	}
 
 	/**

+ 41 - 15
htdocs/core/modules/expedition/doc/doc_generic_shipment_odt.modules.php

@@ -289,9 +289,9 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 				dol_mkdir($conf->expedition->dir_temp);
 
 
-				// If BILLING contact defined on invoice, we use it
+				// If SHIPMENT contact defined on invoice, we use it
 				$usecontact=false;
-				$arrayidcontact=$object->getIdContact('external','BILLING');
+				$arrayidcontact=$object->getIdContact('external','SHIPPING');
 				if (count($arrayidcontact) > 0)
 				{
 					$usecontact=true;
@@ -299,24 +299,27 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
 				}
 
 				// Recipient name
-				if (! empty($usecontact))
-				{
+				$contactobject = null;
+				if (! empty($usecontact)) {
 					// On peut utiliser le nom de la societe du contact
-					if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact;
-					else $socobject = $object->thirdparty;
-				}
-				else
-				{
-					$socobject=$object->thirdparty;
+					if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT))
+						$socobject = $object->contact;
+					else {
+						$socobject = $object->thirdparty;
+						// if we have a SHIIPPING contact and we dont use it as recipient we store the contact object for later use
+						$contactobject = $object->contact;
+					}
+				} else {
+					$socobject = $object->thirdparty;
 				}
 
 				// Make substitution
 				$substitutionarray=array(
-				'__FROM_NAME__' => $this->emetteur->name,
-				'__FROM_EMAIL__' => $this->emetteur->email,
-				'__TOTAL_TTC__' => $object->total_ttc,
-				'__TOTAL_HT__' => $object->total_ht,
-				'__TOTAL_VAT__' => $object->total_vat
+					'__FROM_NAME__' => $this->emetteur->name,
+					'__FROM_EMAIL__' => $this->emetteur->email,
+					'__TOTAL_TTC__' => $object->total_ttc,
+					'__TOTAL_HT__' => $object->total_ht,
+					'__TOTAL_VAT__' => $object->total_vat
 				);
 				complete_substitutions_array($substitutionarray, $langs, $object);
 				// Call the ODTSubstitution hook
@@ -430,6 +433,29 @@ class doc_generic_shipment_odt extends ModelePdfExpedition
                         dol_syslog($e->getMessage(), LOG_INFO);
 					}
 				}
+
+				if ($usecontact && is_object($contactobject)) {
+					$tmparray=$this->get_substitutionarray_contact($contactobject,$outputlangs,'contact');
+					foreach($tmparray as $key=>$value)
+					{
+						try {
+							if (preg_match('/logo$/',$key))	// Image
+							{
+								if (file_exists($value)) $odfHandler->setImage($key, $value);
+								else $odfHandler->setVars($key, 'ErrorFileNotFound', true, 'UTF-8');
+							}
+							else	// Text
+							{
+								$odfHandler->setVars($key, $value, true, 'UTF-8');
+							}
+						}
+						catch(OdfException $e)
+						{
+                            dol_syslog($e->getMessage(), LOG_INFO);
+						}
+					}
+				}
+
 				// Replace tags of object + external modules
 				$tmparray=$this->get_substitutionarray_shipment($object,$outputlangs);
 				complete_substitutions_array($tmparray, $outputlangs, $object);

+ 206 - 182
htdocs/core/modules/expensereport/doc/pdf_standard.modules.php

@@ -1,7 +1,8 @@
 <?php
-/* Copyright (C) 2015 Laurent Destailleur    <eldy@users.sourceforge.net>
- * Copyright (C) 2015 Alexandre Spangaro     <aspangaro.dolibarr@gmail.com>
- * Copyright (C) 2016-2018 Philippe Grand	 <philippe.grand@atoo-net.com>
+/* Copyright (C) 2015       Laurent Destailleur     <eldy@users.sourceforge.net>
+ * Copyright (C) 2015       Alexandre Spangaro      <aspangaro.dolibarr@gmail.com>
+ * Copyright (C) 2016-2018  Philippe Grand          <philippe.grand@atoo-net.com>
+ * Copyright (C) 2018       Frédéric France         <frederic.france@netlogic.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
@@ -150,7 +151,7 @@ class pdf_standard extends ModeleExpenseReport
 		$this->option_freetext = 1;				   // Support add of a personalised text
 		$this->option_draft_watermark = 1;		   // Support add of a watermark on drafts
 
-		$this->franchise=!$mysoc->tva_assuj;
+		$this->franchise = !$mysoc->tva_assuj;
 
 		// Get source company
 		$this->emetteur=$mysoc;
@@ -159,19 +160,19 @@ class pdf_standard extends ModeleExpenseReport
 		// Define position of columns
 		$this->posxpiece=$this->marge_gauche+1;
 		$this->posxcomment=$this->marge_gauche+10;
-		$this->posxdate=88;
-		$this->posxtype=107;
-		$this->posxprojet=120;
-		$this->posxtva=138;
-		$this->posxup=154;
+		//$this->posxdate=88;
+		//$this->posxtype=107;
+		//$this->posxprojet=120;
+		$this->posxtva=130;
+		$this->posxup=145;
 		$this->posxqty=168;
 		$this->postotalttc=178;
-        if (empty($conf->projet->enabled)) {
-            $this->posxtva-=20;
-            $this->posxup-=20;
-            $this->posxqty-=20;
-            $this->postotalttc-=20;
-        }
+        // if (empty($conf->projet->enabled)) {
+        //     $this->posxtva-=20;
+        //     $this->posxup-=20;
+        //     $this->posxqty-=20;
+        //     $this->postotalttc-=20;
+        // }
 		if ($this->page_largeur < 210) // To work with US executive format
 		{
 			$this->posxdate-=20;
@@ -202,10 +203,10 @@ class pdf_standard extends ModeleExpenseReport
      *  @param		int			$hideref			Do not show ref
      *  @return     int             				1=OK, 0=KO
 	 */
-	function write_file($object,$outputlangs,$srctemplatepath='',$hidedetails=0,$hidedesc=0,$hideref=0)
+	function write_file($object, $outputlangs, $srctemplatepath = '', $hidedetails = 0, $hidedesc = 0, $hideref = 0)
 	{
         // phpcs:enable
-		global $user,$langs,$conf,$mysoc,$db,$hookmanager;
+		global $user, $langs, $conf, $mysoc, $db, $hookmanager;
 
 		if (! is_object($outputlangs)) $outputlangs=$langs;
 		// For backward compatibility with FPDF, force output charset to ISO, because FPDF expect text to be encoded in ISO
@@ -216,11 +217,9 @@ class pdf_standard extends ModeleExpenseReport
 
 		$nblignes = count($object->lines);
 
-		if ($conf->expensereport->dir_output)
-		{
+		if ($conf->expensereport->dir_output) {
 			// Definition of $dir and $file
-			if ($object->specimen)
-			{
+			if ($object->specimen) {
 				$dir = $conf->expensereport->dir_output;
 				$file = $dir . "/SPECIMEN.pdf";
 			}
@@ -258,7 +257,7 @@ class pdf_standard extends ModeleExpenseReport
 				$default_font_size = pdf_getPDFFontSize($outputlangs);	// Must be after pdf_getInstance
 				$heightforinfotot = 40;	// Height reserved to output the info and total part
 		        $heightforfreetext= (isset($conf->global->MAIN_PDF_FREETEXT_HEIGHT)?$conf->global->MAIN_PDF_FREETEXT_HEIGHT:5);	// Height reserved to output the free text on last page
-	            $heightforfooter = $this->marge_basse + 8;	// Height reserved to output the footer (value include bottom margin)
+	            $heightforfooter = $this->marge_basse + 12;	// Height reserved to output the footer (value include bottom margin)
                 $pdf->SetAutoPageBreak(1,0);
 
                 if (class_exists('TCPDF'))
@@ -344,82 +343,47 @@ class pdf_standard extends ModeleExpenseReport
 				$nexY = $tab_top + 7;
 
 				// Loop on each lines
-				for ($i = 0 ; $i < $nblignes ; $i++)
-				{
-					$piece_comptable = $i +1;
-
+				for ($i = 0 ; $i < $nblignes ; $i++) {
 					$pdf->SetFont('','', $default_font_size - 2);   // Into loop to work with multipage
 					$pdf->SetTextColor(0,0,0);
 
 					$pdf->setTopMargin($tab_top_newpage);
 					$pdf->setPageOrientation('', 1, $heightforfooter+$heightforfreetext+$heightforinfotot);	// The only function to edit the bottom margin of current page to set it.
-					$pageposbefore=$pdf->getPage();
+					$pageposbefore = $pdf->getPage();
                     $curY = $nexY;
-
-					$pdf->SetFont('','', $default_font_size - 1);
-
-                    // Accountancy piece
-                    $pdf->SetXY($this->posxpiece, $curY);
-                    $pdf->writeHTMLCell($this->posxcomment-$this->posxpiece-0.8, 4, $this->posxpiece-1, $curY, $piece_comptable, 0, 1);
-                    $curY = ($pdf->PageNo() > $pageposbefore) ? $pdf->GetY()-4 : $curY;
-
-                    // Comments
-                    $pdf->SetXY($this->posxcomment, $curY );
-                    $pdf->writeHTMLCell($this->posxdate-$this->posxcomment-0.8, 4, $this->posxcomment-1, $curY, $object->lines[$i]->comments, 0, 1);
-                    $curY = ($pdf->PageNo() > $pageposbefore) ? $pdf->GetY()-4 : $curY;
-
-                    // Date
-					$pdf->SetXY($this->posxdate -1, $curY);
-					$pdf->MultiCell($this->posxtype-$this->posxdate-0.8, 4, dol_print_date($object->lines[$i]->date,"day",false,$outputlangs), 0, 'C');
-
-                    // Type
-					$pdf->SetXY($this->posxtype -1, $curY);
-					$nextColumnPosX = $this->posxup;
-                    if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
-                        $nextColumnPosX = $this->posxtva;
-                    }
-                    if (!empty($conf->projet->enabled)) {
-                        $nextColumnPosX = $this->posxprojet;
-                    }
-
-                    $expensereporttypecode = $object->lines[$i]->type_fees_code;
-                    $expensereporttypecodetoshow = $outputlangs->transnoentities($expensereporttypecode);
-                    if ($expensereporttypecodetoshow == $expensereporttypecode)
-                    {
-                    	$expensereporttypecodetoshow = preg_replace('/^(EX_|TF_)/', '', $expensereporttypecodetoshow);
-                    }
-                    $expensereporttypecodetoshow = dol_trunc($expensereporttypecodetoshow, 9);	// 10 is too much
-
-                    $pdf->MultiCell($nextColumnPosX-$this->posxtype-0.8, 4, $expensereporttypecodetoshow, 0, 'C');
-
-                    // Project
-					if (! empty($conf->projet->enabled))
-					{
-                        $pdf->SetFont('','', $default_font_size - 1);
-                        $pdf->SetXY($this->posxprojet, $curY);
-                        $pdf->MultiCell($this->posxtva-$this->posxprojet-0.8, 4, $object->lines[$i]->projet_ref, 0, 'C');
-                    }
-
-					// VAT Rate
-					if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
+                    $pdf->startTransaction();
+                    $this->printLine($pdf, $object, $i, $curY, $default_font_size, $outputlangs, $hidedetails);
+                    $pageposafter=$pdf->getPage();
+					if ($pageposafter > $pageposbefore) {
+                        // There is a pagebreak
+						$pdf->rollbackTransaction(true);
+						$pageposafter = $pageposbefore;
+						//print $pageposafter.'-'.$pageposbefore;exit;
+						$pdf->setPageOrientation('', 1, $heightforfooter);	// The only function to edit the bottom margin of current page to set it.
+						$this->printLine($pdf, $object, $i, $curY, $default_font_size, $outputlangs, $hidedetails);
+						$pageposafter = $pdf->getPage();
+						$posyafter = $pdf->GetY();
+						//var_dump($posyafter); var_dump(($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))); exit;
+						if ($posyafter > ($this->page_hauteur - ($heightforfooter+$heightforfreetext+$heightforinfotot))) {
+                            // There is no space left for total+free text
+							if ($i == ($nblignes-1)) {
+                                // No more lines, and no space left to show total, so we create a new page
+								$pdf->AddPage('', '', true);
+								if (! empty($tplidx)) $pdf->useTemplate($tplidx);
+								if (empty($conf->global->MAIN_PDF_DONOTREPEAT_HEAD)) $this->_pagehead($pdf, $object, 0, $outputlangs);
+								$pdf->setPage($pageposafter+1);
+							}
+						}
+						else
+						{
+							// We found a page break
+							$showpricebeforepagebreak=0;
+						}
+					}
+					else	// No pagebreak
 					{
-						$vat_rate = pdf_getlinevatrate($object, $i, $outputlangs, $hidedetails);
-						$pdf->SetXY($this->posxtva, $curY);
-						$pdf->MultiCell($this->posxup-$this->posxtva-0.8, 4,$vat_rate, 0, 'C');
-                    }
-
-					// Unit price
-					$pdf->SetXY($this->posxup, $curY);
-					$pdf->MultiCell($this->posxqty-$this->posxup-0.8, 4,price($object->lines[$i]->value_unit), 0, 'R');
-
-                    // Quantity
-					$pdf->SetXY($this->posxqty, $curY);
-					$pdf->MultiCell($this->postotalttc-$this->posxqty-0.8, 4,$object->lines[$i]->qty, 0, 'R');
-
-                    // Total with all taxes
-					$pdf->SetXY($this->postotalttc-1, $curY);
-					$pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalttc, 4, price($object->lines[$i]->total_ttc), 0, 'R');
-
+						$pdf->commitTransaction();
+					}
                     //nexY
                     $nexY = $pdf->GetY();
                     $pageposafter=$pdf->getPage();
@@ -427,22 +391,23 @@ class pdf_standard extends ModeleExpenseReport
                     $pdf->setTopMargin($this->marge_haute);
                     $pdf->setPageOrientation('', 1, 0);	// The only function to edit the bottom margin of current page to set it.
 
-                    $nblineFollowComment = 1;
+                    //$nblineFollowComment = 1;
                     // Cherche nombre de lignes a venir pour savoir si place suffisante
-					if ($i < ($nblignes - 1))	// If it's not last line
-					{
-					    //Fetch current description to know on which line the next one should be placed
-						$follow_comment = $object->lines[$i]->comments;
-						$follow_type = $object->lines[$i]->type_fees_code;
+					// if ($i < ($nblignes - 1))	// If it's not last line
+					// {
+					//     //Fetch current description to know on which line the next one should be placed
+					// 	$follow_comment = $object->lines[$i]->comments;
+					// 	$follow_type = $object->lines[$i]->type_fees_code;
 
-						//on compte le nombre de ligne afin de verifier la place disponible (largeur de ligne 52 caracteres)
-						$nbLineCommentNeed = dol_nboflines_bis($follow_comment,52,$outputlangs->charset_output);
-						$nbLineTypeNeed = dol_nboflines_bis($follow_type,4,$outputlangs->charset_output);
+					// 	//on compte le nombre de ligne afin de verifier la place disponible (largeur de ligne 52 caracteres)
+					// 	$nbLineCommentNeed = dol_nboflines_bis($follow_comment,52,$outputlangs->charset_output);
+					// 	$nbLineTypeNeed = dol_nboflines_bis($follow_type,4,$outputlangs->charset_output);
 
-                        $nblineFollowComment = max($nbLineCommentNeed, $nbLineTypeNeed);
-					}
+                    //     $nblineFollowComment = max($nbLineCommentNeed, $nbLineTypeNeed);
+					// }
 
-                    $nexY+=$nblineFollowComment*($pdf->getFontSize()*1.3);    // Passe espace entre les lignes
+                    //$nexY+=$nblineFollowComment*($pdf->getFontSize()*1.3);    // Passe espace entre les lignes
+                    $nexY += ($pdf->getFontSize()*1.3);    // Passe espace entre les lignes
 
 					// Detect if some page were added automatically and output _tableau for past pages
 					while ($pagenb < $pageposafter)
@@ -524,7 +489,7 @@ class pdf_standard extends ModeleExpenseReport
 
 				// Pied de page
 				$this->_pagefoot($pdf,$object,$outputlangs);
-				if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPages();
+				if (method_exists($pdf,'AliasNbPages')) $pdf->AliasNbPage();
 
 				$pdf->Close();
 
@@ -556,7 +521,87 @@ class pdf_standard extends ModeleExpenseReport
 		}
 	}
 
-	/**
+    /**
+     * @param   TCPDF       $pdf                Object PDF
+     * @param   Object      $object             Object to show
+     * @param   int         $linenumber         line number
+     * @param   int         $curY               current y position
+     * @param   int         $default_font_size  default siez of font
+     * @param   Translate   $outputlangs        Object lang for output
+     * @param	int			$hidedetails		Hide details (0=no, 1=yes, 2=just special lines)
+     * @return  void
+     */
+	private function printLine(&$pdf, $object, $linenumber, $curY, $default_font_size, $outputlangs, $hidedetails=0)
+	{
+        global $conf;
+        $pdf->SetFont('','', $default_font_size - 1);
+
+        // Accountancy piece
+        $pdf->SetXY($this->posxpiece, $curY);
+        $pdf->writeHTMLCell($this->posxcomment-$this->posxpiece-0.8, 4, $this->posxpiece-1, $curY, $linenumber + 1, 0, 1);
+
+        // Date
+        //$pdf->SetXY($this->posxdate -1, $curY);
+        //$pdf->MultiCell($this->posxtype-$this->posxdate-0.8, 4, dol_print_date($object->lines[$linenumber]->date,"day",false,$outputlangs), 0, 'C');
+
+        // Type
+        $pdf->SetXY($this->posxtype -1, $curY);
+        $nextColumnPosX = $this->posxup;
+        if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
+            $nextColumnPosX = $this->posxtva;
+        }
+        if (!empty($conf->projet->enabled)) {
+            $nextColumnPosX = $this->posxprojet;
+        }
+
+        $expensereporttypecode = $object->lines[$linenumber]->type_fees_code;
+        $expensereporttypecodetoshow = $outputlangs->trans($expensereporttypecode);
+        if ($expensereporttypecodetoshow == $expensereporttypecode) {
+            $expensereporttypecodetoshow = preg_replace('/^(EX_|TF_)/', '', $expensereporttypecodetoshow);
+        }
+        //$expensereporttypecodetoshow = dol_trunc($expensereporttypecodetoshow, 9);
+
+        //$pdf->MultiCell($nextColumnPosX-$this->posxtype-0.8, 4, $expensereporttypecodetoshow, 0, 'C');
+
+        // Project
+        //if (! empty($conf->projet->enabled))
+        //{
+        //    $pdf->SetFont('','', $default_font_size - 1);
+        //    $pdf->SetXY($this->posxprojet, $curY);
+        //    $pdf->MultiCell($this->posxtva-$this->posxprojet-0.8, 4, $object->lines[$linenumber]->projet_ref, 0, 'C');
+        //}
+
+        // VAT Rate
+        if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
+            $vat_rate = pdf_getlinevatrate($object, $linenumber, $outputlangs, $hidedetails);
+            $pdf->SetXY($this->posxtva, $curY);
+            $pdf->MultiCell($this->posxup-$this->posxtva-0.8, 4,$vat_rate, 0, 'R');
+        }
+
+        // Unit price
+        $pdf->SetXY($this->posxup, $curY);
+        $pdf->MultiCell($this->posxqty-$this->posxup-0.8, 4,price($object->lines[$linenumber]->value_unit), 0, 'R');
+
+        // Quantity
+        $pdf->SetXY($this->posxqty, $curY);
+        $pdf->MultiCell($this->postotalttc-$this->posxqty-0.8, 4,$object->lines[$linenumber]->qty, 0, 'R');
+
+        // Total with all taxes
+        $pdf->SetXY($this->postotalttc-1, $curY);
+        $pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalttc, 4, price($object->lines[$linenumber]->total_ttc), 0, 'R');
+
+        // Comments
+        $pdf->SetXY($this->posxcomment, $curY );
+        $comment = $outputlangs->trans("Date").':'. dol_print_date($object->lines[$linenumber]->date,"day",false,$outputlangs).' ';
+        $comment .= $outputlangs->trans("Type").':'. $expensereporttypecodetoshow.'<br>';
+        if (! empty($object->lines[$linenumber]->projet_ref)) {
+            $comment .= $outputlangs->trans("Project").':'. $object->lines[$linenumber]->projet_ref.'<br>';
+        }
+        $comment .= $object->lines[$linenumber]->comments;
+        $pdf->writeHTMLCell($this->posxtva-$this->posxcomment-0.8, 4, $this->posxcomment-1, $curY, $comment, 0, 1);
+    }
+
+    /**
 	 *  Show top header of page.
 	 *
 	 *  @param	PDF			$pdf     		Object PDF
@@ -583,13 +628,12 @@ class pdf_standard extends ModeleExpenseReport
 		*/
 
 	    // Draft watermark
-		if ($object->fk_statut == 0 && ! empty($conf->global->EXPENSEREPORT_DRAFT_WATERMARK))
-		{
+		if ($object->fk_statut == 0 && ! empty($conf->global->EXPENSEREPORT_DRAFT_WATERMARK)) {
  			pdf_watermark($pdf,$outputlangs,$this->page_hauteur,$this->page_largeur,'mm',$conf->global->EXPENSEREPORT_DRAFT_WATERMARK);
 		}
 
-		$pdf->SetTextColor(0,0,60);
-		$pdf->SetFont('','B', $default_font_size + 3);
+		$pdf->SetTextColor(0, 0, 60);
+		$pdf->SetFont('', 'B', $default_font_size + 3);
 
 		$posy=$this->marge_haute;
 		$posx=$this->page_largeur-$this->marge_droite-100;
@@ -597,16 +641,12 @@ class pdf_standard extends ModeleExpenseReport
 		$pdf->SetXY($this->marge_gauche,$posy);
 
 		// Logo
-		$logo=$conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
-		if ($this->emetteur->logo)
-		{
-			if (is_readable($logo))
-			{
+		$logo = $conf->mycompany->dir_output.'/logos/'.$this->emetteur->logo;
+		if ($this->emetteur->logo) {
+			if (is_readable($logo)) {
 			    $height=pdf_getHeightForLogo($logo);
 			    $pdf->Image($logo, $this->marge_gauche, $posy, 0, $height);	// width=0 (auto)
-			}
-			else
-			{
+			} else {
 				$pdf->SetTextColor(200,0,0);
 				$pdf->SetFont('','B', $default_font_size -2);
 				$pdf->MultiCell(100, 3, $outputlangs->transnoentities("ErrorLogoFileNotFound",$logo), 0, 'L');
@@ -651,8 +691,7 @@ class pdf_standard extends ModeleExpenseReport
    		$pdf->SetTextColor(111,81,124);
 		$pdf->MultiCell($this->page_largeur-$this->marge_droite-$posx, 3, $object->getLibStatut(0), '', 'R');
 
-		if ($showaddress)
-		{
+		if ($showaddress) {
 			// Sender properties
 			$carac_emetteur = '';
 			$carac_emetteur .= ($carac_emetteur ? "\n" : '' ).$outputlangs->convToOutputCharset($this->emetteur->address);
@@ -674,14 +713,14 @@ class pdf_standard extends ModeleExpenseReport
 			if (! empty($conf->global->MAIN_INVERT_SENDER_RECIPIENT)) $posx=118;
 
 			// Show sender frame
-			$pdf->SetTextColor(0,0,0);
+			$pdf->SetTextColor(0, 0, 0);
 			$pdf->SetFont('','B', $default_font_size - 2);
 			$pdf->SetXY($posx,$posy-5);
 			$pdf->MultiCell(66,5, $outputlangs->transnoentities("TripSociete")." :",'','L');
 			$pdf->SetXY($posx,$posy);
 			$pdf->SetFillColor(224,224,224);
 			$pdf->MultiCell(82, $hautcadre, "", 0, 'R', 1);
-			$pdf->SetTextColor(0,0,60);
+			$pdf->SetTextColor(0, 0, 60);
 
 			// Show sender name
 			$pdf->SetXY($posx+2,$posy+3);
@@ -690,7 +729,7 @@ class pdf_standard extends ModeleExpenseReport
 
 			// Show sender information
 			$pdf->SetXY($posx+2,$posy+8);
-			$pdf->SetFont('','', $default_font_size - 1);
+			$pdf->SetFont('', '', $default_font_size - 1);
 			$pdf->MultiCell(80, 4, $carac_emetteur, 0, 'L');
 
 			// Show recipient
@@ -698,15 +737,14 @@ class pdf_standard extends ModeleExpenseReport
 			$posx=100;
 
 			// Show recipient frame
-			$pdf->SetTextColor(0,0,0);
-			$pdf->SetFont('','B',8);
+			$pdf->SetTextColor(0, 0, 0);
+			$pdf->SetFont('', 'B', 8);
 			$pdf->SetXY($posx,$posy-5);
-			$pdf->MultiCell(80,5, $outputlangs->transnoentities("TripNDF")." :", 0, 'L');
+			$pdf->MultiCell(80, 5, $outputlangs->transnoentities("TripNDF")." :", 0, 'L');
 			$pdf->rect($posx, $posy, $this->page_largeur - $this->marge_gauche - $posx, $hautcadre);
 
 			// Informations for trip (dates and users workflow)
-			if ($object->fk_user_author > 0)
-			{
+			if ($object->fk_user_author > 0) {
 				$userfee=new User($this->db);
 				$userfee->fetch($object->fk_user_author); $posy+=3;
 				$pdf->SetXY($posx+2,$posy);
@@ -719,8 +757,7 @@ class pdf_standard extends ModeleExpenseReport
 
 			if ($object->fk_statut==99)
 			{
-				if ($object->fk_user_refuse > 0)
-				{
+				if ($object->fk_user_refuse > 0) {
 					$userfee=new User($this->db);
 					$userfee->fetch($object->fk_user_refuse); $posy+=6;
 					$pdf->SetXY($posx+2,$posy);
@@ -735,8 +772,7 @@ class pdf_standard extends ModeleExpenseReport
 			}
 			else if($object->fk_statut==4)
 			{
-				if ($object->fk_user_cancel > 0)
-				{
+				if ($object->fk_user_cancel > 0) {
 					$userfee=new User($this->db);
 					$userfee->fetch($object->fk_user_cancel); $posy+=6;
 					$pdf->SetXY($posx+2,$posy);
@@ -751,8 +787,7 @@ class pdf_standard extends ModeleExpenseReport
 			}
 			else
 			{
-				if ($object->fk_user_approve > 0)
-				{
+				if ($object->fk_user_approve > 0) {
 					$userfee=new User($this->db);
 					$userfee->fetch($object->fk_user_approve); $posy+=6;
 					$pdf->SetXY($posx+2,$posy);
@@ -763,10 +798,8 @@ class pdf_standard extends ModeleExpenseReport
 				}
 			}
 
-			if($object->fk_statut==6)
-			{
-				if ($object->fk_user_paid > 0)
-				{
+			if($object->fk_statut==6) {
+				if ($object->fk_user_paid > 0) {
 					$userfee=new User($this->db);
 					$userfee->fetch($object->fk_user_paid); $posy+=6;
 					$pdf->SetXY($posx+2,$posy);
@@ -805,8 +838,8 @@ class pdf_standard extends ModeleExpenseReport
 
 		// Amount in (at tab_top - 1)
 		$pdf->SetTextColor(0,0,0);
-		$pdf->SetFont('','', $default_font_size - 2);
-		$titre = $outputlangs->transnoentities("AmountInCurrency",$outputlangs->transnoentitiesnoconv("Currency".$currency));
+		$pdf->SetFont('', '', $default_font_size - 2);
+		$titre = $outputlangs->transnoentities("AmountInCurrency", $outputlangs->transnoentitiesnoconv("Currency".$currency));
 		$pdf->SetXY($this->page_largeur - $this->marge_droite - ($pdf->GetStringWidth($titre) + 4), $tab_top -4);
 		$pdf->MultiCell(($pdf->GetStringWidth($titre) + 3), 2, $titre);
 
@@ -815,61 +848,55 @@ class pdf_standard extends ModeleExpenseReport
 		// Rect prend une longueur en 3eme param
 		$pdf->Rect($this->marge_gauche, $tab_top, $this->page_largeur-$this->marge_gauche-$this->marge_droite, $tab_height);
 		// line prend une position y en 3eme param
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->line($this->marge_gauche, $tab_top+5, $this->page_largeur-$this->marge_droite, $tab_top+5);
 		}
 
 		$pdf->SetFont('','',8);
 
 		// Accountancy piece
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->SetXY($this->posxpiece-1, $tab_top+1);
-			$pdf->MultiCell($this->posxcomment-$this->posxpiece-1,1,'','','R');
+			$pdf->MultiCell($this->posxcomment-$this->posxpiece-1, 1, '', '', 'R');
 		}
 
 		// Comments
 		$pdf->line($this->posxcomment-1, $tab_top, $this->posxcomment-1, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->SetXY($this->posxcomment-1, $tab_top+1);
-			$pdf->MultiCell($this->posxdate-$this->posxcomment-1,1,$outputlangs->transnoentities("Description"),'','L');
+			$pdf->MultiCell($this->posxdate-$this->posxcomment-1, 1, $outputlangs->transnoentities("Description"),'','L');
 		}
 
 		// Date
-		$pdf->line($this->posxdate-1, $tab_top, $this->posxdate-1, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
-			$pdf->SetXY($this->posxdate-1, $tab_top+1);
-			$pdf->MultiCell($this->posxtype-$this->posxdate-1,2, $outputlangs->transnoentities("Date"),'','C');
-		}
+		//$pdf->line($this->posxdate-1, $tab_top, $this->posxdate-1, $tab_top + $tab_height);
+		//if (empty($hidetop))
+		//{
+		//	$pdf->SetXY($this->posxdate-1, $tab_top+1);
+		//	$pdf->MultiCell($this->posxtype-$this->posxdate-1,2, $outputlangs->transnoentities("Date"),'','C');
+		//}
 
 		// Type
-		$pdf->line($this->posxtype-1, $tab_top, $this->posxtype-1, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
-			$pdf->SetXY($this->posxtype-1, $tab_top+1);
-			$pdf->MultiCell($this->posxprojet-$this->posxtype - 1, 2, $outputlangs->transnoentities("Type"), '', 'C');
-		}
-
-        if (!empty($conf->projet->enabled))
-        {
-            // Project
-            $pdf->line($this->posxprojet - 1, $tab_top, $this->posxprojet - 1, $tab_top + $tab_height);
-    		if (empty($hidetop))
-    		{
-                $pdf->SetXY($this->posxprojet - 1, $tab_top + 1);
-                $pdf->MultiCell($this->posxtva - $this->posxprojet - 1, 2, $outputlangs->transnoentities("Project"), '', 'C');
-    		}
-        }
+		//$pdf->line($this->posxtype-1, $tab_top, $this->posxtype-1, $tab_top + $tab_height);
+		//if (empty($hidetop))
+		//{
+		//	$pdf->SetXY($this->posxtype-1, $tab_top+1);
+		//	$pdf->MultiCell($this->posxprojet-$this->posxtype - 1, 2, $outputlangs->transnoentities("Type"), '', 'C');
+		//}
+
+        //if (!empty($conf->projet->enabled))
+        //{
+        //    // Project
+        //    $pdf->line($this->posxprojet - 1, $tab_top, $this->posxprojet - 1, $tab_top + $tab_height);
+    	//	if (empty($hidetop)) {
+        //        $pdf->SetXY($this->posxprojet - 1, $tab_top + 1);
+        //        $pdf->MultiCell($this->posxtva - $this->posxprojet - 1, 2, $outputlangs->transnoentities("Project"), '', 'C');
+    	//	}
+        //}
 
 		// VAT
-		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT))
-		{
+		if (empty($conf->global->MAIN_GENERATE_DOCUMENTS_WITHOUT_VAT)) {
 			$pdf->line($this->posxtva-1, $tab_top, $this->posxtva-1, $tab_top + $tab_height);
-			if (empty($hidetop))
-			{
+			if (empty($hidetop)) {
 				$pdf->SetXY($this->posxtva-1, $tab_top+1);
 				$pdf->MultiCell($this->posxup-$this->posxtva - 1, 2, $outputlangs->transnoentities("VAT"), '', 'C');
 			}
@@ -877,24 +904,21 @@ class pdf_standard extends ModeleExpenseReport
 
         // Unit price
 		$pdf->line($this->posxup-1, $tab_top, $this->posxup-1, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->SetXY($this->posxup-1, $tab_top+1);
 			$pdf->MultiCell($this->posxqty-$this->posxup-1,2, $outputlangs->transnoentities("PriceU"),'','C');
 		}
 
 		// Quantity
 		$pdf->line($this->posxqty-1, $tab_top, $this->posxqty-1, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->SetXY($this->posxqty-1, $tab_top+1);
 			$pdf->MultiCell($this->postotalttc-$this->posxqty - 1,2, $outputlangs->transnoentities("Qty"),'','R');
 		}
 
 		// Total with all taxes
 		$pdf->line($this->postotalttc, $tab_top, $this->postotalttc, $tab_top + $tab_height);
-		if (empty($hidetop))
-		{
+		if (empty($hidetop)) {
 			$pdf->SetXY($this->postotalttc-1, $tab_top+1);
 			$pdf->MultiCell($this->page_largeur-$this->marge_droite-$this->postotalttc, 2, $outputlangs->transnoentities("TotalTTC"),'','R');
 		}
@@ -914,7 +938,7 @@ class pdf_standard extends ModeleExpenseReport
 	function _pagefoot(&$pdf,$object,$outputlangs,$hidefreetext=0)
 	{
 		global $conf;
-		$showdetails=$conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
-		return pdf_pagefoot($pdf,$outputlangs,'EXPENSEREPORT_FREE_TEXT',$this->emetteur,$this->marge_basse,$this->marge_gauche,$this->page_hauteur,$object,$showdetails,$hidefreetext);
+		$showdetails = $conf->global->MAIN_GENERATE_DOCUMENTS_SHOW_FOOT_DETAILS;
+		return pdf_pagefoot($pdf, $outputlangs, 'EXPENSEREPORT_FREE_TEXT', $this->emetteur, $this->marge_basse, $this->marge_gauche, $this->page_hauteur, $object, $showdetails, $hidefreetext);
 	}
 }

+ 10 - 12
htdocs/core/modules/facture/doc/doc_generic_invoice_odt.modules.php

@@ -300,20 +300,18 @@ class doc_generic_invoice_odt extends ModelePDFFactures
 				}
 
 				// Recipient name
-				$contactobject=null;
-				if (! empty($usecontact))
-				{
+				$contactobject = null;
+				if (! empty($usecontact)) {
 					// On peut utiliser le nom de la societe du contact
-					if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT)) $socobject = $object->contact;
+					if (! empty($conf->global->MAIN_USE_COMPANY_NAME_OF_CONTACT))
+						$socobject = $object->contact;
 					else {
-			                        $socobject = $object->thirdparty;
-                        			// if we have a BILLING contact and we dont use it as recipient we store the contact object for later use
-                        			$contactobject = $object->contact;
-                    			}
-				}
-				else
-				{
-					$socobject=$object->thirdparty;
+						$socobject = $object->thirdparty;
+						// if we have a BILLING contact and we dont use it as recipient we store the contact object for later use
+						$contactobject = $object->contact;
+					}
+				} else {
+					$socobject = $object->thirdparty;
 				}
 
 				// Fetch info for linked propal

+ 1 - 1
htdocs/core/modules/modAccounting.class.php

@@ -80,7 +80,7 @@ class modAccounting extends DolibarrModules
 				"MAIN_COMPANY_CODE_ALWAYS_REQUIRED",
 				"chaine",
 				"1",
-				"With this constants on, third party code is always required whatever is numbering module behaviour", 0, 'current', 0
+				"With this constants on, third party code is always required whatever is numbering module behaviour", 0, 'current', 1
 		);
 		$this->const[2] = array(
 				"MAIN_BANK_ACCOUNTANCY_CODE_ALWAYS_REQUIRED",

+ 2 - 2
htdocs/core/modules/modAdherent.class.php

@@ -49,7 +49,7 @@ class modAdherent extends DolibarrModules
         $this->numero = 310;
 
         $this->family = "hr";
-        $this->module_position = '20';
+        $this->module_position = '55';
 		// Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
 		$this->name = preg_replace('/^mod/i','',get_class($this));
         $this->description = "Management of members of a foundation or association";
@@ -323,7 +323,7 @@ class modAdherent extends DolibarrModules
 			'a.datec'=>'DateCreation','a.datefin'=>'DateEndSubscription'
 		);
 		// Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'adherent' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'adherent' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{

+ 1 - 1
htdocs/core/modules/modCashDesk.class.php

@@ -97,7 +97,7 @@ class modCashDesk extends DolibarrModules
 		// This is to declare the Top Menu entry:
 		$this->menu[$r]=array(	    'fk_menu'=>0,			// Put 0 if this is a top menu
 									'type'=>'top',			// This is a Top menu entry
-									'titre'=>'CashDeskMenu',
+									'titre'=>'PointOfSaleShort',
 									'mainmenu'=>'cashdesk',
 									'url'=>'/cashdesk/index.php?user=__LOGIN__',
 									'langs'=>'cashdesk',	// Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.

+ 1 - 1
htdocs/core/modules/modDav.class.php

@@ -91,7 +91,7 @@ class modDav extends DolibarrModules
 		$this->requiredby = array();	// List of module ids to disable if this one is disabled
 		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
 		$this->langfiles = array("admin");
-		$this->phpmin = array(5,4);					// Minimum version of PHP required by module
+		$this->phpmin = array(5,6);					// Minimum version of PHP required by module
 		$this->need_dolibarr_version = array(7,0);	// Minimum version of Dolibarr required by module
 		$this->warnings_activation = array();                     // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
 		$this->warnings_activation_ext = array();                 // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...)

+ 2 - 2
htdocs/core/modules/modEmailCollector.class.php

@@ -46,7 +46,7 @@ class modEmailCollector extends DolibarrModules
 		// Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
 		$this->numero = 50320;
 		// Key text used to identify module (for permissions, menus, etc...)
-		$this->rights_class = 'dav';
+		$this->rights_class = 'emailcollector';
 
 		// Family can be 'base' (core modules),'crm','financial','hr','projects','products','ecm','technic' (transverse modules),'interface' (link with external tools),'other','...'
 		// It is used to group modules by family in module setup page
@@ -64,7 +64,7 @@ class modEmailCollector extends DolibarrModules
 		$this->descriptionlong = "EmailCollectorDescription";
 
 		// Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated' or a version string like 'x.y.z'
-		$this->version = 'development';
+		$this->version = 'experimental';
 		// Key used in llx_const table to save module status enabled/disabled (where DAV is value of property name of module in uppercase)
 		$this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
 		// Name of image file used for this module.

+ 1 - 1
htdocs/core/modules/modProduct.class.php

@@ -317,7 +317,7 @@ class modProduct extends DolibarrModules
 		if (! empty($conf->global->PRODUCT_USE_UNITS)) $this->import_fields_array[$r]['p.fk_unit'] = 'Unit';
 		// Add extra fields
 		$import_extrafield_sample=array();
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'product' AND entity IN (0, ".$conf->entity.')';
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'product' AND entity IN (0, ".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{

+ 1 - 1
htdocs/core/modules/modProjet.class.php

@@ -278,7 +278,7 @@ class modProjet extends DolibarrModules
     		$this->import_tables_array[$r]=array('t'=>MAIN_DB_PREFIX.'projet_task','extra'=>MAIN_DB_PREFIX.'projet_task_extrafields');	// List of tables to insert into (insert done in same order)
     		$this->import_fields_array[$r]=array('t.fk_projet'=>'ProjectRef*','t.ref'=>'RefTask*','t.label'=>'LabelTask*','t.dateo'=>"DateStart",'t.datee'=>"DateEnd",'t.planned_workload'=>"PlannedWorkload",'t.progress'=>"Progress",'t.note_private'=>"NotePrivate",'t.note_public'=>"NotePublic",'t.datec'=>"DateCreation");
     		// Add extra fields
-    		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'projet_task' AND entity = ".$conf->entity;
+    		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'projet_task' AND entity IN (0,".$conf->entity.")";
     		$resql=$this->db->query($sql);
     		if ($resql)    // This can fail when class is used on old database (during migration for example)
     		{

+ 5 - 0
htdocs/core/modules/modPropale.class.php

@@ -225,8 +225,13 @@ class modPropale extends DolibarrModules
 		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
 		$keyforselect='product'; $keyforelement='product'; $keyforaliasextra='extra3';
 		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+		$keyforselect='societe'; $keyforelement='societe'; $keyforaliasextra='extra4';
+		include DOL_DOCUMENT_ROOT.'/core/extrafieldsinexport.inc.php';
+
 		$this->export_sql_start[$r]='SELECT DISTINCT ';
 		$this->export_sql_end[$r]  =' FROM '.MAIN_DB_PREFIX.'societe as s ';
+		$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe_extrafields as extra4 ON s.rowid = extra4.fk_object';
+
 		if(!$user->rights->societe->client->voir) $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'societe_commerciaux as sc ON sc.fk_soc = s.rowid';
 		$this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON s.fk_pays = co.rowid,';
 		$this->export_sql_end[$r] .=' '.MAIN_DB_PREFIX.'propal as c';

+ 1 - 1
htdocs/core/modules/modResource.class.php

@@ -265,7 +265,7 @@ class modResource extends DolibarrModules
 		$this->import_tables_array[$r]=array('r'=>MAIN_DB_PREFIX.'resource','extra'=>MAIN_DB_PREFIX.'resource_extrafields');	// List of tables to insert into (insert done in same order)
 		$this->import_fields_array[$r]=array('r.ref'=>"ResourceFormLabel_ref*",'r.fk_code_type_resource'=>'ResourceTypeCode','r.description'=>'ResourceFormLabel_description','r.note_private'=>"NotePrivate",'r.note_public'=>"NotePublic",'r.asset_number'=>'AssetNumber','r.datec'=>'DateCreation');
 		// Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'resource' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'resource' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{

+ 1 - 1
htdocs/core/modules/modService.class.php

@@ -255,7 +255,7 @@ class modService extends DolibarrModules
 		if (! empty($conf->barcode->enabled)) $this->import_fields_array[$r]=array_merge($this->import_fields_array[$r],array('p.barcode'=>'BarCode'));
 		if (! empty($conf->global->PRODUCT_USE_UNITS)) $this->import_fields_array[$r]['p.fk_unit'] = 'Unit';
         // Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'product' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'product' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{

+ 9 - 6
htdocs/core/modules/modSociete.class.php

@@ -395,7 +395,7 @@ class modSociete extends DolibarrModules
 			's.barcode'=>'BarCode','s.datec'=>"DateCreation"
 		);
 		// Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'societe' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'societe' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{
@@ -441,11 +441,11 @@ class modSociete extends DolibarrModules
 		$this->import_tables_array[$r]=array('s'=>MAIN_DB_PREFIX.'socpeople','extra'=>MAIN_DB_PREFIX.'socpeople_extrafields');	// List of tables to insert into (insert done in same order)
 		$this->import_fields_array[$r]=array(
 			's.fk_soc'=>'ThirdPartyName','s.civility'=>'UserTitle','s.lastname'=>"Lastname*",'s.firstname'=>"Firstname",'s.address'=>"Address",'s.zip'=>"Zip",
-			's.town'=>"Town",'s.fk_pays'=>"CountryCode",'s.birthday'=>"BirthdayDate",'s.poste'=>"Role",'s.phone'=>"Phone",'s.phone_perso'=>"PhonePerso",
+			's.town'=>"Town",'s.fk_departement'=>"StateId",'s.fk_pays'=>"CountryCode",'s.birthday'=>"BirthdayDate",'s.poste'=>"Role",'s.phone'=>"Phone",'s.phone_perso'=>"PhonePerso",
 			's.phone_mobile'=>"PhoneMobile",'s.fax'=>"Fax",'s.email'=>"Email",'s.note_private'=>"Note",'s.note_public'=>"Note",'s.datec'=>"DateCreation"
 		);
 		// Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'socpeople' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'socpeople' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{
@@ -461,7 +461,7 @@ class modSociete extends DolibarrModules
 		$this->import_convertvalue_array[$r]=array(
 			's.fk_soc'=>array('rule'=>'fetchidfromref','file'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty'),
 			's.fk_departement'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/cstate.class.php','class'=>'Cstate','method'=>'fetch','dict'=>'DictionaryState'),
-		    's.fk_pays'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/ccountry.class.php','class'=>'Ccountry','method'=>'fetch','dict'=>'DictionaryCountry'),
+			's.fk_pays'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/ccountry.class.php','class'=>'Ccountry','method'=>'fetch','dict'=>'DictionaryCountry'),
 		);
 		//$this->import_convertvalue_array[$r]=array('s.fk_soc'=>array('rule'=>'lastrowid',table='t');
 		$this->import_regex_array[$r]=array('s.birthday'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$','s.datec'=>'^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?$');
@@ -480,11 +480,14 @@ class modSociete extends DolibarrModules
 		$this->import_tables_array[$r]=array('sr'=>MAIN_DB_PREFIX.'societe_rib');
 		$this->import_fields_array[$r]=array('sr.fk_soc'=>"ThirdPartyName*",'sr.bank'=>"Bank",
 				'sr.code_banque'=>"BankCode",'sr.code_guichet'=>"DeskCode",'sr.number'=>"BankAccountNumber*",
-				'sr.cle_rib'=>"BankAccountNumberKey",'sr.bic'=>"BIC",'sr.iban_prefix'=>"IBAN", 'sr.domiciliation'=>"BankAccountDomiciliation",'sr.proprio' => "BankAccountOwner", 'sr.owner_address' => "BankAccountOwnerAddress", 'sr.default_rib' => 'Default'
+				'sr.cle_rib'=>"BankAccountNumberKey",'sr.bic'=>"BIC",'sr.iban_prefix'=>"IBAN", 'sr.domiciliation'=>"BankAccountDomiciliation",'sr.proprio' => "BankAccountOwner", 'sr.owner_address' => "BankAccountOwnerAddress", 'sr.default_rib' => 'Default',
+				'sr.fk_departement'=>"StateId",'sr.fk_pays'=>"CountryCode"
 		);
 
 		$this->import_convertvalue_array[$r]=array(
-				'sr.fk_soc'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty')
+				'sr.fk_soc'=>array('rule'=>'fetchidfromref','classfile'=>'/societe/class/societe.class.php','class'=>'Societe','method'=>'fetch','element'=>'ThirdParty'),
+				'sr.fk_departement'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/cstate.class.php','class'=>'Cstate','method'=>'fetch','dict'=>'DictionaryState'),
+				'sr.fk_pays'=>array('rule'=>'fetchidfromcodeid','classfile'=>'/core/class/ccountry.class.php','class'=>'Ccountry','method'=>'fetch','dict'=>'DictionaryCountry'),
 		);
 		$this->import_examplevalues_array[$r]=array('sr.fk_soc'=>"MyBigCompany",'sr.bank'=>"ING",
 				'sr.code_banque'=>"0000", 'sr.code_guichet'=>"1111",'sr.number'=>"3333333333",

+ 2 - 2
htdocs/core/modules/modTakePos.class.php

@@ -102,7 +102,7 @@ class modTakePos extends DolibarrModules
 		$this->requiredby = array();	// List of module ids to disable if this one is disabled
 		$this->conflictwith = array();	// List of module class names as string this module is in conflict with
 		$this->langfiles = array("cashdesk");
-		$this->phpmin = array(5,43);					// Minimum version of PHP required by module
+		$this->phpmin = array(5,4);					// Minimum version of PHP required by module
 		$this->need_dolibarr_version = array(4,0);	// Minimum version of Dolibarr required by module
 		$this->warnings_activation = array();                     // Warning to show when we activate module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
 		$this->warnings_activation_ext = array();                 // Warning to show when we activate an external module. array('always'='text') or array('FR'='textfr','ES'='textes'...)
@@ -226,7 +226,7 @@ class modTakePos extends DolibarrModules
 		/* BEGIN MODULEBUILDER TOPMENU */
 		$this->menu[$r++]=array('fk_menu'=>'',			                // '' if this is a top menu. For left menu, use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
 								'type'=>'top',			                // This is a Top menu entry
-								'titre'=>'PointOfSale',
+								'titre'=>'PointOfSaleShort',
 								'mainmenu'=>'takepos',
 								'leftmenu'=>'',
 								'url'=>'/takepos/takepos.php',

+ 1 - 1
htdocs/core/modules/modUser.class.php

@@ -261,7 +261,7 @@ class modUser extends DolibarrModules
 			'u.dateemployment'=>'DateEmployment','u.salary'=>'Salary','u.color'=>'Color','u.api_key'=>'ApiKey','u.datec'=>"DateCreation"
 		);
 		// Add extra fields
-		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'user' AND entity = ".$conf->entity;
+		$sql="SELECT name, label, fieldrequired FROM ".MAIN_DB_PREFIX."extrafields WHERE elementtype = 'user' AND entity IN (0,".$conf->entity.")";
 		$resql=$this->db->query($sql);
 		if ($resql)    // This can fail when class is used on old database (during migration for example)
 		{

+ 1 - 1
htdocs/core/modules/modWebsite.class.php

@@ -167,7 +167,7 @@ class modWebsite extends DolibarrModules
 	    		if ($result < 0)
 	    		{
 	    			$langs->load("errors");
-	    			$this->error=$langs->trans('ErrorFailToCopyDirectory',$src,$dest);
+	    			$this->error=$langs->trans('ErrorFailToCopyDir',$src,$dest);
 	    			return 0;
 	    		}
 	    	}

+ 1 - 1
htdocs/core/modules/project/doc/doc_generic_project_odt.modules.php

@@ -796,7 +796,7 @@ class doc_generic_project_odt extends ModelePDFProjects
 								if (!empty($row['thm'])) {
 									$row['amountht']=($row['task_duration'] / 3600) * $row['thm'];
 									$defaultvat = get_default_tva($mysoc, $mysoc);
-									$row['amountttc']=price2num($row['amountht'] * (1 + ($defaultvat / 100)),'MT');;
+									$row['amountttc']=price2num($row['amountht'] * (1 + ($defaultvat / 100)),'MT');
 								} else {
 									$row['amountht']=0;
 									$row['amountttc']=0;

+ 7 - 6
htdocs/core/modules/project/doc/pdf_beluga.modules.php

@@ -1,7 +1,7 @@
 <?php
-/* Copyright (C) 2010-2012	Regis Houssin  <regis.houssin@inodbox.com>
- * Copyright (C) 2015		Charlie Benke  <charlie@patas-monkey.com>
- * Copyright (C) 2018      Laurent Destailleur <eldy@users.sourceforge.net>
+/* Copyright (C) 2010-2012	Regis Houssin   <regis.houssin@inodbox.com>
+ * Copyright (C) 2015-2018	Charlene Benke  <charlie@patas-monkey.com>
+ * Copyright (C) 2018      Laurent Destailleur  <eldy@users.sourceforge.net>
  *
  * 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
@@ -191,10 +191,11 @@ class pdf_beluga extends ModelePDFProjects
 
 				// Complete object by loading several other informations
 				$task = new Task($this->db);
-				$tasksarray = $task->getTasksArray(0,0,$object->id);
+				$tasksarray = array();
+				$tasksarray = $task->getTasksArray(0, 0, $object->id);
 
-				if (! $object->id > 0)  // Special case when used with object = specimen, we may return all lines
-				{
+				// Special case when used with object = specimen, we may return all lines
+				if (! $object->id > 0) {
 					$tasksarray=array_slice($tasksarray, 0, min(5, count($tasksarray)));
 				}
 

+ 2 - 2
htdocs/core/modules/rapport/pdf_paiement.class.php

@@ -1,7 +1,7 @@
 <?php
 /* Copyright (C) 2003-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  * Copyright (C) 2006-2014 Laurent Destailleur  <eldy@users.sourceforge.net>
- * Copyright (C) 2015		Charles-Fr BENKE  	 <charles.fr@benke.fr>
+ * Copyright (C) 2015-2018 Charlene BENKE  	<charlie@patas-monkey.com>
  *
  * 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
@@ -346,7 +346,7 @@ class pdf_paiement
 	 */
 	function _pagehead(&$pdf, $page, $showaddress, $outputlangs)
 	{
-		global $langs;
+		global $langs, $conf;
 
 		// Do not add the BACKGROUND as this is a report
 		//pdf_pagehead($pdf,$outputlangs,$this->page_hauteur);

+ 1 - 1
htdocs/core/modules/societe/mod_codecompta_aquarium.php

@@ -164,7 +164,7 @@ class mod_codecompta_aquarium extends ModeleAccountancyCode
 		if (! isset($conf->global->COMPANY_AQUARIUM_REMOVE_SPECIAL) || ! empty($conf->global->COMPANY_AQUARIUM_REMOVE_SPECIAL)) $codetouse=preg_replace('/([^a-z0-9])/i','',$codetouse);
 		// Remove special alpha if COMPANY_AQUARIUM_REMOVE_ALPHA is set to 1
 		if (! empty($conf->global->COMPANY_AQUARIUM_REMOVE_ALPHA))   $codetouse=preg_replace('/([a-z])/i','',$codetouse);
-		// Apply a regex replacement pattern if COMPANY_AQUARIUM_REMOVE_ALPHA is set to 1
+		// Apply a regex replacement pattern on code if COMPANY_AQUARIUM_CLEAN_REGEX is set. Value must be a regex with parenthesis. The part into parenthesis is kept, the rest removed.
 		if (! empty($conf->global->COMPANY_AQUARIUM_CLEAN_REGEX))	// Example: $conf->global->COMPANY_AQUARIUM_CLEAN_REGEX='^..(..)..';
 		{
 			$codetouse=preg_replace('/'.$conf->global->COMPANY_AQUARIUM_CLEAN_REGEX.'/','\1\2\3',$codetouse);

+ 1 - 1
htdocs/core/modules/stock/doc/pdf_stdmovement.modules.php

@@ -150,7 +150,7 @@ class pdf_stdmovement extends ModelePDFMovement
 		// Define position of columns
 		$this->wref = 15;
 		$this->posxidref = $this->marge_gauche;
-		$this->posxdatemouv = $this->marge_gauche+8;;
+		$this->posxdatemouv = $this->marge_gauche+8;
 		$this->posxdesc=37;
 		$this->posxlabel=50;
 		$this->posxtva=80;

+ 1 - 1
htdocs/core/tpl/extrafields_view.tpl.php

@@ -129,7 +129,7 @@ if (empty($reshook) && is_array($extrafields->attributes[$object->table_element]
 
 			$html_id = !empty($object->id) ? $object->element.'_extras_'.$key.'_'.$object->id : '';
 
-			print '<td id="'.$html_id.'" class="'.$object->element.'_extras_'.$key.'"'.($cols?' colspan="'.$cols.'"':'').'>';
+			print '<td id="'.$html_id.'" class="'.$object->element.'_extras_'.$key.' wordbreak"'.($cols?' colspan="'.$cols.'"':'').'>';
 
 			// Convert date into timestamp format
 			if (in_array($extrafields->attributes[$object->table_element]['type'][$key], array('date','datetime')))

+ 2 - 0
htdocs/core/tpl/filemanager.tpl.php

@@ -143,6 +143,8 @@ if ($action == 'delete_section')
 
 if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg_match('/refresh/i',$action) || $action == 'delete')
 {
+	$langs->load("ecm");
+
 	print '<table width="100%" class="liste noborderbottom">'."\n";
 
 	print '<!-- Title for manual directories -->'."\n";

+ 8 - 3
htdocs/core/triggers/interface_50_modAgenda_ActionsAuto.class.php

@@ -769,7 +769,7 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		    $object->sendtoid=0;
 		}
 
-		$object->actionmsg.="\n".$langs->transnoentities("Author").': '.$user->login;
+		$object->actionmsg = $langs->transnoentities("Author").': '.$user->login."\n".$object->actionmsg;
 
 		dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
 
@@ -841,8 +841,13 @@ class InterfaceActionsAuto extends DolibarrTriggers
 		$actioncomm->email_subject = $object->email_subject;
 		$actioncomm->errors_to     = $object->errors_to;
 
-		$actioncomm->fk_element  = $elementid;
-		$actioncomm->elementtype = $elementtype;
+		// Object linked (if link is for thirdparty, contact, project it is a recording error. We should not have links in link table
+		// for such objects because there is already a dedicated field into table llx_actioncomm.
+		if (! in_array($elementtype, array('societe','contact','project')))
+		{
+			$actioncomm->fk_element  = $elementid;
+			$actioncomm->elementtype = $elementtype;
+		}
 
 		if (property_exists($object,'attachedfiles') && is_array($object->attachedfiles) && count($object->attachedfiles)>0) {
 			$actioncomm->attachedfiles=$object->attachedfiles;

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